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