xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp (revision e32fecd0c2c3ee37c47ee100f169e7eb0282a873)
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
103 PPCMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
104                                      const MCAsmLayout *Layout,
105                                      const MCFixup *Fixup) const {
106   MCValue Value;
107 
108   if (!getSubExpr()->evaluateAsRelocatable(Value, Layout, Fixup))
109     return false;
110 
111   if (Value.isAbsolute()) {
112     int64_t Result = evaluateAsInt64(Value.getConstant());
113     bool IsHalf16 = Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16;
114     bool IsHalf16DS =
115         Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16ds;
116     bool IsHalf16DQ =
117         Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16dq;
118     bool IsHalf = IsHalf16 || IsHalf16DS || IsHalf16DQ;
119 
120     if (!IsHalf && Result >= 0x8000)
121       return false;
122     if ((IsHalf16DS && (Result & 0x3)) || (IsHalf16DQ && (Result & 0xf)))
123       return false;
124 
125     Res = MCValue::get(Result);
126   } else {
127     if (!Layout)
128       return false;
129 
130     MCContext &Context = Layout->getAssembler().getContext();
131     const MCSymbolRefExpr *Sym = Value.getSymA();
132     MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
133     if (Modifier != MCSymbolRefExpr::VK_None)
134       return false;
135     switch (Kind) {
136       default:
137         llvm_unreachable("Invalid kind!");
138       case VK_PPC_LO:
139         Modifier = MCSymbolRefExpr::VK_PPC_LO;
140         break;
141       case VK_PPC_HI:
142         Modifier = MCSymbolRefExpr::VK_PPC_HI;
143         break;
144       case VK_PPC_HA:
145         Modifier = MCSymbolRefExpr::VK_PPC_HA;
146         break;
147       case VK_PPC_HIGH:
148         Modifier = MCSymbolRefExpr::VK_PPC_HIGH;
149         break;
150       case VK_PPC_HIGHA:
151         Modifier = MCSymbolRefExpr::VK_PPC_HIGHA;
152         break;
153       case VK_PPC_HIGHERA:
154         Modifier = MCSymbolRefExpr::VK_PPC_HIGHERA;
155         break;
156       case VK_PPC_HIGHER:
157         Modifier = MCSymbolRefExpr::VK_PPC_HIGHER;
158         break;
159       case VK_PPC_HIGHEST:
160         Modifier = MCSymbolRefExpr::VK_PPC_HIGHEST;
161         break;
162       case VK_PPC_HIGHESTA:
163         Modifier = MCSymbolRefExpr::VK_PPC_HIGHESTA;
164         break;
165     }
166     Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context);
167     Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
168   }
169 
170   return true;
171 }
172 
173 void PPCMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
174   Streamer.visitUsedExpr(*getSubExpr());
175 }
176