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