bitwise AND selector node not commutative?

Using the Thumb-2 target we see that ORN ( a | ^b) and BIC (a & ^b) have similar patterns, as we would expect:

defm t2BIC : T2I_bin_irs<“bic”, BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
defm t2ORN : T2I_bin_irs<“orn”, BinOpFrag<(or node:$LHS, (not node:$RHS))>>;

Compiling the following three works as expected:

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %a, %tmp1 → orn r0, r0, r1

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %tmp1, %a → orn r0, r0, r1

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %a, %tmp → bic r0, r0, r1

But this doesn’t:

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %tmp, %a → eor r1, r1, #4294967295 ; and r0, r1, r0

On the surface it seems that the selector is not commuting the AND operands. I’ve attached the complete test files. I can take a look but I need a pointer to get started.

David

RM_20_BIC.ll (364 Bytes)

RM_112_ORN.ll (366 Bytes)

Using the Thumb-2 target we see that ORN ( a | ^b) and BIC (a & ^b) have similar patterns, as we would expect:

defm t2BIC : T2I_bin_irs<“bic”, BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
defm t2ORN : T2I_bin_irs<“orn”, BinOpFrag<(or node:$LHS, (not node:$RHS))>>;

Compiling the following three works as expected:

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %a, %tmp1 → orn r0, r0, r1

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %tmp1, %a → orn r0, r0, r1

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %a, %tmp → bic r0, r0, r1

But this doesn’t:

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %tmp, %a → eor r1, r1, #4294967295 ; and r0, r1, r0

On the surface it seems that the selector is not commuting the AND operands. I’ve attached the complete test files. I can take a look but I need a pointer to get started.

No, isel is trying to commute the AND. See ARMGenDAGISel.inc (auto-generated by tablegen):

// Pattern: (and:i32 GPR:i32:$lhs, (xor:i32 t2_so_reg:i32:$rhs, (imm:i32)<<P:Predicate_immAllOnes>>))
// Emits: (t2BICrs:i32 GPR:i32:$lhs, t2_so_reg:i32:$rhs)
// Pattern complexity = 19 cost = 1 size = 0
{

}

// Pattern: (and:i32 (xor:i32 t2_so_reg:i32:$rhs, (imm:i32)<<P:Predicate_immAllOnes>>), GPR:i32:$lhs)
// Emits: (t2BICrs:i32 GPR:i32:$lhs, t2_so_reg:i32:$rhs)
// Pattern complexity = 19 cost = 1 size = 0
{

}

The second one is the commuted version. Looks like the issue is in SelectThumb2ShifterOperandReg.

Evan

Using the Thumb-2 target we see that ORN ( a | ^b) and BIC (a & ^b) have similar patterns, as we would expect:

defm t2BIC : T2I_bin_irs<“bic”, BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
defm t2ORN : T2I_bin_irs<“orn”, BinOpFrag<(or node:$LHS, (not node:$RHS))>>;

Compiling the following three works as expected:

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %a, %tmp1 → orn r0, r0, r1

%tmp1 = xor i32 4294967295, %b ; %tmp2 = or i32 %tmp1, %a → orn r0, r0, r1

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %a, %tmp → bic r0, r0, r1

But this doesn’t:

%tmp = xor i32 %b, 4294967295 ; %tmp1 = and i32 %tmp, %a → eor r1, r1, #4294967295 ; and r0, r1, r0

On the surface it seems that the selector is not commuting the AND operands. I’ve attached the complete test files. I can take a look but I need a pointer to get started.

No, isel is trying to commute the AND. See ARMGenDAGISel.inc (auto-generated by tablegen):

// Pattern: (and:i32 GPR:i32:$lhs, (xor:i32 t2_so_reg:i32:$rhs, (imm:i32)<<P:Predicate_immAllOnes>>))
// Emits: (t2BICrs:i32 GPR:i32:$lhs, t2_so_reg:i32:$rhs)
// Pattern complexity = 19 cost = 1 size = 0
{

}

// Pattern: (and:i32 (xor:i32 t2_so_reg:i32:$rhs, (imm:i32)<<P:Predicate_immAllOnes>>), GPR:i32:$lhs)
// Emits: (t2BICrs:i32 GPR:i32:$lhs, t2_so_reg:i32:$rhs)
// Pattern complexity = 19 cost = 1 size = 0
{

}

The second one is the commuted version. Looks like the issue is in SelectThumb2ShifterOperandReg.

Ugh. It should try to match t2BICrr. But someone tblgen is not generating the commuted version. Very strange. I’m take a look.

Evan

Fixed.

Evan