diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 8d51ec6dc7f31..6eebf62d73c0e 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -16700,56 +16700,51 @@ SITargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI_, return std::pair(0U, RC); } - if (Constraint.starts_with("{") && Constraint.ends_with("}")) { - StringRef RegName(Constraint.data() + 1, Constraint.size() - 2); - if (RegName.consume_front("v")) { + auto [Kind, Idx, NumRegs] = AMDGPU::parseAsmConstraintPhysReg(Constraint); + if (Kind != '\0') { + if (Kind == 'v') { RC = &AMDGPU::VGPR_32RegClass; - } else if (RegName.consume_front("s")) { + } else if (Kind == 's') { RC = &AMDGPU::SGPR_32RegClass; - } else if (RegName.consume_front("a")) { + } else if (Kind == 'a') { RC = &AMDGPU::AGPR_32RegClass; } if (RC) { - uint32_t Idx; - if (RegName.consume_front("[")) { - uint32_t End; - bool Failed = RegName.consumeInteger(10, Idx); - Failed |= !RegName.consume_front(":"); - Failed |= RegName.consumeInteger(10, End); - Failed |= !RegName.consume_back("]"); - if (!Failed) { - uint32_t Width = (End - Idx + 1) * 32; - // Prohibit constraints for register ranges with a width that does not - // match the required type. - if (VT.SimpleTy != MVT::Other && Width != VT.getSizeInBits()) + if (NumRegs > 1) { + if (Idx >= RC->getNumRegs() || Idx + NumRegs - 1 > RC->getNumRegs()) + return std::pair(0U, nullptr); + + uint32_t Width = NumRegs * 32; + // Prohibit constraints for register ranges with a width that does not + // match the required type. + if (VT.SimpleTy != MVT::Other && Width != VT.getSizeInBits()) + return std::pair(0U, nullptr); + + MCRegister Reg = RC->getRegister(Idx); + if (SIRegisterInfo::isVGPRClass(RC)) + RC = TRI->getVGPRClassForBitWidth(Width); + else if (SIRegisterInfo::isSGPRClass(RC)) + RC = TRI->getSGPRClassForBitWidth(Width); + else if (SIRegisterInfo::isAGPRClass(RC)) + RC = TRI->getAGPRClassForBitWidth(Width); + if (RC) { + Reg = TRI->getMatchingSuperReg(Reg, AMDGPU::sub0, RC); + if (!Reg) { + // The register class does not contain the requested register, + // e.g., because it is an SGPR pair that would violate alignment + // requirements. return std::pair(0U, nullptr); - MCRegister Reg = RC->getRegister(Idx); - if (SIRegisterInfo::isVGPRClass(RC)) - RC = TRI->getVGPRClassForBitWidth(Width); - else if (SIRegisterInfo::isSGPRClass(RC)) - RC = TRI->getSGPRClassForBitWidth(Width); - else if (SIRegisterInfo::isAGPRClass(RC)) - RC = TRI->getAGPRClassForBitWidth(Width); - if (RC) { - Reg = TRI->getMatchingSuperReg(Reg, AMDGPU::sub0, RC); - if (!Reg) { - // The register class does not contain the requested register, - // e.g., because it is an SGPR pair that would violate alignment - // requirements. - return std::pair(0U, nullptr); - } - return std::pair(Reg, RC); } + return std::pair(Reg, RC); } - } else { - // Check for lossy scalar/vector conversions. - if (VT.isVector() && VT.getSizeInBits() != 32) - return std::pair(0U, nullptr); - bool Failed = RegName.getAsInteger(10, Idx); - if (!Failed && Idx < RC->getNumRegs()) - return std::pair(RC->getRegister(Idx), RC); } + + // Check for lossy scalar/vector conversions. + if (VT.isVector() && VT.getSizeInBits() != 32) + return std::pair(0U, nullptr); + if (Idx < RC->getNumRegs()) + return std::pair(RC->getRegister(Idx), RC); } } diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp index b5b3cc97569ed..dff377135d62b 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -1541,6 +1541,42 @@ bool shouldEmitConstantsToTextSection(const Triple &TT) { return TT.getArch() == Triple::r600; } +static bool isValidRegPrefix(char C) { + return C == 'v' || C == 's' || C == 'a'; +} + +std::tuple +parseAsmConstraintPhysReg(StringRef Constraint) { + StringRef RegName = Constraint; + if (!RegName.consume_front("{") || !RegName.consume_back("}")) + return {}; + + char Kind = RegName.front(); + if (!isValidRegPrefix(Kind)) + return {}; + + RegName = RegName.drop_front(); + if (RegName.consume_front("[")) { + unsigned Idx, End; + bool Failed = RegName.consumeInteger(10, Idx); + Failed |= !RegName.consume_front(":"); + Failed |= RegName.consumeInteger(10, End); + Failed |= !RegName.consume_back("]"); + if (!Failed) { + unsigned NumRegs = End - Idx + 1; + if (NumRegs > 1) + return {Kind, Idx, NumRegs}; + } + } else { + unsigned Idx; + bool Failed = RegName.getAsInteger(10, Idx); + if (!Failed) + return {Kind, Idx, 1}; + } + + return {}; +} + std::pair getIntegerPairAttribute(const Function &F, StringRef Name, std::pair Default, diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h index c09a9d694f3d8..498ac12837c56 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -1012,6 +1012,12 @@ bool isReadOnlySegment(const GlobalValue *GV); /// target triple \p TT, false otherwise. bool shouldEmitConstantsToTextSection(const Triple &TT); +/// Returns a valid charcode or 0 in the first entry if this is a valid physical +/// register constraint. Followed by the start register number, and the register +/// width. Does not validate the number of registers exists in the class. +std::tuple +parseAsmConstraintPhysReg(StringRef Constraint); + /// \returns Integer value requested using \p F's \p Name attribute. /// /// \returns \p Default if attribute is not present. diff --git a/llvm/test/CodeGen/AMDGPU/inline-asm-out-of-bounds-register.ll b/llvm/test/CodeGen/AMDGPU/inline-asm-out-of-bounds-register.ll new file mode 100644 index 0000000000000..892955c3973b0 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/inline-asm-out-of-bounds-register.ll @@ -0,0 +1,98 @@ +; RUN: not llc -mtriple=amdgcn-amd-amdhsa -mcpu=bonaire -filetype=null %s 2>&1 | FileCheck -implicit-check-not=error %s + +; CHECK: error: couldn't allocate output register for constraint '{v256}' +define void @out_of_bounds_vgpr32_def() { + %v = tail call i32 asm sideeffect "v_mov_b32 $0, -1", "={v256}"() + ret void +} + +; CHECK: error: couldn't allocate output register for constraint '{v[255:256]}' +define void @out_of_bounds_vgpr64_def_high_tuple() { + %v = tail call i32 asm sideeffect "v_mov_b32 $0, -1", "={v[255:256]}"() + ret void +} + +; CHECK: error: couldn't allocate output register for constraint '{v[256:257]}' +define void @out_of_bounds_vgpr64_def_low_tuple() { + %v = tail call i32 asm sideeffect "v_mov_b32 $0, -1", "={v[256:257]}"() + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v256}' +define void @out_of_bounds_vgpr32_use() { + %v = tail call i32 asm sideeffect "v_mov_b32 %0, %1", "=v,{v256}"(i32 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[255:256]}' +define void @out_of_bounds_vgpr64_high_tuple() { + tail call void asm sideeffect "; use %0", "{v[255:256]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[256:257]}' +define void @out_of_bounds_vgpr64_low_tuple() { + tail call void asm sideeffect "; use %0", "{v[256:257]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[1:0]}' +define void @vgpr_tuple_swapped() { + tail call void asm sideeffect "; use %0", "{v[1:0]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v4294967295}' +define void @vgpr_uintmax() { + tail call void asm sideeffect "; use %0", "{v4294967295}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v4294967296}' +define void @vgpr_uintmax_p1() { + tail call void asm sideeffect "; use %0", "{v4294967296}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[4294967295:4294967296]}' +define void @vgpr_tuple_uintmax() { + tail call void asm sideeffect "; use %0", "{v[4294967295:4294967296]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[0:4294967295]}' +define void @vgpr_tuple_0_uintmax() { + tail call void asm sideeffect "; use %0", "{v[0:4294967295]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[0:4294967296]}' +define void @vgpr_tuple_0_uintmax_p1() { + tail call void asm sideeffect "; use %0", "{v[0:4294967296]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[4294967264:4294967295]}' +define void @vgpr32_last_is_uintmax() { + tail call void asm sideeffect "; use %0", "{v[4294967264:4294967295]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[4294967265:4294967296]}' +define void @vgpr32_last_is_uintmax_p1() { + tail call void asm sideeffect "; use %0", "{v[4294967265:4294967296]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[2:2147483651]}' +define void @overflow_bitwidth_0() { + tail call void asm sideeffect "; use %0", "{v[2:2147483651]}"(i64 123) + ret void +} + +; CHECK: error: couldn't allocate input reg for constraint '{v[2147483635:2147483651]}' +define void @overflow_bitwidth_1() { + tail call void asm sideeffect "; use %0", "{v[2147483635:2147483651]}"(i64 123) + ret void +} +