i1 true ^= -1 in DAG matcher?

Hello,

It looks like that in the DAG matcher, the DAG has a xor with ‘-1’ for checking a true value vector

for instance,

%cmp4.i = icmp ne <8 x i32> %6, %5
%7 = xor <8 x i1> %cmp4.i, <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>

[use of %7]

results in vector of ‘-1’ in the DAG. This also seems the reason why LLVM’s vnot PatFrag doesn’t match in this case. I’ve also found from third_party/llvm/llvm-project/llvm/lib/Target/AMDGPU/SIInstructions.td:

// FIXME: The generated DAG matcher seems to have strange behavior
// with a 1-bit literal to match, so use a -1 for checking a true
// 1-bit value.

Which seems to reflect the same observation. Is this a bug or a feature?

Thanks in advance for any explanation

Hi Hendrik,

It looks like that in the DAG matcher, the DAG has a xor with '-1' for checking a true value vector

for instance,

%cmp4.i = icmp ne <8 x i32> %6, %5
%7 = xor <8 x i1> %cmp4.i, <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>
[use of %7]

results in vector of '-1' in the DAG.

This should be controlled by TargetLowering::setBooleanVectorContents,
which lets each target choose whether a boolean is 0/1 or 0/-1 when
held in a larger register. For AMDGPU it looks like R600 wants 0/-1,
but SIL wants 0/1 so if you're seeing -1 when compiling for a SIL
target that's probably a bug.

Cheers.

Tim.

The vnot PatFrag uses ImmAllOnesV which should put an OPC_CheckImmAllOnesV in the matcher table. And the matcher table should call ISD::isBuildVectorAllOnes. I believe we use vnot with vXi1 vectors on X86 and I haven’t seen any issues.

The FIXME you pointed to seems related to a scalar patcher not a vector pattern. In that case the issue is that the immediate matcher for scalars calls getSExtValue on a 1-bit APInt which will return -1 in an int64_t.

Yes the cited FIXME code might be unrelated. I do think there is some kind of issue somewhere because I do see a BUILD_VECTOR of i1 -1 on our target which I set to setBooleanVectorContents(ZeroOrOneBooleanContent). The backend is not open source, but the i1 vector is an input to a clang builtin which takes V8i like
__builtin_special(~mask) where mask is an vector of i1 form a setne (cmp), and the vector of i1 -1 is from the ~ that does an xor of those two vectors. I would have expected a vector of 1, not -1. I would love to send in a better open source reproducer, will try to construct one.

A constant i1 is stored as a one bit APInt wrapped in a ConstantInt which is then wrapped in ConstantSDNode for SelectionDAG. The BUILD_VECTOR will just point to the same ConstantSDNode for each element. There is no concept of a sign in the storage. It’s just a bit. Whether or not its treated as 1 or negative 1 is going to depend on the code looking at the value including printing code. And nothing in the printing code knows about setBooleanVectorContents so it can’t make any decisions about how to print it either. I believe SelectionDAGDumper just calls APInt::operator<<(raw_ostream &) which defaults to printing signed.

Ok, interesting. The reason why this came up in the first place is that a ‘vnot’ pattern did not seem to match, neither does a (xor R:$m, (vNi1 (Splat 1))). But a (xor R:$m, (vNi1 (Splat -1))) does.

Are you llvm trunk or an older version?

Pretty much trunk