[LLVMdev] Convert the result of a vector comparison into a scalar bit mask?

Jeff Bush jeffbush001 at gmail.com
Tue Jul 2 09:12:10 PDT 2013

On Sun, Jun 30, 2013 at 11:14 PM, Jeff Bush <jeffbush001 at gmail.com> wrote:
> When LLVM does a comparison of two vectors, in this case with 16
> elements, the returned type of setcc is v16i1. The architecture I'm
> targeting allows storing the result of a vector comparison as a bit
> mask in a scalar register, but I'm having trouble converting the
> result of setcc into a value that is usable there.  For example, if I
> try to AND together masks that are the results of two comparisons, it
> can't select an instruction because the operand types are v16i1 and no
> instructions can deal with that. I don't want to have to modify every
> instruction to be aware of v16i1 as a data type (which doesn't seem
> right anyway).  Ideally, I could just tell the backend to treat the
> result of a vector setcc as an i32. I've tried a number of things,
> including:
> - Using setOperationAction for SETCC to Promote and set the Promote
> type to i32.  It asserts internally because it tries to do a sext
> operation on the result, which is incompatible.
> - Using a custom lowering action to wrap the setcc in a combination of
> BITCAST/ZERO_EXTEND nodes (which I could match and eliminate in the
> instruction pattern).  However those DAG nodes get removed during one
> of the passes and I the result type is still v16i1

After some thought, I realize that the second approach doesn't work
because the operation would be applied to each element in the vector
(thus the result is still a vector). There doesn't appear a promotion
type that will pack a vector.

I tried adding a lowering that will transform SETCC into into a custom
node that returns a scalar:

VectorProcTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const
    return DAG.getNode(SPISD::VECTOR_COMPARE, Op.getDebugLoc(),
MVT::i32, Op.getOperand(0),
        Op.getOperand(1), Op.getOperand(2));

def veccmp : SDNode<"SPISD::VECTOR_COMPARE", SDTypeProfile<1, 1, [SDTCisInt<0>,
    SDTCisSameAs<1, 2>, SDTCisVec<1>]>>;

And changing the pattern that matches vector comparisions to:

  [(set i32:$dst, (veccmp v16i32:$a, v16i32:$b, condition))]

Unfortunately, this ends up tripping an assert:

Assertion failed: (Op.getValueType().getScalarType().getSizeInBits()
== BitWidth && "Mask size mismatches value type size!"), function
SimplifyDemandedBits, file
llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp, line 357.

(another variant of this would be to keep the setcc and wrap it with a
custom node 'PACK_VECTOR' that takes v16i1 as a param and returns i32
as a result).

I'm not sure if I'm on the right track with this approach or not.

Since I'm exposing this with a built-in in clang anyway (since there
is no other way to do in C this that I know of), I could just punt
entirely and use an intrinsic to expose packed vector comparisons.
But that doesn't seem like the right thing to do.

More information about the llvm-dev mailing list