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