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 "RISCVMCExpr.h"
16 #include "llvm/MC/MCAssembler.h"
17 #include "llvm/MC/MCContext.h"
18 #include "llvm/MC/MCStreamer.h"
19 #include "llvm/MC/MCSymbolELF.h"
20 #include "llvm/MC/MCValue.h"
21 #include "llvm/Object/ELF.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 = getKind() != VK_RISCV_None;
35   if (HasVariant)
36     OS << '%' << getVariantKindName(getKind()) << '(';
37   Expr->print(OS, MAI);
38   if (HasVariant)
39     OS << ')';
40 }
41 
42 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
43                                             const MCAsmLayout *Layout,
44                                             const MCFixup *Fixup) const {
45   return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
46 }
47 
48 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
49   Streamer.visitUsedExpr(*getSubExpr());
50 }
51 
52 RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
53   return StringSwitch<RISCVMCExpr::VariantKind>(name)
54       .Case("lo", VK_RISCV_LO)
55       .Case("hi", VK_RISCV_HI)
56       .Case("pcrel_lo", VK_RISCV_PCREL_LO)
57       .Case("pcrel_hi", VK_RISCV_PCREL_HI)
58       .Default(VK_RISCV_Invalid);
59 }
60 
61 StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
62   switch (Kind) {
63   default:
64     llvm_unreachable("Invalid ELF symbol kind");
65   case VK_RISCV_LO:
66     return "lo";
67   case VK_RISCV_HI:
68     return "hi";
69   case VK_RISCV_PCREL_LO:
70     return "pcrel_lo";
71   case VK_RISCV_PCREL_HI:
72     return "pcrel_hi";
73   }
74 }
75 
76 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
77   MCValue Value;
78 
79   if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO)
80     return false;
81 
82   if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr))
83     return false;
84 
85   if (!Value.isAbsolute())
86     return false;
87 
88   Res = evaluateAsInt64(Value.getConstant());
89   return true;
90 }
91 
92 int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const {
93   switch (Kind) {
94   default:
95     llvm_unreachable("Invalid kind");
96   case VK_RISCV_LO:
97     return SignExtend64<12>(Value);
98   case VK_RISCV_HI:
99     // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative.
100     return ((Value + 0x800) >> 12) & 0xfffff;
101   }
102 }
103