1 //===-- RISCVMCExpr.cpp - RISCV specific MC expression classes ------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains the implementation of the assembly expression modifiers
11 // accepted by the RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "RISCV.h"
16 #include "RISCVMCExpr.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 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
44                                             const MCAsmLayout *Layout,
45                                             const MCFixup *Fixup) const {
46   if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
47     return false;
48 
49   // Some custom fixup types are not valid with symbol difference expressions
50   if (Res.getSymA() && Res.getSymB()) {
51     switch (getKind()) {
52     default:
53       return true;
54     case VK_RISCV_LO:
55     case VK_RISCV_HI:
56     case VK_RISCV_PCREL_LO:
57     case VK_RISCV_PCREL_HI:
58       return false;
59     }
60   }
61 
62   return true;
63 }
64 
65 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
66   Streamer.visitUsedExpr(*getSubExpr());
67 }
68 
69 RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
70   return StringSwitch<RISCVMCExpr::VariantKind>(name)
71       .Case("lo", VK_RISCV_LO)
72       .Case("hi", VK_RISCV_HI)
73       .Case("pcrel_lo", VK_RISCV_PCREL_LO)
74       .Case("pcrel_hi", VK_RISCV_PCREL_HI)
75       .Default(VK_RISCV_Invalid);
76 }
77 
78 StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
79   switch (Kind) {
80   default:
81     llvm_unreachable("Invalid ELF symbol kind");
82   case VK_RISCV_LO:
83     return "lo";
84   case VK_RISCV_HI:
85     return "hi";
86   case VK_RISCV_PCREL_LO:
87     return "pcrel_lo";
88   case VK_RISCV_PCREL_HI:
89     return "pcrel_hi";
90   }
91 }
92 
93 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
94   MCValue Value;
95 
96   if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO ||
97       Kind == VK_RISCV_CALL)
98     return false;
99 
100   if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))
101     return false;
102 
103   if (!Value.isAbsolute())
104     return false;
105 
106   Res = evaluateAsInt64(Value.getConstant());
107   return true;
108 }
109 
110 int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const {
111   switch (Kind) {
112   default:
113     llvm_unreachable("Invalid kind");
114   case VK_RISCV_LO:
115     return SignExtend64<12>(Value);
116   case VK_RISCV_HI:
117     // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative.
118     return ((Value + 0x800) >> 12) & 0xfffff;
119   }
120 }
121