Open regehr opened 3 months ago
@llvm/issue-subscribers-backend-aarch64
Author: John Regehr (regehr)
Hi,
The combiner does something strange I don't understand. Maybe related to poison value and select.
# *** IR Dump After IRTranslator (irtranslator) ***:
# Machine code for function f: IsSSA, TracksLiveness
Function Live Ins: $w0, $w1
bb.1 (%ir-block.2):
liveins: $w0, $w1
%0:_(s32) = COPY $w0
%1:_(s32) = COPY $w1
%4:_(s1) = G_CONSTANT i1 false
%6:_(s32) = G_CONSTANT i32 0
%9:_(s32) = G_CONSTANT i32 1
%2:_(s32) = G_SUB %1:_, %0:_
%3:_(s32) = nsw G_SUB %1:_, %0:_
%5:_(s32) = G_SELECT %4:_(s1), %3:_, %2:_
%7:_(s1) = G_ICMP intpred(sgt), %5:_(s32), %6:_
%8:_(s32) = G_SELECT %7:_(s1), %6:_, %9:_
$w0 = COPY %8:_(s32)
RET_ReallyLR implicit $w0
# End machine code for function f.
The combiner does something very fishy:
Try combining %5:_(s32) = G_SELECT %4:_(s1), %3:_, %2:_
10: GIM_SwitchOpcode(MIs[0], [19, 274), Default=6760, JumpTable...) // Got=142
3921: Begin try-block
3928: GIM_CheckSimplePredicate(Predicate=51)
3932: GIM_CheckCxxPredicate(MIs[0], Predicate=23)
3935: GIR_CustomAction(FnID=15)
Erasing: %5:_(s32) = G_SELECT %4:_(s1), %3:_, %2:_
Changing: %7:_(s1) = G_ICMP intpred(sgt), %5:_(s32), %6:_
Changed: %7:_(s1) = G_ICMP intpred(sgt), %3:_(s32), %6:_
3936: GIR_Done
When swapping the operands in select
with the following %5 = select i1 false, i32 %3, i32 %4
that's %4
that's the first operand which is selected:
# *** IR Dump After IRTranslator (irtranslator) ***:
# Machine code for function f: IsSSA, TracksLiveness
Function Live Ins: $w0, $w1
bb.1 (%ir-block.2):
liveins: $w0, $w1
%0:_(s32) = COPY $w0
%1:_(s32) = COPY $w1
%4:_(s1) = G_CONSTANT i1 false
%6:_(s32) = G_CONSTANT i32 0
%9:_(s32) = G_CONSTANT i32 1
%2:_(s32) = G_SUB %1:_, %0:_
%3:_(s32) = nsw G_SUB %1:_, %0:_
%5:_(s32) = G_SELECT %4:_(s1), %2:_, %3:_
%7:_(s1) = G_ICMP intpred(sgt), %5:_(s32), %6:_
%8:_(s32) = G_SELECT %7:_(s1), %6:_, %9:_
$w0 = COPY %8:_(s32)
RET_ReallyLR implicit $w0
# End machine code for function f.
[...]
Try combining %5:_(s32) = G_SELECT %4:_(s1), %2:_, %3:_
10: GIM_SwitchOpcode(MIs[0], [19, 274), Default=6760, JumpTable...) // Got=142
3921: Begin try-block
3928: GIM_CheckSimplePredicate(Predicate=51)
3932: GIM_CheckCxxPredicate(MIs[0], Predicate=23)
3935: GIR_CustomAction(FnID=15)
Erasing: %5:_(s32) = G_SELECT %4:_(s1), %2:_, %3:_
Changing: %7:_(s1) = G_ICMP intpred(sgt), %5:_(s32), %6:_
Changed: %7:_(s1) = G_ICMP intpred(sgt), %2:_(s32), %6:_
Now, if we remove nosw
, we can see that the G_SELECT
is changed before the erase:
Changing: %5:_(s32) = G_SELECT %4:_(s1), %3:_, %2:_
CSEInfo::Recording new MI %5:_(s32) = G_SELECT %4:_(s1), %3:_, %2:_
Changed: %5:_(s32) = G_SELECT %4:_(s1), %2:_, %2:_
CSEInfo::Recording new MI %5:_(s32) = G_SELECT %4:_(s1), %2:_, %2:_
1046: GIR_Done
select false
to already be normalised and takes the first operand. The changing combine pattern does not set both operands to the second one as there is a poison value for one of them.I think I've got the reason. It seems the two subs are seen as equivalent (ie ~= select false, A, A
) which makes the instruction match the select_same_val
pattern in Combine.td
. cf CodeGen/GlobalISel/CombinerHelper.cpp matchSelectSameVal
and matchEqualDefs
. Beneath it uses produceSameValue(...) -> MachineInstr::isIdentical
. The code is at:
I don't know if it is a fault as marking one as nsw
could also imply the other one as nsw
. BUT swapping the two operands produce different outputs, so in this sense the two should not be seen as equivalent.
From a brief scan of isDenticalTo
, it looks as if it ignores flags.
here's a function:
using this driver:
it should print 0, and this is what happens with the sdag backend, but using the global isel backend it prints 1.
for the given inputs,
%4
is poison. the poison is blocked by the subsequent select but it seems like this is confusing the backend somehow, since llvm-reduce was unable to remove the poison-producing operation and the subsequent select.cc @hatsunespica