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