1 //===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===// 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 /// \file 10 /// Code to lower AMDGPU MachineInstrs to their corresponding MCInst. 11 // 12 //===----------------------------------------------------------------------===// 13 // 14 15 #include "AMDGPUAsmPrinter.h" 16 #include "AMDGPUTargetMachine.h" 17 #include "MCTargetDesc/AMDGPUInstPrinter.h" 18 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 19 #include "R600AsmPrinter.h" 20 #include "llvm/CodeGen/MachineBasicBlock.h" 21 #include "llvm/CodeGen/MachineInstr.h" 22 #include "llvm/IR/Constants.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/IR/GlobalVariable.h" 25 #include "llvm/MC/MCCodeEmitter.h" 26 #include "llvm/MC/MCContext.h" 27 #include "llvm/MC/MCExpr.h" 28 #include "llvm/MC/MCInst.h" 29 #include "llvm/MC/MCObjectStreamer.h" 30 #include "llvm/MC/MCStreamer.h" 31 #include "llvm/Support/ErrorHandling.h" 32 #include "llvm/Support/Format.h" 33 #include <algorithm> 34 35 using namespace llvm; 36 37 namespace { 38 39 class AMDGPUMCInstLower { 40 MCContext &Ctx; 41 const TargetSubtargetInfo &ST; 42 const AsmPrinter &AP; 43 44 const MCExpr *getLongBranchBlockExpr(const MachineBasicBlock &SrcBB, 45 const MachineOperand &MO) const; 46 47 public: 48 AMDGPUMCInstLower(MCContext &ctx, const TargetSubtargetInfo &ST, 49 const AsmPrinter &AP); 50 51 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; 52 53 /// Lower a MachineInstr to an MCInst 54 void lower(const MachineInstr *MI, MCInst &OutMI) const; 55 56 }; 57 58 class R600MCInstLower : public AMDGPUMCInstLower { 59 public: 60 R600MCInstLower(MCContext &ctx, const R600Subtarget &ST, 61 const AsmPrinter &AP); 62 63 /// Lower a MachineInstr to an MCInst 64 void lower(const MachineInstr *MI, MCInst &OutMI) const; 65 }; 66 67 68 } // End anonymous namespace 69 70 #include "AMDGPUGenMCPseudoLowering.inc" 71 72 AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx, 73 const TargetSubtargetInfo &st, 74 const AsmPrinter &ap): 75 Ctx(ctx), ST(st), AP(ap) { } 76 77 static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags) { 78 switch (MOFlags) { 79 default: 80 return MCSymbolRefExpr::VK_None; 81 case SIInstrInfo::MO_GOTPCREL: 82 return MCSymbolRefExpr::VK_GOTPCREL; 83 case SIInstrInfo::MO_GOTPCREL32_LO: 84 return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO; 85 case SIInstrInfo::MO_GOTPCREL32_HI: 86 return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI; 87 case SIInstrInfo::MO_REL32_LO: 88 return MCSymbolRefExpr::VK_AMDGPU_REL32_LO; 89 case SIInstrInfo::MO_REL32_HI: 90 return MCSymbolRefExpr::VK_AMDGPU_REL32_HI; 91 case SIInstrInfo::MO_ABS32_LO: 92 return MCSymbolRefExpr::VK_AMDGPU_ABS32_LO; 93 case SIInstrInfo::MO_ABS32_HI: 94 return MCSymbolRefExpr::VK_AMDGPU_ABS32_HI; 95 } 96 } 97 98 const MCExpr *AMDGPUMCInstLower::getLongBranchBlockExpr( 99 const MachineBasicBlock &SrcBB, 100 const MachineOperand &MO) const { 101 const MCExpr *DestBBSym 102 = MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx); 103 const MCExpr *SrcBBSym = MCSymbolRefExpr::create(SrcBB.getSymbol(), Ctx); 104 105 // FIXME: The first half of this assert should be removed. This should 106 // probably be PC relative instead of using the source block symbol, and 107 // therefore the indirect branch expansion should use a bundle. 108 assert( 109 skipDebugInstructionsForward(SrcBB.begin(), SrcBB.end())->getOpcode() == 110 AMDGPU::S_GETPC_B64 && 111 ST.getInstrInfo()->get(AMDGPU::S_GETPC_B64).Size == 4); 112 113 // s_getpc_b64 returns the address of next instruction. 114 const MCConstantExpr *One = MCConstantExpr::create(4, Ctx); 115 SrcBBSym = MCBinaryExpr::createAdd(SrcBBSym, One, Ctx); 116 117 if (MO.getTargetFlags() == SIInstrInfo::MO_LONG_BRANCH_FORWARD) 118 return MCBinaryExpr::createSub(DestBBSym, SrcBBSym, Ctx); 119 120 assert(MO.getTargetFlags() == SIInstrInfo::MO_LONG_BRANCH_BACKWARD); 121 return MCBinaryExpr::createSub(SrcBBSym, DestBBSym, Ctx); 122 } 123 124 bool AMDGPUMCInstLower::lowerOperand(const MachineOperand &MO, 125 MCOperand &MCOp) const { 126 switch (MO.getType()) { 127 default: 128 llvm_unreachable("unknown operand type"); 129 case MachineOperand::MO_Immediate: 130 MCOp = MCOperand::createImm(MO.getImm()); 131 return true; 132 case MachineOperand::MO_Register: 133 MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST)); 134 return true; 135 case MachineOperand::MO_MachineBasicBlock: { 136 if (MO.getTargetFlags() != 0) { 137 MCOp = MCOperand::createExpr( 138 getLongBranchBlockExpr(*MO.getParent()->getParent(), MO)); 139 } else { 140 MCOp = MCOperand::createExpr( 141 MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 142 } 143 144 return true; 145 } 146 case MachineOperand::MO_GlobalAddress: { 147 const GlobalValue *GV = MO.getGlobal(); 148 SmallString<128> SymbolName; 149 AP.getNameWithPrefix(SymbolName, GV); 150 MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName); 151 const MCExpr *Expr = 152 MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx); 153 int64_t Offset = MO.getOffset(); 154 if (Offset != 0) { 155 Expr = MCBinaryExpr::createAdd(Expr, 156 MCConstantExpr::create(Offset, Ctx), Ctx); 157 } 158 MCOp = MCOperand::createExpr(Expr); 159 return true; 160 } 161 case MachineOperand::MO_ExternalSymbol: { 162 MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName())); 163 Sym->setExternal(true); 164 const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx); 165 MCOp = MCOperand::createExpr(Expr); 166 return true; 167 } 168 case MachineOperand::MO_RegisterMask: 169 // Regmasks are like implicit defs. 170 return false; 171 } 172 } 173 174 void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 175 unsigned Opcode = MI->getOpcode(); 176 const auto *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 177 178 // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We 179 // need to select it to the subtarget specific version, and there's no way to 180 // do that with a single pseudo source operation. 181 if (Opcode == AMDGPU::S_SETPC_B64_return) 182 Opcode = AMDGPU::S_SETPC_B64; 183 else if (Opcode == AMDGPU::SI_CALL) { 184 // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the 185 // called function (which we need to remove here). 186 OutMI.setOpcode(TII->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64)); 187 MCOperand Dest, Src; 188 lowerOperand(MI->getOperand(0), Dest); 189 lowerOperand(MI->getOperand(1), Src); 190 OutMI.addOperand(Dest); 191 OutMI.addOperand(Src); 192 return; 193 } else if (Opcode == AMDGPU::SI_TCRETURN) { 194 // TODO: How to use branch immediate and avoid register+add? 195 Opcode = AMDGPU::S_SETPC_B64; 196 } 197 198 int MCOpcode = TII->pseudoToMCOpcode(Opcode); 199 if (MCOpcode == -1) { 200 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 201 C.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have " 202 "a target-specific version: " + Twine(MI->getOpcode())); 203 } 204 205 OutMI.setOpcode(MCOpcode); 206 207 for (const MachineOperand &MO : MI->explicit_operands()) { 208 MCOperand MCOp; 209 lowerOperand(MO, MCOp); 210 OutMI.addOperand(MCOp); 211 } 212 213 int FIIdx = AMDGPU::getNamedOperandIdx(MCOpcode, AMDGPU::OpName::fi); 214 if (FIIdx >= (int)OutMI.getNumOperands()) 215 OutMI.addOperand(MCOperand::createImm(0)); 216 } 217 218 bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO, 219 MCOperand &MCOp) const { 220 const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 221 AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 222 return MCInstLowering.lowerOperand(MO, MCOp); 223 } 224 225 static const MCExpr *lowerAddrSpaceCast(const TargetMachine &TM, 226 const Constant *CV, 227 MCContext &OutContext) { 228 // TargetMachine does not support llvm-style cast. Use C++-style cast. 229 // This is safe since TM is always of type AMDGPUTargetMachine or its 230 // derived class. 231 auto &AT = static_cast<const AMDGPUTargetMachine&>(TM); 232 auto *CE = dyn_cast<ConstantExpr>(CV); 233 234 // Lower null pointers in private and local address space. 235 // Clang generates addrspacecast for null pointers in private and local 236 // address space, which needs to be lowered. 237 if (CE && CE->getOpcode() == Instruction::AddrSpaceCast) { 238 auto Op = CE->getOperand(0); 239 auto SrcAddr = Op->getType()->getPointerAddressSpace(); 240 if (Op->isNullValue() && AT.getNullPointerValue(SrcAddr) == 0) { 241 auto DstAddr = CE->getType()->getPointerAddressSpace(); 242 return MCConstantExpr::create(AT.getNullPointerValue(DstAddr), 243 OutContext); 244 } 245 } 246 return nullptr; 247 } 248 249 const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) { 250 if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 251 return E; 252 return AsmPrinter::lowerConstant(CV); 253 } 254 255 void AMDGPUAsmPrinter::emitInstruction(const MachineInstr *MI) { 256 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 257 return; 258 259 const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 260 AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 261 262 StringRef Err; 263 if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 264 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 265 C.emitError("Illegal instruction detected: " + Err); 266 MI->print(errs()); 267 } 268 269 if (MI->isBundle()) { 270 const MachineBasicBlock *MBB = MI->getParent(); 271 MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 272 while (I != MBB->instr_end() && I->isInsideBundle()) { 273 emitInstruction(&*I); 274 ++I; 275 } 276 } else { 277 // We don't want these pseudo instructions encoded. They are 278 // placeholder terminator instructions and should only be printed as 279 // comments. 280 if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) { 281 if (isVerbose()) 282 OutStreamer->emitRawComment(" return to shader part epilog"); 283 return; 284 } 285 286 if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) { 287 if (isVerbose()) 288 OutStreamer->emitRawComment(" wave barrier"); 289 return; 290 } 291 292 if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) { 293 if (isVerbose()) 294 OutStreamer->emitRawComment(" divergent unreachable"); 295 return; 296 } 297 298 MCInst TmpInst; 299 MCInstLowering.lower(MI, TmpInst); 300 EmitToStreamer(*OutStreamer, TmpInst); 301 302 #ifdef EXPENSIVE_CHECKS 303 // Sanity-check getInstSizeInBytes on explicitly specified CPUs (it cannot 304 // work correctly for the generic CPU). 305 // 306 // The isPseudo check really shouldn't be here, but unfortunately there are 307 // some negative lit tests that depend on being able to continue through 308 // here even when pseudo instructions haven't been lowered. 309 // 310 // We also overestimate branch sizes with the offset bug. 311 if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU()) && 312 (!STI.hasOffset3fBug() || !MI->isBranch())) { 313 SmallVector<MCFixup, 4> Fixups; 314 SmallVector<char, 16> CodeBytes; 315 raw_svector_ostream CodeStream(CodeBytes); 316 317 std::unique_ptr<MCCodeEmitter> InstEmitter(createSIMCCodeEmitter( 318 *STI.getInstrInfo(), *OutContext.getRegisterInfo(), OutContext)); 319 InstEmitter->encodeInstruction(TmpInst, CodeStream, Fixups, STI); 320 321 assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI)); 322 } 323 #endif 324 325 if (DumpCodeInstEmitter) { 326 // Disassemble instruction/operands to text 327 DisasmLines.resize(DisasmLines.size() + 1); 328 std::string &DisasmLine = DisasmLines.back(); 329 raw_string_ostream DisasmStream(DisasmLine); 330 331 AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(), 332 *STI.getRegisterInfo()); 333 InstPrinter.printInst(&TmpInst, 0, StringRef(), STI, DisasmStream); 334 335 // Disassemble instruction/operands to hex representation. 336 SmallVector<MCFixup, 4> Fixups; 337 SmallVector<char, 16> CodeBytes; 338 raw_svector_ostream CodeStream(CodeBytes); 339 340 DumpCodeInstEmitter->encodeInstruction( 341 TmpInst, CodeStream, Fixups, MF->getSubtarget<MCSubtargetInfo>()); 342 HexLines.resize(HexLines.size() + 1); 343 std::string &HexLine = HexLines.back(); 344 raw_string_ostream HexStream(HexLine); 345 346 for (size_t i = 0; i < CodeBytes.size(); i += 4) { 347 unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i]; 348 HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord); 349 } 350 351 DisasmStream.flush(); 352 DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size()); 353 } 354 } 355 } 356 357 R600MCInstLower::R600MCInstLower(MCContext &Ctx, const R600Subtarget &ST, 358 const AsmPrinter &AP) : 359 AMDGPUMCInstLower(Ctx, ST, AP) { } 360 361 void R600MCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 362 OutMI.setOpcode(MI->getOpcode()); 363 for (const MachineOperand &MO : MI->explicit_operands()) { 364 MCOperand MCOp; 365 lowerOperand(MO, MCOp); 366 OutMI.addOperand(MCOp); 367 } 368 } 369 370 void R600AsmPrinter::emitInstruction(const MachineInstr *MI) { 371 const R600Subtarget &STI = MF->getSubtarget<R600Subtarget>(); 372 R600MCInstLower MCInstLowering(OutContext, STI, *this); 373 374 StringRef Err; 375 if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 376 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 377 C.emitError("Illegal instruction detected: " + Err); 378 MI->print(errs()); 379 } 380 381 if (MI->isBundle()) { 382 const MachineBasicBlock *MBB = MI->getParent(); 383 MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 384 while (I != MBB->instr_end() && I->isInsideBundle()) { 385 emitInstruction(&*I); 386 ++I; 387 } 388 } else { 389 MCInst TmpInst; 390 MCInstLowering.lower(MI, TmpInst); 391 EmitToStreamer(*OutStreamer, TmpInst); 392 } 393 } 394 395 const MCExpr *R600AsmPrinter::lowerConstant(const Constant *CV) { 396 if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 397 return E; 398 return AsmPrinter::lowerConstant(CV); 399 } 400