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:
parent
283c47b4c5
commit
1d7a0fa08a
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user