AMDGPU: Move asm constraint physreg parsing to utils (#150903)

Also fixes an assertion on out of bound physical register
indexes.
This commit is contained in:
Matt Arsenault 2025-08-01 16:11:11 +09:00 committed by GitHub
parent 283c47b4c5
commit 1d7a0fa08a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 177 additions and 42 deletions

View File

@ -16825,56 +16825,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())
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);
}
}
} else {
// Check for lossy scalar/vector conversions.
if (VT.isVector() && VT.getSizeInBits() != 32)
if (NumRegs > 1) {
if (Idx >= RC->getNumRegs() || Idx + NumRegs - 1 > RC->getNumRegs())
return std::pair(0U, nullptr);
bool Failed = RegName.getAsInteger(10, Idx);
if (!Failed && Idx < RC->getNumRegs())
return std::pair(RC->getRegister(Idx), RC);
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);
}
return std::pair(Reg, 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);
}
}

View File

@ -1548,6 +1548,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<char, unsigned, unsigned>
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<unsigned, unsigned>
getIntegerPairAttribute(const Function &F, StringRef Name,
std::pair<unsigned, unsigned> Default,

View File

@ -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<char, unsigned, unsigned>
parseAsmConstraintPhysReg(StringRef Constraint);
/// \returns Integer value requested using \p F's \p Name attribute.
///
/// \returns \p Default if attribute is not present.

View File

@ -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
}