1 //===-- VEAsmPrinter.cpp - VE LLVM assembly writer ------------------------===// 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 a printer that converts from our internal representation 10 // of machine-dependent LLVM code to GAS-format VE assembly language. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "MCTargetDesc/VEInstPrinter.h" 15 #include "MCTargetDesc/VEMCExpr.h" 16 #include "MCTargetDesc/VETargetStreamer.h" 17 #include "VE.h" 18 #include "VEInstrInfo.h" 19 #include "VETargetMachine.h" 20 #include "llvm/CodeGen/AsmPrinter.h" 21 #include "llvm/CodeGen/MachineInstr.h" 22 #include "llvm/CodeGen/MachineModuleInfoImpls.h" 23 #include "llvm/CodeGen/MachineRegisterInfo.h" 24 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 25 #include "llvm/IR/Mangler.h" 26 #include "llvm/MC/MCAsmInfo.h" 27 #include "llvm/MC/MCContext.h" 28 #include "llvm/MC/MCInst.h" 29 #include "llvm/MC/MCInstBuilder.h" 30 #include "llvm/MC/MCStreamer.h" 31 #include "llvm/MC/MCSymbol.h" 32 #include "llvm/Support/TargetRegistry.h" 33 #include "llvm/Support/raw_ostream.h" 34 using namespace llvm; 35 36 #define DEBUG_TYPE "ve-asmprinter" 37 38 namespace { 39 class VEAsmPrinter : public AsmPrinter { 40 VETargetStreamer &getTargetStreamer() { 41 return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer()); 42 } 43 44 public: 45 explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 46 : AsmPrinter(TM, std::move(Streamer)) {} 47 48 StringRef getPassName() const override { return "VE Assembly Printer"; } 49 50 void lowerGETGOTAndEmitMCInsts(const MachineInstr *MI, 51 const MCSubtargetInfo &STI); 52 void lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI, 53 const MCSubtargetInfo &STI); 54 void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, 55 const MCSubtargetInfo &STI); 56 57 void emitInstruction(const MachineInstr *MI) override; 58 59 static const char *getRegisterName(unsigned RegNo) { 60 return VEInstPrinter::getRegisterName(RegNo); 61 } 62 }; 63 } // end of anonymous namespace 64 65 static MCOperand createVEMCOperand(VEMCExpr::VariantKind Kind, MCSymbol *Sym, 66 MCContext &OutContext) { 67 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext); 68 const VEMCExpr *expr = VEMCExpr::create(Kind, MCSym, OutContext); 69 return MCOperand::createExpr(expr); 70 } 71 72 static MCOperand createGOTRelExprOp(VEMCExpr::VariantKind Kind, 73 MCSymbol *GOTLabel, MCContext &OutContext) { 74 const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext); 75 const VEMCExpr *expr = VEMCExpr::create(Kind, GOT, OutContext); 76 return MCOperand::createExpr(expr); 77 } 78 79 static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD, 80 const MCSubtargetInfo &STI) { 81 MCInst SICInst; 82 SICInst.setOpcode(VE::SIC); 83 SICInst.addOperand(RD); 84 OutStreamer.emitInstruction(SICInst, STI); 85 } 86 87 static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2, 88 const MCSubtargetInfo &STI) { 89 MCInst BSICInst; 90 BSICInst.setOpcode(VE::BSIC); 91 BSICInst.addOperand(R1); 92 BSICInst.addOperand(R2); 93 OutStreamer.emitInstruction(BSICInst, STI); 94 } 95 96 static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, 97 const MCSubtargetInfo &STI) { 98 MCInst LEAInst; 99 LEAInst.setOpcode(VE::LEAzzi); 100 LEAInst.addOperand(RD); 101 LEAInst.addOperand(Imm); 102 OutStreamer.emitInstruction(LEAInst, STI); 103 } 104 105 static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, 106 const MCSubtargetInfo &STI) { 107 MCInst LEASLInst; 108 LEASLInst.setOpcode(VE::LEASLzzi); 109 LEASLInst.addOperand(RD); 110 LEASLInst.addOperand(Imm); 111 OutStreamer.emitInstruction(LEASLInst, STI); 112 } 113 114 static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm, 115 MCOperand &RD, const MCSubtargetInfo &STI) { 116 MCInst LEAInst; 117 LEAInst.setOpcode(VE::LEAzii); 118 LEAInst.addOperand(RD); 119 LEAInst.addOperand(RS1); 120 LEAInst.addOperand(Imm); 121 OutStreamer.emitInstruction(LEAInst, STI); 122 } 123 124 static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1, 125 MCOperand &RS2, MCOperand &Imm, MCOperand &RD, 126 const MCSubtargetInfo &STI) { 127 MCInst LEASLInst; 128 LEASLInst.setOpcode(VE::LEASLrri); 129 LEASLInst.addOperand(RS1); 130 LEASLInst.addOperand(RS2); 131 LEASLInst.addOperand(RD); 132 LEASLInst.addOperand(Imm); 133 OutStreamer.emitInstruction(LEASLInst, STI); 134 } 135 136 static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1, 137 MCOperand &Src2, MCOperand &RD, 138 const MCSubtargetInfo &STI) { 139 MCInst Inst; 140 Inst.setOpcode(Opcode); 141 Inst.addOperand(RD); 142 Inst.addOperand(RS1); 143 Inst.addOperand(Src2); 144 OutStreamer.emitInstruction(Inst, STI); 145 } 146 147 static void emitANDrm0(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm, 148 MCOperand &RD, const MCSubtargetInfo &STI) { 149 emitBinary(OutStreamer, VE::ANDrm0, RS1, Imm, RD, STI); 150 } 151 152 static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, 153 VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind, 154 MCOperand &RD, MCContext &OutContext, 155 const MCSubtargetInfo &STI) { 156 157 MCOperand hi = createVEMCOperand(HiKind, GOTSym, OutContext); 158 MCOperand lo = createVEMCOperand(LoKind, GOTSym, OutContext); 159 MCOperand ci32 = MCOperand::createImm(32); 160 emitLEAzzi(OutStreamer, lo, RD, STI); 161 emitANDrm0(OutStreamer, RD, ci32, RD, STI); 162 emitLEASLzzi(OutStreamer, hi, RD, STI); 163 } 164 165 void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI, 166 const MCSubtargetInfo &STI) { 167 MCSymbol *GOTLabel = 168 OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); 169 170 const MachineOperand &MO = MI->getOperand(0); 171 MCOperand MCRegOP = MCOperand::createReg(MO.getReg()); 172 173 if (!isPositionIndependent()) { 174 // Just load the address of GOT to MCRegOP. 175 switch (TM.getCodeModel()) { 176 default: 177 llvm_unreachable("Unsupported absolute code model"); 178 case CodeModel::Small: 179 case CodeModel::Medium: 180 case CodeModel::Large: 181 emitHiLo(*OutStreamer, GOTLabel, VEMCExpr::VK_VE_HI32, 182 VEMCExpr::VK_VE_LO32, MCRegOP, OutContext, STI); 183 break; 184 } 185 return; 186 } 187 188 MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT 189 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT 190 191 // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24) 192 // and %got, %got, (32)0 193 // sic %plt 194 // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%got, %plt) 195 MCOperand cim24 = MCOperand::createImm(-24); 196 MCOperand loImm = 197 createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext); 198 emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI); 199 MCOperand ci32 = MCOperand::createImm(32); 200 emitANDrm0(*OutStreamer, MCRegOP, ci32, MCRegOP, STI); 201 emitSIC(*OutStreamer, RegPLT, STI); 202 MCOperand hiImm = 203 createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext); 204 emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI); 205 } 206 207 void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI, 208 const MCSubtargetInfo &STI) { 209 const MachineOperand &MO = MI->getOperand(0); 210 MCOperand MCRegOP = MCOperand::createReg(MO.getReg()); 211 const MachineOperand &Addr = MI->getOperand(1); 212 MCSymbol *AddrSym = nullptr; 213 214 switch (Addr.getType()) { 215 default: 216 llvm_unreachable("<unknown operand type>"); 217 return; 218 case MachineOperand::MO_MachineBasicBlock: 219 report_fatal_error("MBB is not supported yet"); 220 return; 221 case MachineOperand::MO_ConstantPoolIndex: 222 report_fatal_error("ConstantPool is not supported yet"); 223 return; 224 case MachineOperand::MO_ExternalSymbol: 225 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName()); 226 break; 227 case MachineOperand::MO_GlobalAddress: 228 AddrSym = getSymbol(Addr.getGlobal()); 229 break; 230 } 231 232 if (!isPositionIndependent()) { 233 llvm_unreachable("Unsupported uses of %plt in not PIC code"); 234 return; 235 } 236 237 MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT 238 239 // lea %dst, %plt_lo(func)(-24) 240 // and %dst, %dst, (32)0 241 // sic %plt ; FIXME: is it safe to use %plt here? 242 // lea.sl %dst, %plt_hi(func)(%dst, %plt) 243 MCOperand cim24 = MCOperand::createImm(-24); 244 MCOperand loImm = 245 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, AddrSym, OutContext); 246 emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI); 247 MCOperand ci32 = MCOperand::createImm(32); 248 emitANDrm0(*OutStreamer, MCRegOP, ci32, MCRegOP, STI); 249 emitSIC(*OutStreamer, RegPLT, STI); 250 MCOperand hiImm = 251 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext); 252 emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI); 253 } 254 255 void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, 256 const MCSubtargetInfo &STI) { 257 const MachineOperand &Addr = MI->getOperand(0); 258 MCSymbol *AddrSym = nullptr; 259 260 switch (Addr.getType()) { 261 default: 262 llvm_unreachable("<unknown operand type>"); 263 return; 264 case MachineOperand::MO_MachineBasicBlock: 265 report_fatal_error("MBB is not supported yet"); 266 return; 267 case MachineOperand::MO_ConstantPoolIndex: 268 report_fatal_error("ConstantPool is not supported yet"); 269 return; 270 case MachineOperand::MO_ExternalSymbol: 271 AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName()); 272 break; 273 case MachineOperand::MO_GlobalAddress: 274 AddrSym = getSymbol(Addr.getGlobal()); 275 break; 276 } 277 278 MCOperand RegLR = MCOperand::createReg(VE::SX10); // LR 279 MCOperand RegS0 = MCOperand::createReg(VE::SX0); // S0 280 MCOperand RegS12 = MCOperand::createReg(VE::SX12); // S12 281 MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Twine("__tls_get_addr")); 282 283 // lea %s0, sym@tls_gd_lo(-24) 284 // and %s0, %s0, (32)0 285 // sic %lr 286 // lea.sl %s0, sym@tls_gd_hi(%s0, %lr) 287 // lea %s12, __tls_get_addr@plt_lo(8) 288 // and %s12, %s12, (32)0 289 // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr) 290 // bsic %lr, (, %s12) 291 MCOperand cim24 = MCOperand::createImm(-24); 292 MCOperand loImm = 293 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32, AddrSym, OutContext); 294 emitLEAzii(*OutStreamer, cim24, loImm, RegS0, STI); 295 MCOperand ci32 = MCOperand::createImm(32); 296 emitANDrm0(*OutStreamer, RegS0, ci32, RegS0, STI); 297 emitSIC(*OutStreamer, RegLR, STI); 298 MCOperand hiImm = 299 createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext); 300 emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI); 301 MCOperand ci8 = MCOperand::createImm(8); 302 MCOperand loImm2 = 303 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext); 304 emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI); 305 emitANDrm0(*OutStreamer, RegS12, ci32, RegS12, STI); 306 MCOperand hiImm2 = 307 createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext); 308 emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI); 309 emitBSIC(*OutStreamer, RegLR, RegS12, STI); 310 } 311 312 void VEAsmPrinter::emitInstruction(const MachineInstr *MI) { 313 314 switch (MI->getOpcode()) { 315 default: 316 break; 317 case TargetOpcode::DBG_VALUE: 318 // FIXME: Debug Value. 319 return; 320 case VE::GETGOT: 321 lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo()); 322 return; 323 case VE::GETFUNPLT: 324 lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo()); 325 return; 326 case VE::GETTLSADDR: 327 lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo()); 328 return; 329 } 330 331 MachineBasicBlock::const_instr_iterator I = MI->getIterator(); 332 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); 333 do { 334 MCInst TmpInst; 335 LowerVEMachineInstrToMCInst(&*I, TmpInst, *this); 336 EmitToStreamer(*OutStreamer, TmpInst); 337 } while ((++I != E) && I->isInsideBundle()); // Delay slot check. 338 } 339 340 // Force static initialization. 341 extern "C" void LLVMInitializeVEAsmPrinter() { 342 RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget()); 343 } 344