[SPIRV] Preserve sign-sensitive width record across G_TRUNC replacement (#211626)
**Summary** Follow-up to #203661. When the `G_TRUNC` handler in `SPIRVPreLegalizer` collapses source and destination to the same widened width, it calls `MRI.replaceRegWith(DstReg, MaskedReg)` and drops the original `G_TRUNC`. The `SignSensitiveInfo.OrigWidth` map, however, was still keyed on `DstReg`, so `widenSignSensitiveOps` no longer found the narrow original width and skipped the `shl/ashr` sign extension for signed users of the truncated value. Rekey `OrigWidth` from `DstReg` to `MaskedReg` before the `replaceRegWith` so signed ops fed by the truncated value still receive `G_SEXT_INREG` on the widened type. **Test plan** New test case is added to `llvm/test/CodeGen/SPIRV/legalization/signed-narrow-int.ll`: `trunc i8 → i4` feeding `icmp slt` — src and dst both widen to `i8`, exercising the same-width `replaceRegWith` path. Checks that the widened `i8` compare is preceded by matching `OpShiftLeftLogical / OpShiftRightArithmetic` pairs on both operands.
This commit is contained in:
parent
a4a9b6864c
commit
ee25d3ec23
2 changed files with 33 additions and 0 deletions
|
|
@ -684,6 +684,14 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
|
|||
MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
|
||||
|
||||
if (NewSrcWidth == NewDstWidth) {
|
||||
// Rekey OrigWidth from DstReg to MaskedReg so widenSignSensitiveOps
|
||||
// still sees the narrow original width after replaceRegWith.
|
||||
if (auto It = SignSensitiveInfo.OrigWidth.find(DstReg);
|
||||
It != SignSensitiveInfo.OrigWidth.end()) {
|
||||
unsigned W = It->second;
|
||||
SignSensitiveInfo.OrigWidth.erase(It);
|
||||
SignSensitiveInfo.OrigWidth.try_emplace(MaskedReg, W);
|
||||
}
|
||||
MRI.replaceRegWith(DstReg, MaskedReg);
|
||||
TruncToRemove.push_back(&MI);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -225,6 +225,31 @@ define spir_kernel void @trunc_i24_icmp_slt(i64 %a, ptr addrspace(1) %out) {
|
|||
ret void
|
||||
}
|
||||
|
||||
; ----------------------------------------------------------------------------
|
||||
; trunc i8 to i4 feeding icmp slt: source and destination widen to the same
|
||||
; legal width (i8), so the G_TRUNC handler replaces the destination with the
|
||||
; masking G_AND. The sign-sensitive width record must survive that replacement
|
||||
; so the widened i8 compare still gets its shl/ashr sign extension.
|
||||
; CHECK: OpFunction
|
||||
; CHECK: %[[#XT8:]] = OpFunctionParameter
|
||||
; CHECK: %[[#YT8:]] = OpFunctionParameter
|
||||
; CHECK: OpFunctionParameter
|
||||
; CHECK-DAG: %[[#ANDA_T8:]] = OpBitwiseAnd %[[#I8]] %[[#XT8]] {{%[0-9]+}}
|
||||
; CHECK-DAG: %[[#ANDB_T8:]] = OpBitwiseAnd %[[#I8]] %[[#YT8]] {{%[0-9]+}}
|
||||
; CHECK: %[[#SHLA_T8:]] = OpShiftLeftLogical %[[#I8]] %[[#ANDA_T8]] %[[#K4]]
|
||||
; CHECK: %[[#SXA_T8:]] = OpShiftRightArithmetic %[[#I8]] %[[#SHLA_T8]] %[[#K4]]
|
||||
; CHECK: %[[#SHLB_T8:]] = OpShiftLeftLogical %[[#I8]] %[[#ANDB_T8]] %[[#K4]]
|
||||
; CHECK: %[[#SXB_T8:]] = OpShiftRightArithmetic %[[#I8]] %[[#SHLB_T8]] %[[#K4]]
|
||||
; CHECK: OpSLessThan {{%[0-9]+}} %[[#SXA_T8]] %[[#SXB_T8]]
|
||||
define spir_kernel void @trunc_i8_to_i4_icmp_slt(i8 %a, i8 %b, ptr addrspace(1) %out) {
|
||||
%at = trunc i8 %a to i4
|
||||
%bt = trunc i8 %b to i4
|
||||
%c = icmp slt i4 %at, %bt
|
||||
%r = sext i1 %c to i8
|
||||
store i8 %r, ptr addrspace(1) %out
|
||||
ret void
|
||||
}
|
||||
|
||||
; ----------------------------------------------------------------------------
|
||||
; Negative test: unsigned compare must NOT emit sign-extension shifts.
|
||||
; CHECK: OpFunction
|
||||
|
|
|
|||
Loading…
Reference in a new issue