This is an archive of the discontinued LLVM Phabricator instance.

[AArch64] Fix a corner case in BitFeild select
ClosedPublic

Authored by weimingz on Nov 18 2015, 6:32 PM.

Details

Summary

When not useful bits, BitWidth becomes 0 and APInt will not be happy.

See https://llvm.org/bugs/show_bug.cgi?id=25571

We can just mark the operand as IMPLICIT_DEF is none bits of it is used.

Diff Detail

Event Timeline

weimingz updated this revision to Diff 40593.Nov 18 2015, 6:32 PM
weimingz retitled this revision from to [AArch64] Fix a corner case in BitFeild select.
weimingz updated this object.
weimingz added a reviewer: t.p.northover.
weimingz added a subscriber: llvm-commits.
mgrang added a subscriber: mgrang.Nov 18 2015, 10:29 PM

Please fix the typo in the commit title:

BitFeild ==> BitField
lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
1699

Comments should begin with an uppercase letter.

1700

Can we change this to if (!BitWidth) ?

test/CodeGen/AArch64/bitfield-pr25571.ll
2 ↗(On Diff #40593)

Space between ;RUN

jmolloy accepted this revision.Nov 19 2015, 12:47 AM
jmolloy added a reviewer: jmolloy.
jmolloy added a subscriber: jmolloy.

This LGTM, Thanks!

lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
1700

I don't agree with this, BitWidth is an integer, not a boolean. "== 0" expresses the intent better than !.

This revision is now accepted and ready to land.Nov 19 2015, 12:47 AM
gberry added a subscriber: gberry.Nov 19 2015, 7:41 AM

Hi Weiming,

I think your fix is correct, but if fixed differently it may lead to better code being generated. The reason isBitfieldDstMask ends up with a BitWidth of 0 is because isBitfieldInsertOpFromOr has computed that the Or node in question has 0 UsefulBits, which if I understand correctly, means it is dead and could be replaced with an UNDEF node, allowing the instructions feeding to potentially be removed.

weimingz added inline comments.Nov 19 2015, 11:50 AM
lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
2065

HI Geoff,

The NumberOfIgnoredHighBits is used here to check if we can remove the AND.
The current function
static bool isBitfieldInsertOpFromOr(SDNode *N, unsigned &Opc, SDValue &Dst,

SDValue &Src, unsigned &ImmR,
unsigned &ImmS, SelectionDAG *CurDAG)

always expects a BFM op if it returns true.

I tried putting code like
if (NumberOfIgnoredHighBits == 32) {

  Src = Dst;
}

But it doest make much difference.
mov w8, w0
bfi w8, w8, #8, #24
mov w9, w0
bfi w9, w8, #8, #24
mov w8, w0
bfi w8, w9, #8, #24
bfi w0, w8, #8, #24
lsl w0, w0, #8

gberry added inline comments.Nov 20 2015, 12:26 PM
lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
2065

I was thinking something more like the following diff, which will eliminate a mov and a bfi from the final code. It seems like if we're already computing the bit-liveness of the 'Or' we should take advantage of it. I'd like to hear someone else's opinion on whether it is worth the effort (since we clearly haven't seen many cases that would hit this or they would have crashed).

@@ -1974,7 +1974,8 @@ static bool isBitfieldPositioningOp(SelectionDAG *CurDAG, SDValue Op,
// f = Opc Opd0, Opd1, LSB, MSB ; where Opc is a BFM, LSB = imm, and MSB = imm2
static bool isBitfieldInsertOpFromOr(SDNode *N, unsigned &Opc, SDValue &Dst,

SDValue &Src, unsigned &ImmR,
  • unsigned &ImmS, SelectionDAG *CurDAG) {

+ unsigned &ImmS, SelectionDAG *CurDAG,
+ const APInt &UsefulBits) {

assert(N->getOpcode() == ISD::OR && "Expect a OR operation");
 
// Set Opc

@@ -1988,9 +1989,6 @@ static bool isBitfieldInsertOpFromOr(SDNode *N, unsigned &Opc, SDValue &Dst,

// Because of simplify-demanded-bits in DAGCombine, involved masks may not
// have the expected shape. Try to undo that.
  • APInt UsefulBits;
  • getUsefulBits(SDValue(N, 0), UsefulBits); - unsigned NumberOfIgnoredLowBits = UsefulBits.countTrailingZeros(); unsigned NumberOfIgnoredHighBits = UsefulBits.countLeadingZeros();

@@ -2083,11 +2081,17 @@ SDNode *AArch64DAGToDAGISel::SelectBitfieldInsertOp(SDNode *N) {

unsigned Opc;
unsigned LSB, MSB;
SDValue Opd0, Opd1;

+ EVT VT = N->getValueType(0);

  • if (!isBitfieldInsertOpFromOr(N, Opc, Opd0, Opd1, LSB, MSB, CurDAG))

+ APInt NUsefulBits;
+ getUsefulBits(SDValue(N, 0), NUsefulBits);
+ if (!NUsefulBits)
+ return CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, VT);
+
+ if (!isBitfieldInsertOpFromOr(N, Opc, Opd0, Opd1, LSB, MSB, CurDAG,
+ NUsefulBits))

return nullptr;
  • EVT VT = N->getValueType(0); SDLoc dl(N); SDValue Ops[] = { Opd0, Opd1,
test/CodeGen/AArch64/bitfield-pr25571.ll
4 ↗(On Diff #40593)

You can get rid of the datalayout and triple lines (just pass the triple via a -mtriple= command line flag on the run line). You may also want to consider adding this test to another pre-existing test file (perhaps bitfield-insert.ll?).

7 ↗(On Diff #40593)

Add a ':' after test to avoid false matches.

11 ↗(On Diff #40593)

Maybe check for an lsl at the end as well?

12 ↗(On Diff #40593)

This comment should be: 0 0 0 A

weimingz updated this revision to Diff 40975.Nov 23 2015, 2:11 PM
weimingz updated this object.
weimingz edited edge metadata.

Hi Geoff,

Very appreciate! I think you're right. And it can save a BFI instruction.

This change looks good to me (but that's not too suprising, since it's pretty much the change I suggested). I would like to hear from Tim or James on whether they think this small added code complexity is worth it (as opposed to just going with the original fix).

This still looks OK to me.

weimingz closed this revision.Dec 1 2015, 11:20 AM