Skip to content

Commit

Permalink
[mips][msa] Added support for matching bmnz, bmnzi, bmz, and bmzi fro…
Browse files Browse the repository at this point in the history
…m normal IR (i.e. not intrinsics)

Also corrected the definition of the intrinsics for these instructions (the
result register is also the first operand), and added intrinsics for bsel and
bseli to clang (they already existed in the backend).

These four operations are mostly equivalent to bsel, and bseli (the difference
is which operand is tied to the result). As a result some of the tests changed
as described below.

bitwise.ll:
- bsel.v test adapted so that the mask is unknown at compile-time. This stops
  it emitting bmnzi.b instead of the intended bsel.v.
- The bseli.b test now tests the right thing. Namely the case when one of the
  values is an uimm8, rather than when the condition is a uimm8 (which is
  covered by bmnzi.b)

compare.ll:
- bsel.v tests now (correctly) emits bmnz.v instead of bsel.v because this
  is the same operation (see MSA.txt).

i8.ll
- CHECK-DAG-ized test.
- bmzi.b test now (correctly) emits equivalent bmnzi.b with swapped operands
  because this is the same operation (see MSA.txt).
- bseli.b still emits bseli.b though because the immediate makes it
  distinguishable from bmnzi.b.

vec.ll:
- CHECK-DAG-ized test.
- bmz.v tests now (correctly) emits bmnz.v with swapped operands (see
  MSA.txt).
- bsel.v tests now (correctly) emits bmnz.v with swapped operands (see
  MSA.txt).



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193693 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dsandersllvm committed Oct 30, 2013
1 parent f853a03 commit c385709
Show file tree
Hide file tree
Showing 8 changed files with 471 additions and 176 deletions.
12 changes: 8 additions & 4 deletions include/llvm/IR/IntrinsicsMips.td
Original file line number Diff line number Diff line change
Expand Up @@ -610,16 +610,20 @@ def int_mips_binsri_d : GCCBuiltin<"__builtin_msa_binsri_d">,
[IntrNoMem]>;

def int_mips_bmnz_v : GCCBuiltin<"__builtin_msa_bmnz_v">,
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>;
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty],
[IntrNoMem]>;

def int_mips_bmnzi_b : GCCBuiltin<"__builtin_msa_bmnzi_b">,
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_i32_ty], [IntrNoMem]>;
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty],
[IntrNoMem]>;

def int_mips_bmz_v : GCCBuiltin<"__builtin_msa_bmz_v">,
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>;
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty],
[IntrNoMem]>;

def int_mips_bmzi_b : GCCBuiltin<"__builtin_msa_bmzi_b">,
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_i32_ty], [IntrNoMem]>;
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty],
[IntrNoMem]>;

def int_mips_bneg_b : GCCBuiltin<"__builtin_msa_bneg_b">,
Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>;
Expand Down
17 changes: 17 additions & 0 deletions lib/Target/Mips/MSA.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,20 @@ binsri.[bhwd], binsli.[bhwd]:
appropriate.
Furthermore, the compiler may use bsel.[bhwd] for some masks that do
not survive the legalization process (this is a bug and will be fixed).

bmnz.v, bmz.v, bsel.v:
These three operations differ only in the operand that is tied to the
result.
It is (currently) not possible to emit bmz.v, or bsel.v since bmnz.v is
the same operation and will be emitted instead.
In future, the compiler may choose between these three instructions
according to register allocation.

bmnzi.b, bmzi.b:
Like their non-immediate counterparts, bmnzi.v and bmzi.v are the same
operation with the operands swapped. bmnzi.v will (currently) be emitted
for both cases.

bseli.v:
Unlike the non-immediate versions, bseli.v is distinguishable from
bmnzi.b and bmzi.b and can be emitted.
49 changes: 44 additions & 5 deletions lib/Target/Mips/MipsMSAInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1538,14 +1538,53 @@ class BINSRI_H_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.h", v8i16, MSA128HOpnd>;
class BINSRI_W_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.w", v4i32, MSA128WOpnd>;
class BINSRI_D_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.d", v2i64, MSA128DOpnd>;

class BMNZ_V_DESC : MSA_VEC_DESC_BASE<"bmnz.v", int_mips_bmnz_v, MSA128BOpnd>;
class BMNZ_V_DESC {
dag OutOperandList = (outs MSA128BOpnd:$wd);
dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws,
MSA128BOpnd:$wt);
string AsmString = "bmnz.v\t$wd, $ws, $wt";
list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt,
MSA128BOpnd:$ws,
MSA128BOpnd:$wd_in))];
InstrItinClass Itinerary = NoItinerary;
string Constraints = "$wd = $wd_in";
}

class BMNZI_B_DESC : MSA_I8_X_DESC_BASE<"bmnzi.b", int_mips_bmnzi_b,
MSA128BOpnd>;
class BMNZI_B_DESC {
dag OutOperandList = (outs MSA128BOpnd:$wd);
dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws,
vsplat_uimm8:$u8);
string AsmString = "bmnzi.b\t$wd, $ws, $u8";
list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8,
MSA128BOpnd:$ws,
MSA128BOpnd:$wd_in))];
InstrItinClass Itinerary = NoItinerary;
string Constraints = "$wd = $wd_in";
}

class BMZ_V_DESC : MSA_VEC_DESC_BASE<"bmz.v", int_mips_bmz_v, MSA128BOpnd>;
class BMZ_V_DESC {
dag OutOperandList = (outs MSA128BOpnd:$wd);
dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws,
MSA128BOpnd:$wt);
string AsmString = "bmz.v\t$wd, $ws, $wt";
list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt,
MSA128BOpnd:$wd_in,
MSA128BOpnd:$ws))];
InstrItinClass Itinerary = NoItinerary;
string Constraints = "$wd = $wd_in";
}

class BMZI_B_DESC : MSA_I8_X_DESC_BASE<"bmzi.b", int_mips_bmzi_b, MSA128BOpnd>;
class BMZI_B_DESC {
dag OutOperandList = (outs MSA128BOpnd:$wd);
dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws,
vsplat_uimm8:$u8);
string AsmString = "bmzi.b\t$wd, $ws, $u8";
list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8,
MSA128BOpnd:$wd_in,
MSA128BOpnd:$ws))];
InstrItinClass Itinerary = NoItinerary;
string Constraints = "$wd = $wd_in";
}

class BNEG_B_DESC : MSA_3R_DESC_BASE<"bneg.b", int_mips_bneg_b, MSA128BOpnd>;
class BNEG_H_DESC : MSA_3R_DESC_BASE<"bneg.h", int_mips_bneg_h, MSA128HOpnd>;
Expand Down
108 changes: 103 additions & 5 deletions lib/Target/Mips/MipsSEISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,44 @@ static bool isVSplat(SDValue N, APInt &Imm, bool IsLittleEndian) {
return true;
}

// Test whether the given node is an all-ones build_vector.
static bool isVectorAllOnes(SDValue N) {
// Look through bitcasts. Endianness doesn't matter because we are looking
// for an all-ones value.
if (N->getOpcode() == ISD::BITCAST)
N = N->getOperand(0);

BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N);

if (!BVN)
return false;

APInt SplatValue, SplatUndef;
unsigned SplatBitSize;
bool HasAnyUndefs;

// Endianness doesn't matter in this context because we are looking for
// an all-ones value.
if (BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs))
return SplatValue.isAllOnesValue();

return false;
}

// Test whether N is the bitwise inverse of OfNode.
static bool isBitwiseInverse(SDValue N, SDValue OfNode) {
if (N->getOpcode() != ISD::XOR)
return false;

if (isVectorAllOnes(N->getOperand(0)))
return N->getOperand(1) == OfNode;

if (isVectorAllOnes(N->getOperand(1)))
return N->getOperand(0) == OfNode;

return false;
}

// Perform combines where ISD::OR is the root node.
//
// Performs the following transformations:
Expand Down Expand Up @@ -544,6 +582,7 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
bool IsLittleEndian = !Subtarget->isLittle();

SDValue IfSet, IfClr, Cond;
bool IsConstantMask = false;
APInt Mask, InvMask;

// If Op0Op0 is an appropriate mask, try to find it's inverse in either
Expand All @@ -558,6 +597,8 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
IfClr = Op1Op1;
else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && Mask == ~InvMask)
IfClr = Op1Op0;

IsConstantMask = true;
}

// If IfClr is not yet set, and Op0Op1 is an appropriate mask, try the same
Expand All @@ -571,6 +612,47 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
IfClr = Op1Op1;
else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && Mask == ~InvMask)
IfClr = Op1Op0;

IsConstantMask = true;
}

// If IfClr is not yet set, try looking for a non-constant match.
// IfClr will be set if we find a valid match amongst the eight
// possibilities.
if (!IfClr.getNode()) {
if (isBitwiseInverse(Op0Op0, Op1Op0)) {
Cond = Op1Op0;
IfSet = Op1Op1;
IfClr = Op0Op1;
} else if (isBitwiseInverse(Op0Op1, Op1Op0)) {
Cond = Op1Op0;
IfSet = Op1Op1;
IfClr = Op0Op0;
} else if (isBitwiseInverse(Op0Op0, Op1Op1)) {
Cond = Op1Op1;
IfSet = Op1Op0;
IfClr = Op0Op1;
} else if (isBitwiseInverse(Op0Op1, Op1Op1)) {
Cond = Op1Op1;
IfSet = Op1Op0;
IfClr = Op0Op0;
} else if (isBitwiseInverse(Op1Op0, Op0Op0)) {
Cond = Op0Op0;
IfSet = Op0Op1;
IfClr = Op1Op1;
} else if (isBitwiseInverse(Op1Op1, Op0Op0)) {
Cond = Op0Op0;
IfSet = Op0Op1;
IfClr = Op1Op0;
} else if (isBitwiseInverse(Op1Op0, Op0Op1)) {
Cond = Op0Op1;
IfSet = Op0Op0;
IfClr = Op1Op1;
} else if (isBitwiseInverse(Op1Op1, Op0Op1)) {
Cond = Op0Op1;
IfSet = Op0Op0;
IfClr = Op1Op0;
}
}

// At this point, IfClr will be set if we have a valid match.
Expand All @@ -580,10 +662,12 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
assert(Cond.getNode() && IfSet.getNode());

// Fold degenerate cases.
if (Mask.isAllOnesValue())
return IfSet;
else if (Mask == 0)
return IfClr;
if (IsConstantMask) {
if (Mask.isAllOnesValue())
return IfSet;
else if (Mask == 0)
return IfClr;
}

// Transform the DAG into an equivalent VSELECT.
return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfClr, IfSet);
Expand Down Expand Up @@ -1284,6 +1368,20 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
DAG.getConstant(Mask, VecTy, true), Op->getOperand(1),
Op->getOperand(2));
}
case Intrinsic::mips_bmnz_v:
return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3),
Op->getOperand(2), Op->getOperand(1));
case Intrinsic::mips_bmnzi_b:
return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
lowerMSASplatImm(Op, 3, DAG), Op->getOperand(2),
Op->getOperand(1));
case Intrinsic::mips_bmz_v:
return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3),
Op->getOperand(1), Op->getOperand(2));
case Intrinsic::mips_bmzi_b:
return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
lowerMSASplatImm(Op, 3, DAG), Op->getOperand(1),
Op->getOperand(2));
case Intrinsic::mips_bnz_b:
case Intrinsic::mips_bnz_h:
case Intrinsic::mips_bnz_w:
Expand Down Expand Up @@ -1872,7 +1970,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_VOID(SDValue Op,
/// true.
static bool isSplatVector(const BuildVectorSDNode *N) {
unsigned int nOps = N->getNumOperands();
assert(nOps > 1 && "isSplat has 0 or 1 sized build vector");
assert(nOps > 1 && "isSplatVector has 0 or 1 sized build vector");

SDValue Operand0 = N->getOperand(0);

Expand Down
51 changes: 39 additions & 12 deletions test/CodeGen/Mips/msa/bitwise.ll
Original file line number Diff line number Diff line change
Expand Up @@ -972,29 +972,56 @@ define void @ctlz_v2i64(<2 x i64>* %c, <2 x i64>* %a) nounwind {
; CHECK: .size ctlz_v2i64
}

define void @bsel_v16i8(<16 x i8>* %c, <16 x i8>* %a, <16 x i8>* %b) nounwind {
define void @bsel_v16i8(<16 x i8>* %c, <16 x i8>* %a, <16 x i8>* %b, <16 x i8>* %m) nounwind {
; CHECK: bsel_v16i8:

%1 = load <16 x i8>* %a
; CHECK-DAG: ld.b [[R1:\$w[0-9]+]], 0($5)
%2 = load <16 x i8>* %b
; CHECK-DAG: ld.b [[R2:\$w[0-9]+]], 0($6)
%3 = and <16 x i8> %1, <i8 6, i8 6, i8 6, i8 6, i8 6, i8 6, i8 6, i8 6,
i8 6, i8 6, i8 6, i8 6, i8 6, i8 6, i8 6, i8 6>
%4 = and <16 x i8> %2, <i8 249, i8 249, i8 249, i8 249,
i8 249, i8 249, i8 249, i8 249,
i8 249, i8 249, i8 249, i8 249,
i8 249, i8 249, i8 249, i8 249>
%5 = or <16 x i8> %3, %4
; CHECK-DAG: ldi.b [[R3:\$w[0-9]+]], 6
; CHECK-DAG: bsel.v [[R3]], [[R2]], [[R1]]
store <16 x i8> %5, <16 x i8>* %c
; CHECK-DAG: st.b [[R3]], 0($4)
%3 = load <16 x i8>* %m
; CHECK-DAG: ld.b [[R3:\$w[0-9]+]], 0($7)
%4 = xor <16 x i8> %3, <i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1>
%5 = and <16 x i8> %1, %3
%6 = and <16 x i8> %2, %4
%7 = or <16 x i8> %5, %6
; bmnz is the same operation
; CHECK-DAG: bmnz.v [[R1]], [[R2]], [[R3]]
store <16 x i8> %7, <16 x i8>* %c
; CHECK-DAG: st.b [[R1]], 0($4)

ret void
; CHECK: .size bsel_v16i8
}

define void @bsel_v16i8_i(<16 x i8>* %c, <16 x i8>* %a, <16 x i8>* %m) nounwind {
; CHECK: bsel_v16i8_i:

%1 = load <16 x i8>* %a
; CHECK-DAG: ld.b [[R1:\$w[0-9]+]], 0($5)
%2 = load <16 x i8>* %m
; CHECK-DAG: ld.b [[R3:\$w[0-9]+]], 0($6)
%3 = xor <16 x i8> %2, <i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1,
i8 -1, i8 -1, i8 -1, i8 -1>
%4 = and <16 x i8> %1, %3
%5 = and <16 x i8> <i8 6, i8 6, i8 6, i8 6,
i8 6, i8 6, i8 6, i8 6,
i8 6, i8 6, i8 6, i8 6,
i8 6, i8 6, i8 6, i8 6>, %2
%6 = or <16 x i8> %4, %5
; CHECK-DAG: bseli.b [[R3]], [[R1]], 6
store <16 x i8> %6, <16 x i8>* %c
; CHECK-DAG: st.b [[R3]], 0($4)

ret void
; CHECK: .size bsel_v16i8_i
}

define void @bsel_v8i16(<8 x i16>* %c, <8 x i16>* %a, <8 x i16>* %b) nounwind {
; CHECK: bsel_v8i16:

Expand Down
10 changes: 6 additions & 4 deletions test/CodeGen/Mips/msa/compare.ll
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,10 @@ define void @bsel_s_v16i8(<16 x i8>* %d, <16 x i8>* %a, <16 x i8>* %b,
%4 = icmp sgt <16 x i8> %1, %2
; CHECK-DAG: clt_s.b [[R4:\$w[0-9]+]], [[R2]], [[R1]]
%5 = select <16 x i1> %4, <16 x i8> %1, <16 x i8> %3
; CHECK-DAG: bsel.v [[R4]], [[R1]], [[R3]]
; bmnz.v is the same operation
; CHECK-DAG: bmnz.v [[R3]], [[R1]], [[R4]]
store <16 x i8> %5, <16 x i8>* %d
; CHECK-DAG: st.b [[R4]], 0($4)
; CHECK-DAG: st.b [[R3]], 0($4)

ret void
; CHECK: .size bsel_s_v16i8
Expand Down Expand Up @@ -737,9 +738,10 @@ define void @bsel_u_v16i8(<16 x i8>* %d, <16 x i8>* %a, <16 x i8>* %b,
%4 = icmp ugt <16 x i8> %1, %2
; CHECK-DAG: clt_u.b [[R4:\$w[0-9]+]], [[R2]], [[R1]]
%5 = select <16 x i1> %4, <16 x i8> %1, <16 x i8> %3
; CHECK-DAG: bsel.v [[R4]], [[R1]], [[R3]]
; bmnz.v is the same operation
; CHECK-DAG: bmnz.v [[R3]], [[R1]], [[R4]]
store <16 x i8> %5, <16 x i8>* %d
; CHECK-DAG: st.b [[R4]], 0($4)
; CHECK-DAG: st.b [[R3]], 0($4)

ret void
; CHECK: .size bsel_u_v16i8
Expand Down
Loading

0 comments on commit c385709

Please sign in to comment.