diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h --- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h +++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h @@ -91,6 +91,10 @@ Register getLiveInRegister(MachineRegisterInfo &MRI, Register Reg, LLT Ty) const; + const ArgDescriptor * + getArgDescriptor(MachineIRBuilder &B, + AMDGPUFunctionArgInfo::PreloadedValue ArgType) const; + bool loadInputValue(Register DstReg, MachineIRBuilder &B, const ArgDescriptor *Arg) const; bool legalizePreloadedArgIntrin( @@ -148,6 +152,11 @@ bool legalizeAtomicIncDec(MachineInstr &MI, MachineIRBuilder &B, bool IsInc) const; + bool legalizeTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilder &B) const; + bool legalizeDebugTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilder &B) const; + bool legalizeIntrinsic(MachineInstr &MI, MachineIRBuilder &B, GISelChangeObserver &Observer) const override; }; diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp @@ -2219,6 +2219,19 @@ return NewReg; } +const ArgDescriptor *AMDGPULegalizerInfo::getArgDescriptor( + MachineIRBuilder &B, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const { + const SIMachineFunctionInfo *MFI = B.getMF().getInfo(); + const ArgDescriptor *Arg; + const TargetRegisterClass *RC; + std::tie(Arg, RC) = MFI->getPreloadedValue(ArgType); + if (!Arg) { + LLVM_DEBUG(dbgs() << "Required arg register missing\n"); + return nullptr; + } + return Arg; +} + bool AMDGPULegalizerInfo::loadInputValue(Register DstReg, MachineIRBuilder &B, const ArgDescriptor *Arg) const { if (!Arg->isRegister() || !Arg->getRegister().isValid()) @@ -3344,6 +3357,55 @@ return true; } +bool AMDGPULegalizerInfo::legalizeTrapIntrinsic(MachineInstr &MI, + MachineRegisterInfo &MRI, + MachineIRBuilder &B) const { + B.setInstr(MI); + + // Is non-HSA path or trap-handler disabled? then, insert s_endpgm instruction + if (ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbiHsa || + !ST.isTrapHandlerEnabled()) { + B.buildInstr(AMDGPU::S_ENDPGM).addImm(0); + } else { + // Pass queue pointer to trap handler as input, and insert trap instruction + // Reference: https://llvm.org/docs/AMDGPUUsage.html#trap-handler-abi + const ArgDescriptor *Arg; + if (!(Arg = getArgDescriptor(B, AMDGPUFunctionArgInfo::QUEUE_PTR))) + return false; + Register DstReg(AMDGPU::SGPR0_SGPR1); + if (!loadInputValue(DstReg, B, Arg)) + return false; + B.buildInstr(AMDGPU::S_TRAP) + .addImm(GCNSubtarget::TrapIDLLVMTrap) + .addReg(DstReg, RegState::Implicit); + } + + MI.eraseFromParent(); + return true; +} + +bool AMDGPULegalizerInfo::legalizeDebugTrapIntrinsic( + MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const { + B.setInstr(MI); + + // Is non-HSA path or trap-handler disabled? then, report a warning + // accordingly + if (ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbiHsa || + !ST.isTrapHandlerEnabled()) { + DiagnosticInfoUnsupported NoTrap(B.getMF().getFunction(), + "debugtrap handler not supported", + MI.getDebugLoc(), DS_Warning); + LLVMContext &Ctx = B.getMF().getFunction().getContext(); + Ctx.diagnose(NoTrap); + } else { + // Insert debug-trap instruction + B.buildInstr(AMDGPU::S_TRAP).addImm(GCNSubtarget::TrapIDLLVMDebugTrap); + } + + MI.eraseFromParent(); + return true; +} + bool AMDGPULegalizerInfo::legalizeIntrinsic(MachineInstr &MI, MachineIRBuilder &B, GISelChangeObserver &Observer) const { @@ -3511,6 +3573,10 @@ return legalizeAtomicIncDec(MI, B, true); case Intrinsic::amdgcn_atomic_dec: return legalizeAtomicIncDec(MI, B, false); + case Intrinsic::trap: + return legalizeTrapIntrinsic(MI, MRI, B); + case Intrinsic::debugtrap: + return legalizeDebugTrapIntrinsic(MI, MRI, B); default: { if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr = AMDGPU::getImageDimIntrinsicInfo(IntrID)) diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.debugtrap.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.debugtrap.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.debugtrap.ll @@ -0,0 +1,53 @@ +; ISelDAG path: +; hsa-path: trap handler enabled +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-DEBUG-TRAP %s +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-DEBUG-TRAP %s + +; hsa-path: trap handler disabled +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=-trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=NO-HSA-DEBUG-TRAP %s + +; non-hsa-path: trap handler enabled +; RUN: llc -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=+trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=MESA-DEBUG-TRAP %s + +; non-hsa-path: trap handler disabled +; RUN: llc -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=-trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=NO-MESA-DEBUG-TRAP %s + +; GlobalISel path: +; hsa-path: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-DEBUG-TRAP %s +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-DEBUG-TRAP %s + +; hsa-path: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=-trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=NO-HSA-DEBUG-TRAP %s + +; non-hsa-path: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=+trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=MESA-DEBUG-TRAP %s + +; non-hsa-path: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=-trap-handler < %s 2>&1 | FileCheck -check-prefix=WARNING -check-prefix=ENTRY-LABLE -check-prefix=NO-MESA-DEBUG-TRAP %s + +declare void @llvm.debugtrap() #0 + +; WARNING: warning: :0:0: in function debug_trap void (i32 addrspace(1)*): debugtrap handler not supported + +; ENTRY-LABLE: {{^}}debug_trap: + +; HSA-DEBUG-TRAP: enable_trap_handler = 0 +; HSA-DEBUG-TRAP: s_trap 3 +; HSA-DEBUG-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 + +; NO-HSA-DEBUG-TRAP: enable_trap_handler = 0 +; NO-HSA-DEBUG-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 + +; MESA-DEBUG-TRAP: enable_trap_handler = 1 +; MESA-DEBUG-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 1 + +; NO-MESA-DEBUG-TRAP: enable_trap_handler = 0 +; NO-MESA-DEBUG-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 +define amdgpu_kernel void @debug_trap(i32 addrspace(1)* nocapture readonly %arg0) { + store volatile i32 1, i32 addrspace(1)* %arg0 + call void @llvm.debugtrap() + ret void +} + +attributes #0 = { nounwind noreturn } diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.trap.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.trap.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.trap.ll @@ -0,0 +1,96 @@ +; ISelDAG path: +; hsa-path: trap handler enabled +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-TRAP %s +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-TRAP %s + +; hsa-path: trap handler disabled +; RUN: llc -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=NO-HSA-TRAP %s + +; non-hsa-path: trap handler enabled +; RUN: llc -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=MESA-TRAP %s + +; non-hsa-path: trap handler disabled +; RUN: llc -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=NO-MESA-TRAP %s + +; GlobalISel path: +; hsa-path: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-TRAP %s +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=HSA-TRAP %s + +; hsa-path: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-amd-amdhsa -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=NO-HSA-TRAP %s + +; non-hsa-path: trap handler enabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=+trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=MESA-TRAP %s + +; non-hsa-path: trap handler disabled +; RUN: llc -global-isel -mtriple=amdgcn-unknown-mesa3d -verify-machineinstrs -mattr=-trap-handler < %s | FileCheck -check-prefix=ENTRY-LABLE -check-prefix=NO-MESA-TRAP %s + +declare void @llvm.trap() #0 + +; ENTRY-LABLE: {{^}}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 @trap(i32 addrspace(1)* nocapture readonly %arg0) { + store volatile i32 1, i32 addrspace(1)* %arg0 + call void @llvm.trap() + ret void +} + +; ENTRY-LABLE: {{^}}non_entry_trap: + +; HSA-TRAP: enable_trap_handler = 0 +; HSA-TRAP: s_endpgm +; HSA-TRAP: BB{{[0-9]_[0-9]+}}: ; %trap +; 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: BB{{[0-9]_[0-9]+}}: ; %trap +; 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: BB{{[0-9]_[0-9]+}}: ; %trap +; 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: BB{{[0-9]_[0-9]+}}: ; %trap +; NO-MESA-TRAP: s_endpgm +; NO-MESA-TRAP: COMPUTE_PGM_RSRC2:TRAP_HANDLER: 0 +define amdgpu_kernel void @non_entry_trap(i32 addrspace(1)* nocapture readonly %arg0) local_unnamed_addr { +entry: + %tmp29 = load volatile i32, i32 addrspace(1)* %arg0 + %cmp = icmp eq i32 %tmp29, -1 + br i1 %cmp, label %ret, label %trap + +trap: + call void @llvm.trap() + unreachable + +ret: + store volatile i32 3, i32 addrspace(1)* %arg0 + ret void +} + +attributes #0 = { nounwind noreturn }