Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions shared/stinkytofu/src/analysis/asm/AsmVerifierPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,23 @@ static std::string checkRegisterWidths(const StinkyInstruction* inst,
// receive a VGPR, not a SGPR (and vice versa).
RegType expectedType = fieldTypeToRegType(field.fieldType);
if (!isExpectedTypeMatch(field.fieldType, expectedType, reg.reg.type)) {
errors << "Instruction '";
inst->dump(errors);
errors << "' operand " << (isDest ? "dest[" : "src[") << operandIndex << "] "
<< "has register type '" << regTypeToString(reg.reg.type) << "', expected '"
<< regTypeToString(expectedType) << "'\n";
// Check promoted encoding: e.g. VOP2 src1 is vgpr-only, but VOP3
// promotion widens it to src (accepts SGPR). The assembler will
// promote automatically, so accept the promoted field type too.
unsigned fieldIdx = static_cast<unsigned>(&field - hwDesc->operandFields.data());
bool promotedOk = false;
if (fieldIdx < hwDesc->promotedFields.size()) {
auto promotedFT = hwDesc->promotedFields[fieldIdx].fieldType;
auto promotedET = fieldTypeToRegType(promotedFT);
promotedOk = isExpectedTypeMatch(promotedFT, promotedET, reg.reg.type);
}
if (!promotedOk) {
errors << "Instruction '";
inst->dump(errors);
errors << "' operand " << (isDest ? "dest[" : "src[") << operandIndex << "] "
<< "has register type '" << regTypeToString(reg.reg.type) << "', expected '"
<< regTypeToString(expectedType) << "'\n";
}
}
}

Expand Down
46 changes: 46 additions & 0 deletions shared/stinkytofu/tests/filecheck/verifier_vop2_sgpr_src.stir
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# RUN: %stinkytofu-opt --arch gfx1250 %s --StinkyIRVerifierPass --print-output 2>&1
#
# Verify that VOP2/VOPC instructions accept SGPR source operands without
# triggering register-type errors. The base VOP2 encoding restricts src1
# to vgpr, but VOP3 promotion widens it to accept SGPRs. The verifier
# must check promotedFields before rejecting.

#--- v_mul_u32_u24 with SGPR src1
# CHECK-LABEL: @vop2_sgpr_src1_mul
# CHECK-NOT: [StinkyIRVerifier]
# CHECK: v_mul_u32_u24

st.func @vop2_sgpr_src1_mul() {
^entry:
v1 = "st.v_mul_u32_u24"(v0, s16) { issueCycles = 1, latencyCycles = 5 }
}

#--- v_cmp_eq_u32 with SGPR src1
# CHECK-LABEL: @vopc_sgpr_src1_cmp_eq
# CHECK-NOT: [StinkyIRVerifier]
# CHECK: v_cmp_eq_u32

st.func @vopc_sgpr_src1_cmp_eq() {
^entry:
vcc_lo0 = "st.v_cmp_eq_u32"(v1, s16) { issueCycles = 1, latencyCycles = 5 }
}

#--- v_cmp_gt_u32 with SGPR src1
# CHECK-LABEL: @vopc_sgpr_src1_cmp_gt
# CHECK-NOT: [StinkyIRVerifier]
# CHECK: v_cmp_gt_u32

st.func @vopc_sgpr_src1_cmp_gt() {
^entry:
vcc_lo0 = "st.v_cmp_gt_u32"(v1, s15) { issueCycles = 1, latencyCycles = 5 }
}

#--- v_cmp_ge_u32 with SGPR src1
# CHECK-LABEL: @vopc_sgpr_src1_cmp_ge
# CHECK-NOT: [StinkyIRVerifier]
# CHECK: v_cmp_ge_u32

st.func @vopc_sgpr_src1_cmp_ge() {
^entry:
vcc_lo0 = "st.v_cmp_ge_u32"(v2, s18) { issueCycles = 1, latencyCycles = 5 }
}
Loading