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 SI_MASK_BRANCH/SI_RETURN_TO_EPILOG encoded. They are 278 // placeholder terminator instructions and should only be printed as 279 // comments. 280 if (MI->getOpcode() == AMDGPU::SI_MASK_BRANCH) { 281 if (isVerbose()) { 282 SmallVector<char, 16> BBStr; 283 raw_svector_ostream Str(BBStr); 284 285 const MachineBasicBlock *MBB = MI->getOperand(0).getMBB(); 286 const MCSymbolRefExpr *Expr 287 = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); 288 Expr->print(Str, MAI); 289 OutStreamer->emitRawComment(Twine(" mask branch ") + BBStr); 290 } 291 292 return; 293 } 294 295 if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) { 296 if (isVerbose()) 297 OutStreamer->emitRawComment(" return to shader part epilog"); 298 return; 299 } 300 301 if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) { 302 if (isVerbose()) 303 OutStreamer->emitRawComment(" wave barrier"); 304 return; 305 } 306 307 if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) { 308 if (isVerbose()) 309 OutStreamer->emitRawComment(" divergent unreachable"); 310 return; 311 } 312 313 MCInst TmpInst; 314 MCInstLowering.lower(MI, TmpInst); 315 EmitToStreamer(*OutStreamer, TmpInst); 316 317 #ifdef EXPENSIVE_CHECKS 318 // Sanity-check getInstSizeInBytes on explicitly specified CPUs (it cannot 319 // work correctly for the generic CPU). 320 // 321 // The isPseudo check really shouldn't be here, but unfortunately there are 322 // some negative lit tests that depend on being able to continue through 323 // here even when pseudo instructions haven't been lowered. 324 // 325 // We also overestimate branch sizes with the offset bug. 326 if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU()) && 327 (!STI.hasOffset3fBug() || !MI->isBranch())) { 328 SmallVector<MCFixup, 4> Fixups; 329 SmallVector<char, 16> CodeBytes; 330 raw_svector_ostream CodeStream(CodeBytes); 331 332 std::unique_ptr<MCCodeEmitter> InstEmitter(createSIMCCodeEmitter( 333 *STI.getInstrInfo(), *OutContext.getRegisterInfo(), OutContext)); 334 InstEmitter->encodeInstruction(TmpInst, CodeStream, Fixups, STI); 335 336 assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI)); 337 } 338 #endif 339 340 if (DumpCodeInstEmitter) { 341 // Disassemble instruction/operands to text 342 DisasmLines.resize(DisasmLines.size() + 1); 343 std::string &DisasmLine = DisasmLines.back(); 344 raw_string_ostream DisasmStream(DisasmLine); 345 346 AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(), 347 *STI.getRegisterInfo()); 348 InstPrinter.printInst(&TmpInst, 0, StringRef(), STI, DisasmStream); 349 350 // Disassemble instruction/operands to hex representation. 351 SmallVector<MCFixup, 4> Fixups; 352 SmallVector<char, 16> CodeBytes; 353 raw_svector_ostream CodeStream(CodeBytes); 354 355 DumpCodeInstEmitter->encodeInstruction( 356 TmpInst, CodeStream, Fixups, MF->getSubtarget<MCSubtargetInfo>()); 357 HexLines.resize(HexLines.size() + 1); 358 std::string &HexLine = HexLines.back(); 359 raw_string_ostream HexStream(HexLine); 360 361 for (size_t i = 0; i < CodeBytes.size(); i += 4) { 362 unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i]; 363 HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord); 364 } 365 366 DisasmStream.flush(); 367 DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size()); 368 } 369 } 370 } 371 372 R600MCInstLower::R600MCInstLower(MCContext &Ctx, const R600Subtarget &ST, 373 const AsmPrinter &AP) : 374 AMDGPUMCInstLower(Ctx, ST, AP) { } 375 376 void R600MCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 377 OutMI.setOpcode(MI->getOpcode()); 378 for (const MachineOperand &MO : MI->explicit_operands()) { 379 MCOperand MCOp; 380 lowerOperand(MO, MCOp); 381 OutMI.addOperand(MCOp); 382 } 383 } 384 385 void R600AsmPrinter::emitInstruction(const MachineInstr *MI) { 386 const R600Subtarget &STI = MF->getSubtarget<R600Subtarget>(); 387 R600MCInstLower MCInstLowering(OutContext, STI, *this); 388 389 StringRef Err; 390 if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 391 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 392 C.emitError("Illegal instruction detected: " + Err); 393 MI->print(errs()); 394 } 395 396 if (MI->isBundle()) { 397 const MachineBasicBlock *MBB = MI->getParent(); 398 MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 399 while (I != MBB->instr_end() && I->isInsideBundle()) { 400 emitInstruction(&*I); 401 ++I; 402 } 403 } else { 404 MCInst TmpInst; 405 MCInstLowering.lower(MI, TmpInst); 406 EmitToStreamer(*OutStreamer, TmpInst); 407 } 408 } 409 410 const MCExpr *R600AsmPrinter::lowerConstant(const Constant *CV) { 411 if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 412 return E; 413 return AsmPrinter::lowerConstant(CV); 414 } 415