xref: /llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp (revision 74b6aae4e8f47bfe150bb2d943474b4529403a37)
1 //===-- RISCVMCExpr.cpp - RISCV 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 // This file contains the implementation of the assembly expression modifiers
10 // accepted by the RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...).
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "RISCV.h"
15 #include "RISCVMCExpr.h"
16 #include "RISCVFixupKinds.h"
17 #include "llvm/MC/MCAssembler.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCSymbolELF.h"
21 #include "llvm/MC/MCValue.h"
22 #include "llvm/Support/ErrorHandling.h"
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "riscvmcexpr"
27 
28 const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind,
29                                        MCContext &Ctx) {
30   return new (Ctx) RISCVMCExpr(Expr, Kind);
31 }
32 
33 void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
34   bool HasVariant =
35       ((getKind() != VK_RISCV_None) && (getKind() != VK_RISCV_CALL));
36   if (HasVariant)
37     OS << '%' << getVariantKindName(getKind()) << '(';
38   Expr->print(OS, MAI);
39   if (HasVariant)
40     OS << ')';
41 }
42 
43 const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
44   MCValue AUIPCLoc;
45   if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr))
46     return nullptr;
47 
48   const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
49   if (!AUIPCSRE)
50     return nullptr;
51 
52   const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
53   const auto *DF = dyn_cast_or_null<MCDataFragment>(AUIPCSymbol->getFragment());
54 
55   if (!DF)
56     return nullptr;
57 
58   uint64_t Offset = AUIPCSymbol->getOffset();
59   if (DF->getContents().size() == Offset) {
60     DF = dyn_cast_or_null<MCDataFragment>(DF->getNextNode());
61     if (!DF)
62       return nullptr;
63     Offset = 0;
64   }
65 
66   for (const MCFixup &F : DF->getFixups()) {
67     if (F.getOffset() != Offset)
68       continue;
69 
70     switch ((unsigned)F.getKind()) {
71     default:
72       continue;
73     case RISCV::fixup_riscv_got_hi20:
74     case RISCV::fixup_riscv_pcrel_hi20:
75       return &F;
76     }
77   }
78 
79   return nullptr;
80 }
81 
82 bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
83                                   const MCFixup *Fixup) const {
84   // VK_RISCV_PCREL_LO has to be handled specially.  The MCExpr inside is
85   // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup
86   // pointing to the real target.  We need to generate an MCValue in the form of
87   // (<real target> + <offset from this fixup to the auipc fixup>).  The Fixup
88   // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the
89   // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct.
90   MCValue AUIPCLoc;
91   if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout))
92     return false;
93 
94   const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
95   // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment
96   // boundries.
97   if (!AUIPCSRE ||
98       findAssociatedFragment() != AUIPCSRE->findAssociatedFragment())
99     return false;
100 
101   const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
102   if (!AUIPCSymbol)
103     return false;
104 
105   const MCFixup *TargetFixup = getPCRelHiFixup();
106   if (!TargetFixup)
107     return false;
108 
109   if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20)
110     return false;
111 
112   MCValue Target;
113   if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout))
114     return false;
115 
116   if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection())
117     return false;
118 
119   if (&Target.getSymA()->getSymbol().getSection() !=
120       findAssociatedFragment()->getParent())
121     return false;
122 
123   uint64_t AUIPCOffset = AUIPCSymbol->getOffset();
124 
125   Res = MCValue::get(Target.getSymA(), nullptr,
126                      Target.getConstant() + (Fixup->getOffset() - AUIPCOffset));
127   return true;
128 }
129 
130 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
131                                             const MCAsmLayout *Layout,
132                                             const MCFixup *Fixup) const {
133   if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup))
134     return true;
135 
136   if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
137     return false;
138 
139   // Some custom fixup types are not valid with symbol difference expressions
140   if (Res.getSymA() && Res.getSymB()) {
141     switch (getKind()) {
142     default:
143       return true;
144     case VK_RISCV_LO:
145     case VK_RISCV_HI:
146     case VK_RISCV_PCREL_LO:
147     case VK_RISCV_PCREL_HI:
148     case VK_RISCV_GOT_HI:
149       return false;
150     }
151   }
152 
153   return true;
154 }
155 
156 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
157   Streamer.visitUsedExpr(*getSubExpr());
158 }
159 
160 RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
161   return StringSwitch<RISCVMCExpr::VariantKind>(name)
162       .Case("lo", VK_RISCV_LO)
163       .Case("hi", VK_RISCV_HI)
164       .Case("pcrel_lo", VK_RISCV_PCREL_LO)
165       .Case("pcrel_hi", VK_RISCV_PCREL_HI)
166       .Case("got_pcrel_hi", VK_RISCV_GOT_HI)
167       .Default(VK_RISCV_Invalid);
168 }
169 
170 StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
171   switch (Kind) {
172   default:
173     llvm_unreachable("Invalid ELF symbol kind");
174   case VK_RISCV_LO:
175     return "lo";
176   case VK_RISCV_HI:
177     return "hi";
178   case VK_RISCV_PCREL_LO:
179     return "pcrel_lo";
180   case VK_RISCV_PCREL_HI:
181     return "pcrel_hi";
182   case VK_RISCV_GOT_HI:
183     return "got_pcrel_hi";
184   }
185 }
186 
187 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
188   MCValue Value;
189 
190   if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO ||
191       Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_CALL)
192     return false;
193 
194   if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))
195     return false;
196 
197   if (!Value.isAbsolute())
198     return false;
199 
200   Res = evaluateAsInt64(Value.getConstant());
201   return true;
202 }
203 
204 int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const {
205   switch (Kind) {
206   default:
207     llvm_unreachable("Invalid kind");
208   case VK_RISCV_LO:
209     return SignExtend64<12>(Value);
210   case VK_RISCV_HI:
211     // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative.
212     return ((Value + 0x800) >> 12) & 0xfffff;
213   }
214 }
215