1 //===-- LoongArchMCExpr.cpp - LoongArch 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 LoongArch architecture. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "LoongArchMCExpr.h" 15 #include "LoongArchAsmBackend.h" 16 #include "LoongArchFixupKinds.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/Support/Casting.h" 22 #include "llvm/Support/ErrorHandling.h" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE "loongarch-mcexpr" 27 28 const LoongArchMCExpr * 29 LoongArchMCExpr::create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx) { 30 return new (Ctx) LoongArchMCExpr(Expr, Kind); 31 } 32 33 void LoongArchMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { 34 VariantKind Kind = getKind(); 35 bool HasVariant = 36 ((Kind != VK_LoongArch_None) && (Kind != VK_LoongArch_CALL)); 37 38 if (HasVariant) 39 OS << '%' << getVariantKindName(getKind()) << '('; 40 Expr->print(OS, MAI); 41 if (HasVariant) 42 OS << ')'; 43 } 44 45 bool LoongArchMCExpr::evaluateAsRelocatableImpl(MCValue &Res, 46 const MCAsmLayout *Layout, 47 const MCFixup *Fixup) const { 48 // Explicitly drop the layout and assembler to prevent any symbolic folding in 49 // the expression handling. This is required to preserve symbolic difference 50 // expressions to emit the paired relocations. 51 if (!getSubExpr()->evaluateAsRelocatable(Res, nullptr, nullptr)) 52 return false; 53 54 Res = 55 MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind()); 56 // Custom fixup types are not valid with symbol difference expressions. 57 return Res.getSymB() ? getKind() == VK_LoongArch_None : true; 58 } 59 60 void LoongArchMCExpr::visitUsedExpr(MCStreamer &Streamer) const { 61 Streamer.visitUsedExpr(*getSubExpr()); 62 } 63 64 StringRef LoongArchMCExpr::getVariantKindName(VariantKind Kind) { 65 switch (Kind) { 66 default: 67 llvm_unreachable("Invalid ELF symbol kind"); 68 case VK_LoongArch_CALL_PLT: 69 return "plt"; 70 case VK_LoongArch_B16: 71 return "b16"; 72 case VK_LoongArch_B21: 73 return "b21"; 74 case VK_LoongArch_B26: 75 return "b21"; 76 case VK_LoongArch_ABS_HI20: 77 return "abs_hi20"; 78 case VK_LoongArch_ABS_LO12: 79 return "abs_lo12"; 80 case VK_LoongArch_ABS64_LO20: 81 return "abs64_lo20"; 82 case VK_LoongArch_ABS64_HI12: 83 return "abs64_hi12"; 84 case VK_LoongArch_PCALA_HI20: 85 return "pc_hi20"; 86 case VK_LoongArch_PCALA_LO12: 87 return "pc_lo12"; 88 case VK_LoongArch_PCALA64_LO20: 89 return "pc64_lo20"; 90 case VK_LoongArch_PCALA64_HI12: 91 return "pc64_hi12"; 92 case VK_LoongArch_GOT_PC_HI20: 93 return "got_pc_hi20"; 94 case VK_LoongArch_GOT_PC_LO12: 95 return "got_pc_lo12"; 96 case VK_LoongArch_GOT64_PC_LO20: 97 return "got64_pc_lo20"; 98 case VK_LoongArch_GOT64_PC_HI12: 99 return "got64_pc_hi12"; 100 case VK_LoongArch_GOT_HI20: 101 return "got_hi20"; 102 case VK_LoongArch_GOT_LO12: 103 return "got_lo12"; 104 case VK_LoongArch_GOT64_LO20: 105 return "got64_lo20"; 106 case VK_LoongArch_GOT64_HI12: 107 return "got64_hi12"; 108 case VK_LoongArch_TLS_LE_HI20: 109 return "le_hi20"; 110 case VK_LoongArch_TLS_LE_LO12: 111 return "le_lo12"; 112 case VK_LoongArch_TLS_LE64_LO20: 113 return "le64_lo20"; 114 case VK_LoongArch_TLS_LE64_HI12: 115 return "le64_hi12"; 116 case VK_LoongArch_TLS_IE_PC_HI20: 117 return "ie_pc_hi20"; 118 case VK_LoongArch_TLS_IE_PC_LO12: 119 return "ie_pc_lo12"; 120 case VK_LoongArch_TLS_IE64_PC_LO20: 121 return "ie64_pc_lo20"; 122 case VK_LoongArch_TLS_IE64_PC_HI12: 123 return "ie64_pc_hi12"; 124 case VK_LoongArch_TLS_IE_HI20: 125 return "ie_hi20"; 126 case VK_LoongArch_TLS_IE_LO12: 127 return "ie_lo12"; 128 case VK_LoongArch_TLS_IE64_LO20: 129 return "ie64_lo20"; 130 case VK_LoongArch_TLS_IE64_HI12: 131 return "ie64_hi12"; 132 case VK_LoongArch_TLS_LD_PC_HI20: 133 return "ld_pc_hi20"; 134 case VK_LoongArch_TLS_LD_HI20: 135 return "ld_hi20"; 136 case VK_LoongArch_TLS_GD_PC_HI20: 137 return "gd_pc_hi20"; 138 case VK_LoongArch_TLS_GD_HI20: 139 return "gd_hi20"; 140 } 141 } 142 143 LoongArchMCExpr::VariantKind 144 LoongArchMCExpr::getVariantKindForName(StringRef name) { 145 return StringSwitch<LoongArchMCExpr::VariantKind>(name) 146 .Case("plt", VK_LoongArch_CALL_PLT) 147 .Case("b16", VK_LoongArch_B16) 148 .Case("b21", VK_LoongArch_B21) 149 .Case("b26", VK_LoongArch_B26) 150 .Case("abs_hi20", VK_LoongArch_ABS_HI20) 151 .Case("abs_lo12", VK_LoongArch_ABS_LO12) 152 .Case("abs64_lo20", VK_LoongArch_ABS64_LO20) 153 .Case("abs64_hi12", VK_LoongArch_ABS64_HI12) 154 .Case("pc_hi20", VK_LoongArch_PCALA_HI20) 155 .Case("pc_lo12", VK_LoongArch_PCALA_LO12) 156 .Case("pc64_lo20", VK_LoongArch_PCALA64_LO20) 157 .Case("pc64_hi12", VK_LoongArch_PCALA64_HI12) 158 .Case("got_pc_hi20", VK_LoongArch_GOT_PC_HI20) 159 .Case("got_pc_lo12", VK_LoongArch_GOT_PC_LO12) 160 .Case("got64_pc_lo20", VK_LoongArch_GOT64_PC_LO20) 161 .Case("got64_pc_hi12", VK_LoongArch_GOT64_PC_HI12) 162 .Case("got_hi20", VK_LoongArch_GOT_HI20) 163 .Case("got_lo12", VK_LoongArch_GOT_LO12) 164 .Case("got64_lo20", VK_LoongArch_GOT64_LO20) 165 .Case("got64_hi12", VK_LoongArch_GOT64_HI12) 166 .Case("le_hi20", VK_LoongArch_TLS_LE_HI20) 167 .Case("le_lo12", VK_LoongArch_TLS_LE_LO12) 168 .Case("le64_lo20", VK_LoongArch_TLS_LE64_LO20) 169 .Case("le64_hi12", VK_LoongArch_TLS_LE64_HI12) 170 .Case("ie_pc_hi20", VK_LoongArch_TLS_IE_PC_HI20) 171 .Case("ie_pc_lo12", VK_LoongArch_TLS_IE_PC_LO12) 172 .Case("ie64_pc_lo20", VK_LoongArch_TLS_IE64_PC_LO20) 173 .Case("ie64_pc_hi12", VK_LoongArch_TLS_IE64_PC_HI12) 174 .Case("ie_hi20", VK_LoongArch_TLS_IE_HI20) 175 .Case("ie_lo12", VK_LoongArch_TLS_IE_LO12) 176 .Case("ie64_lo20", VK_LoongArch_TLS_IE64_LO20) 177 .Case("ie64_hi12", VK_LoongArch_TLS_IE64_HI12) 178 .Case("ld_pc_hi20", VK_LoongArch_TLS_LD_PC_HI20) 179 .Case("ld_hi20", VK_LoongArch_TLS_LD_HI20) 180 .Case("gd_pc_hi20", VK_LoongArch_TLS_GD_PC_HI20) 181 .Case("gd_hi20", VK_LoongArch_TLS_GD_HI20) 182 .Default(VK_LoongArch_Invalid); 183 } 184 185 static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { 186 switch (Expr->getKind()) { 187 case MCExpr::Target: 188 llvm_unreachable("Can't handle nested target expression"); 189 break; 190 case MCExpr::Constant: 191 break; 192 case MCExpr::Unary: 193 fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm); 194 break; 195 case MCExpr::Binary: { 196 const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); 197 fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); 198 fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); 199 break; 200 } 201 case MCExpr::SymbolRef: { 202 // We're known to be under a TLS fixup, so any symbol should be 203 // modified. There should be only one. 204 const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr); 205 cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS); 206 break; 207 } 208 } 209 } 210 211 void LoongArchMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { 212 switch (getKind()) { 213 default: 214 return; 215 case VK_LoongArch_TLS_LE_HI20: 216 case VK_LoongArch_TLS_IE_PC_HI20: 217 case VK_LoongArch_TLS_IE_HI20: 218 case VK_LoongArch_TLS_LD_PC_HI20: 219 case VK_LoongArch_TLS_LD_HI20: 220 case VK_LoongArch_TLS_GD_PC_HI20: 221 case VK_LoongArch_TLS_GD_HI20: 222 break; 223 } 224 fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); 225 } 226