diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h @@ -81,6 +81,8 @@ const TargetRegisterClass &SubRC, unsigned SubIdx) const; + Register getLiveInRegister(Register SrcReg) const; + bool constrainCopyLikeIntrin(MachineInstr &MI, unsigned NewOpc) const; bool selectCOPY(MachineInstr &I) const; bool selectPHI(MachineInstr &I) const; @@ -105,6 +107,7 @@ bool selectDSOrderedIntrinsic(MachineInstr &MI, Intrinsic::ID IID) const; bool selectDSGWSIntrinsic(MachineInstr &MI, Intrinsic::ID IID) const; bool selectDSAppendConsume(MachineInstr &MI, bool IsAppend) const; + bool selectTrapIntrinsic(MachineInstr &MI) const; bool selectG_INTRINSIC_W_SIDE_EFFECTS(MachineInstr &I) const; int getS_CMPOpcode(CmpInst::Predicate P, unsigned Size) const; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -258,6 +258,15 @@ } } +Register AMDGPUInstructionSelector::getLiveInRegister(Register SrcReg) const { + Register LiveIn = MRI->getLiveInVirtReg(SrcReg); + if (!LiveIn) { + LiveIn = MRI->createGenericVirtualRegister(MRI->getType(SrcReg)); + MRI->addLiveIn(SrcReg, LiveIn); + } + return LiveIn; +} + static unsigned getLogicalBitOpcode(unsigned Opc, bool Is64) { switch (Opc) { case AMDGPU::G_AND: @@ -1093,6 +1102,44 @@ return true; } +bool AMDGPUInstructionSelector::selectTrapIntrinsic(MachineInstr &MI) const { + MachineBasicBlock *MBB = MI.getParent(); + MachineFunction *MF = MBB->getParent(); + const DebugLoc &DL = MI.getDebugLoc(); + + // Is non-HSA path or trap-handler disabled? then, insert s_endpgm instruction + if (STI.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbiHsa || + !STI.isTrapHandlerEnabled()) { + BuildMI(*MBB, &MI, DL, TII.get(AMDGPU::S_ENDPGM)).addImm(0); + } else { + // Pass queue pointer to trap handler as input + // Reference: https://llvm.org/docs/AMDGPUUsage.html#trap-handler-abi + unsigned RegNo = + MF->getInfo()->getQueuePtrUserSGPR(); + assert(RegNo != AMDGPU::NoRegister); + Register SrcReg = Register(RegNo); + Register LiveIn = getLiveInRegister(SrcReg); + Register DstReg(AMDGPU::SGPR0_SGPR1); + BuildMI(*MBB, &MI, DL, TII.get(AMDGPU::COPY), DstReg).addReg(LiveIn); + + if (!MRI->getVRegDef(LiveIn)) { + MachineBasicBlock &EntryMBB = MF->front(); + EntryMBB.addLiveIn(SrcReg); + BuildMI(EntryMBB, EntryMBB.begin(), DebugLoc(), TII.get(AMDGPU::COPY), + LiveIn) + .addReg(SrcReg); + } + + // Insert trap instruction + BuildMI(*MBB, &MI, DL, TII.get(AMDGPU::S_TRAP)) + .addImm(GCNSubtarget::TrapIDLLVMTrap) + .addReg(DstReg, RegState::Implicit); + } + + MI.eraseFromParent(); + return true; +} + bool AMDGPUInstructionSelector::selectG_INTRINSIC_W_SIDE_EFFECTS( MachineInstr &I) const { unsigned IntrinsicID = I.getIntrinsicID(); @@ -1113,6 +1160,8 @@ return selectDSAppendConsume(I, true); case Intrinsic::amdgcn_ds_consume: return selectDSAppendConsume(I, false); + case Intrinsic::trap: + return selectTrapIntrinsic(I); default: return selectImpl(I, *CoverageInfo); } diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-trap.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-trap.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-trap.ll @@ -0,0 +1,43 @@ +; hsa: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=LABLE-HSA-TRAP -check-prefix=HSA-TRAP %s +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=LABLE-HSA-TRAP -check-prefix=HSA-TRAP %s + +; hsa: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=LABLE-HSA-TRAP -check-prefix=NO-HSA-TRAP %s + +; mesa: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=LABLE-HSA-TRAP -check-prefix=MESA-TRAP %s + +; mesa: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=LABLE-HSA-TRAP -check-prefix=NO-MESA-TRAP %s + +declare void @llvm.trap() #0 + +; LABLE-HSA-TRAP: {{^}}hsa_trap: + +; HSA-TRAP: enable_trap_handler = 0 +; HSA-TRAP: s_mov_b64 s[0:1], s[4:5] +; HSA-TRAP: s_trap 2 +; HSA-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 + +; NO-HSA-TRAP: enable_trap_handler = 0 +; NO-HSA-TRAP: s_endpgm +; NO-HSA-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 + +; MESA-TRAP: enable_trap_handler = 1 +; MESA-TRAP: s_endpgm +; MESA-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 1 + +; NO-MESA-TRAP: enable_trap_handler = 0 +; NO-MESA-TRAP: s_endpgm +; NO-MESA-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 + +define amdgpu_kernel void @hsa_trap(i32 addrspace(1)* nocapture readonly %arg0) { + store volatile i32 1, i32 addrspace(1)* %arg0 + call void @llvm.trap() + unreachable + store volatile i32 2, i32 addrspace(1)* %arg0 + ret void +} + +attributes #0 = { nounwind noreturn }