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 | |
16 | using namespace llvm; |
17 | |
18 | #define DEBUG_TYPE "ppcmcexpr" |
19 | |
20 | const PPCMCExpr *PPCMCExpr::create(VariantKind Kind, const MCExpr *Expr, |
21 | MCContext &Ctx) { |
22 | return new (Ctx) PPCMCExpr(Kind, Expr); |
23 | } |
24 | |
25 | void PPCMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { |
26 | getSubExpr()->print(OS, MAI); |
27 | |
28 | switch (Kind) { |
29 | default: |
30 | llvm_unreachable("Invalid kind!" ); |
31 | case VK_PPC_LO: |
32 | OS << "@l" ; |
33 | break; |
34 | case VK_PPC_HI: |
35 | OS << "@h" ; |
36 | break; |
37 | case VK_PPC_HA: |
38 | OS << "@ha" ; |
39 | break; |
40 | case VK_PPC_HIGH: |
41 | OS << "@high" ; |
42 | break; |
43 | case VK_PPC_HIGHA: |
44 | OS << "@higha" ; |
45 | break; |
46 | case VK_PPC_HIGHER: |
47 | OS << "@higher" ; |
48 | break; |
49 | case VK_PPC_HIGHERA: |
50 | OS << "@highera" ; |
51 | break; |
52 | case VK_PPC_HIGHEST: |
53 | OS << "@highest" ; |
54 | break; |
55 | case VK_PPC_HIGHESTA: |
56 | OS << "@highesta" ; |
57 | break; |
58 | } |
59 | } |
60 | |
61 | bool |
62 | PPCMCExpr::evaluateAsConstant(int64_t &Res) const { |
63 | MCValue Value; |
64 | |
65 | if (!getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm: nullptr, Fixup: nullptr)) |
66 | return false; |
67 | |
68 | if (!Value.isAbsolute()) |
69 | return false; |
70 | |
71 | Res = evaluateAsInt64(Value: Value.getConstant()); |
72 | return true; |
73 | } |
74 | |
75 | int64_t |
76 | PPCMCExpr::evaluateAsInt64(int64_t Value) const { |
77 | switch (Kind) { |
78 | case VK_PPC_LO: |
79 | return Value & 0xffff; |
80 | case VK_PPC_HI: |
81 | return (Value >> 16) & 0xffff; |
82 | case VK_PPC_HA: |
83 | return ((Value + 0x8000) >> 16) & 0xffff; |
84 | case VK_PPC_HIGH: |
85 | return (Value >> 16) & 0xffff; |
86 | case VK_PPC_HIGHA: |
87 | return ((Value + 0x8000) >> 16) & 0xffff; |
88 | case VK_PPC_HIGHER: |
89 | return (Value >> 32) & 0xffff; |
90 | case VK_PPC_HIGHERA: |
91 | return ((Value + 0x8000) >> 32) & 0xffff; |
92 | case VK_PPC_HIGHEST: |
93 | return (Value >> 48) & 0xffff; |
94 | case VK_PPC_HIGHESTA: |
95 | return ((Value + 0x8000) >> 48) & 0xffff; |
96 | case VK_PPC_None: |
97 | break; |
98 | } |
99 | llvm_unreachable("Invalid kind!" ); |
100 | } |
101 | |
102 | bool PPCMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, |
103 | const MCFixup *Fixup) const { |
104 | MCValue Value; |
105 | |
106 | if (!getSubExpr()->evaluateAsRelocatable(Res&: Value, Asm, Fixup)) |
107 | return false; |
108 | |
109 | if (Value.isAbsolute()) { |
110 | int64_t Result = evaluateAsInt64(Value: Value.getConstant()); |
111 | bool IsHalf16 = Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16; |
112 | bool IsHalf16DS = |
113 | Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16ds; |
114 | bool IsHalf16DQ = |
115 | Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16dq; |
116 | bool IsHalf = IsHalf16 || IsHalf16DS || IsHalf16DQ; |
117 | |
118 | if (!IsHalf && Result >= 0x8000) |
119 | return false; |
120 | if ((IsHalf16DS && (Result & 0x3)) || (IsHalf16DQ && (Result & 0xf))) |
121 | return false; |
122 | |
123 | Res = MCValue::get(Val: Result); |
124 | } else { |
125 | if (!Asm || !Asm->hasLayout()) |
126 | return false; |
127 | |
128 | MCContext &Context = Asm->getContext(); |
129 | const MCSymbolRefExpr *Sym = Value.getSymA(); |
130 | MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); |
131 | if (Modifier != MCSymbolRefExpr::VK_None) |
132 | return false; |
133 | switch (Kind) { |
134 | default: |
135 | llvm_unreachable("Invalid kind!" ); |
136 | case VK_PPC_LO: |
137 | Modifier = MCSymbolRefExpr::VK_PPC_LO; |
138 | break; |
139 | case VK_PPC_HI: |
140 | Modifier = MCSymbolRefExpr::VK_PPC_HI; |
141 | break; |
142 | case VK_PPC_HA: |
143 | Modifier = MCSymbolRefExpr::VK_PPC_HA; |
144 | break; |
145 | case VK_PPC_HIGH: |
146 | Modifier = MCSymbolRefExpr::VK_PPC_HIGH; |
147 | break; |
148 | case VK_PPC_HIGHA: |
149 | Modifier = MCSymbolRefExpr::VK_PPC_HIGHA; |
150 | break; |
151 | case VK_PPC_HIGHERA: |
152 | Modifier = MCSymbolRefExpr::VK_PPC_HIGHERA; |
153 | break; |
154 | case VK_PPC_HIGHER: |
155 | Modifier = MCSymbolRefExpr::VK_PPC_HIGHER; |
156 | break; |
157 | case VK_PPC_HIGHEST: |
158 | Modifier = MCSymbolRefExpr::VK_PPC_HIGHEST; |
159 | break; |
160 | case VK_PPC_HIGHESTA: |
161 | Modifier = MCSymbolRefExpr::VK_PPC_HIGHESTA; |
162 | break; |
163 | } |
164 | Sym = MCSymbolRefExpr::create(Symbol: &Sym->getSymbol(), Kind: Modifier, Ctx&: Context); |
165 | Res = MCValue::get(SymA: Sym, SymB: Value.getSymB(), Val: Value.getConstant()); |
166 | } |
167 | |
168 | return true; |
169 | } |
170 | |
171 | void PPCMCExpr::visitUsedExpr(MCStreamer &Streamer) const { |
172 | Streamer.visitUsedExpr(Expr: *getSubExpr()); |
173 | } |
174 | |