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