1//===-- PPCMCExpr.cpp - PPC specific MC expression classes ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PPCMCExpr.h"
10#include "PPCFixupKinds.h"
11#include "llvm/MC/MCAsmInfo.h"
12#include "llvm/MC/MCAssembler.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCObjectStreamer.h"
15
16using namespace llvm;
17
18#define DEBUG_TYPE "ppcmcexpr"
19
20const PPCMCExpr*
21PPCMCExpr::create(VariantKind Kind, const MCExpr *Expr,
22                  bool IsDarwin, MCContext &Ctx) {
23  return new (Ctx) PPCMCExpr(Kind, Expr, IsDarwin);
24}
25
26void PPCMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
27  if (isDarwinSyntax()) {
28    switch (Kind) {
29    default: llvm_unreachable("Invalid kind!");
30    case VK_PPC_LO: OS << "lo16"; break;
31    case VK_PPC_HI: OS << "hi16"; break;
32    case VK_PPC_HA: OS << "ha16"; break;
33    }
34
35    OS << '(';
36    getSubExpr()->print(OS, MAI);
37    OS << ')';
38  } else {
39    getSubExpr()->print(OS, MAI);
40
41    switch (Kind) {
42    default: llvm_unreachable("Invalid kind!");
43    case VK_PPC_LO: OS << "@l"; break;
44    case VK_PPC_HI: OS << "@h"; break;
45    case VK_PPC_HA: OS << "@ha"; break;
46    case VK_PPC_HIGH: OS << "@high"; break;
47    case VK_PPC_HIGHA: OS << "@higha"; break;
48    case VK_PPC_HIGHER: OS << "@higher"; break;
49    case VK_PPC_HIGHERA: OS << "@highera"; break;
50    case VK_PPC_HIGHEST: OS << "@highest"; break;
51    case VK_PPC_HIGHESTA: OS << "@highesta"; break;
52    }
53  }
54}
55
56bool
57PPCMCExpr::evaluateAsConstant(int64_t &Res) const {
58  MCValue Value;
59
60  if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))
61    return false;
62
63  if (!Value.isAbsolute())
64    return false;
65
66  Res = evaluateAsInt64(Value.getConstant());
67  return true;
68}
69
70int64_t
71PPCMCExpr::evaluateAsInt64(int64_t Value) const {
72  switch (Kind) {
73    case VK_PPC_LO:
74      return Value & 0xffff;
75    case VK_PPC_HI:
76      return (Value >> 16) & 0xffff;
77    case VK_PPC_HA:
78      return ((Value + 0x8000) >> 16) & 0xffff;
79    case VK_PPC_HIGH:
80      return (Value >> 16) & 0xffff;
81    case VK_PPC_HIGHA:
82      return ((Value + 0x8000) >> 16) & 0xffff;
83    case VK_PPC_HIGHER:
84      return (Value >> 32) & 0xffff;
85    case VK_PPC_HIGHERA:
86      return ((Value + 0x8000) >> 32) & 0xffff;
87    case VK_PPC_HIGHEST:
88      return (Value >> 48) & 0xffff;
89    case VK_PPC_HIGHESTA:
90      return ((Value + 0x8000) >> 48) & 0xffff;
91    case VK_PPC_None:
92      break;
93  }
94  llvm_unreachable("Invalid kind!");
95}
96
97bool
98PPCMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
99                                     const MCAsmLayout *Layout,
100                                     const MCFixup *Fixup) const {
101  MCValue Value;
102
103  if (!getSubExpr()->evaluateAsRelocatable(Value, Layout, Fixup))
104    return false;
105
106  if (Value.isAbsolute()) {
107    int64_t Result = evaluateAsInt64(Value.getConstant());
108    if ((Fixup == nullptr || (unsigned)Fixup->getKind() != PPC::fixup_ppc_half16) &&
109        (Result >= 0x8000))
110      return false;
111    Res = MCValue::get(Result);
112  } else {
113    if (!Layout)
114      return false;
115
116    MCContext &Context = Layout->getAssembler().getContext();
117    const MCSymbolRefExpr *Sym = Value.getSymA();
118    MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
119    if (Modifier != MCSymbolRefExpr::VK_None)
120      return false;
121    switch (Kind) {
122      default:
123        llvm_unreachable("Invalid kind!");
124      case VK_PPC_LO:
125        Modifier = MCSymbolRefExpr::VK_PPC_LO;
126        break;
127      case VK_PPC_HI:
128        Modifier = MCSymbolRefExpr::VK_PPC_HI;
129        break;
130      case VK_PPC_HA:
131        Modifier = MCSymbolRefExpr::VK_PPC_HA;
132        break;
133      case VK_PPC_HIGH:
134        Modifier = MCSymbolRefExpr::VK_PPC_HIGH;
135        break;
136      case VK_PPC_HIGHA:
137        Modifier = MCSymbolRefExpr::VK_PPC_HIGHA;
138        break;
139      case VK_PPC_HIGHERA:
140        Modifier = MCSymbolRefExpr::VK_PPC_HIGHERA;
141        break;
142      case VK_PPC_HIGHER:
143        Modifier = MCSymbolRefExpr::VK_PPC_HIGHER;
144        break;
145      case VK_PPC_HIGHEST:
146        Modifier = MCSymbolRefExpr::VK_PPC_HIGHEST;
147        break;
148      case VK_PPC_HIGHESTA:
149        Modifier = MCSymbolRefExpr::VK_PPC_HIGHESTA;
150        break;
151    }
152    Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
153    Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
154  }
155
156  return true;
157}
158
159void PPCMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
160  Streamer.visitUsedExpr(*getSubExpr());
161}
162