xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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(Value, nullptr, nullptr))
66     return false;
67 
68   if (!Value.isAbsolute())
69     return false;
70 
71   Res = evaluateAsInt64(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(Value, Asm, Fixup))
107     return false;
108 
109   if (Value.isAbsolute()) {
110     int64_t Result = evaluateAsInt64(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(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(&Sym->getSymbol(), Modifier, Context);
165     Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
166   }
167 
168   return true;
169 }
170 
171 void PPCMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
172   Streamer.visitUsedExpr(*getSubExpr());
173 }
174