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