mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-25 21:00:00 +00:00
Add Thumb2 movcc instructions.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74946 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
35bd43da76
commit
e253c951b3
@ -1031,7 +1031,6 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
return NULL;
|
||||
}
|
||||
case ARMISD::CMOV: {
|
||||
bool isThumb = Subtarget->isThumb();
|
||||
MVT VT = Op.getValueType();
|
||||
SDValue N0 = Op.getOperand(0);
|
||||
SDValue N1 = Op.getOperand(1);
|
||||
@ -1041,39 +1040,68 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
assert(N2.getOpcode() == ISD::Constant);
|
||||
assert(N3.getOpcode() == ISD::Register);
|
||||
|
||||
// Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
|
||||
// Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
|
||||
// Pattern complexity = 18 cost = 1 size = 0
|
||||
SDValue CPTmp0;
|
||||
SDValue CPTmp1;
|
||||
SDValue CPTmp2;
|
||||
if (!isThumb && VT == MVT::i32 &&
|
||||
SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) {
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(), ARM::MOVCCs, MVT::i32, Ops, 7);
|
||||
}
|
||||
if (!Subtarget->isThumb1Only() && VT == MVT::i32) {
|
||||
// Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
|
||||
// Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
|
||||
// Pattern complexity = 18 cost = 1 size = 0
|
||||
SDValue CPTmp0;
|
||||
SDValue CPTmp1;
|
||||
SDValue CPTmp2;
|
||||
if (Subtarget->isThumb()) {
|
||||
if (SelectT2ShifterOperandReg(Op, N1, CPTmp0, CPTmp1)) {
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, CPTmp0, CPTmp1, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(),
|
||||
ARM::t2MOVCCs, MVT::i32,Ops, 6);
|
||||
}
|
||||
} else {
|
||||
if (SelectShifterOperandReg(Op, N1, CPTmp0, CPTmp1, CPTmp2)) {
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, CPTmp0, CPTmp1, CPTmp2, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(),
|
||||
ARM::MOVCCs, MVT::i32, Ops, 7);
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern: (ARMcmov:i32 GPR:i32:$false,
|
||||
// (imm:i32)<<P:Predicate_so_imm>><<X:so_imm_XFORM>>:$true,
|
||||
// (imm:i32):$cc)
|
||||
// Emits: (MOVCCi:i32 GPR:i32:$false,
|
||||
// (so_imm_XFORM:i32 (imm:i32):$true), (imm:i32):$cc)
|
||||
// Pattern complexity = 10 cost = 1 size = 0
|
||||
if (VT == MVT::i32 &&
|
||||
N3.getOpcode() == ISD::Constant &&
|
||||
Predicate_so_imm(N3.getNode())) {
|
||||
SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N1)->getZExtValue()),
|
||||
MVT::i32);
|
||||
Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode());
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(), ARM::MOVCCi, MVT::i32, Ops, 5);
|
||||
// Pattern: (ARMcmov:i32 GPR:i32:$false,
|
||||
// (imm:i32)<<P:Predicate_so_imm>><<X:so_imm_XFORM>>:$true,
|
||||
// (imm:i32):$cc)
|
||||
// Emits: (MOVCCi:i32 GPR:i32:$false,
|
||||
// (so_imm_XFORM:i32 (imm:i32):$true), (imm:i32):$cc)
|
||||
// Pattern complexity = 10 cost = 1 size = 0
|
||||
if (N3.getOpcode() == ISD::Constant) {
|
||||
if (Subtarget->isThumb()) {
|
||||
if (Predicate_t2_so_imm(N3.getNode())) {
|
||||
SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N1)->getZExtValue()),
|
||||
MVT::i32);
|
||||
Tmp1 = Transform_t2_so_imm_XFORM(Tmp1.getNode());
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(),
|
||||
ARM::t2MOVCCi, MVT::i32, Ops, 5);
|
||||
}
|
||||
} else {
|
||||
if (Predicate_so_imm(N3.getNode())) {
|
||||
SDValue Tmp1 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N1)->getZExtValue()),
|
||||
MVT::i32);
|
||||
Tmp1 = Transform_so_imm_XFORM(Tmp1.getNode());
|
||||
SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
|
||||
cast<ConstantSDNode>(N2)->getZExtValue()),
|
||||
MVT::i32);
|
||||
SDValue Ops[] = { N0, Tmp1, Tmp2, N3, InFlag };
|
||||
return CurDAG->SelectNodeTo(Op.getNode(),
|
||||
ARM::MOVCCi, MVT::i32, Ops, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc)
|
||||
@ -1094,7 +1122,9 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||
default: assert(false && "Illegal conditional move type!");
|
||||
break;
|
||||
case MVT::i32:
|
||||
Opc = isThumb ? ARM::tMOVCCr : ARM::MOVCCr;
|
||||
Opc = Subtarget->isThumb()
|
||||
? (Subtarget->hasThumb2() ? ARM::t2MOVCCr : ARM::tMOVCCr)
|
||||
: ARM::MOVCCr;
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = ARM::FCPYScc;
|
||||
|
@ -1028,7 +1028,24 @@ defm t2TEQ : T2I_cmp_is<"teq",
|
||||
// Short range conditional branch. Looks awesome for loops. Need to figure
|
||||
// out how to use this one.
|
||||
|
||||
// FIXME: Conditional moves
|
||||
|
||||
// Conditional moves
|
||||
// FIXME: should be able to write a pattern for ARMcmov, but can't use
|
||||
// a two-value operand where a dag node expects two operands. :(
|
||||
def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true),
|
||||
"mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">;
|
||||
|
||||
def t2MOVCCs : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_reg:$true),
|
||||
"mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">;
|
||||
|
||||
def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true),
|
||||
"mov", " $dst, $true",
|
||||
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
|
||||
RegConstraint<"$false = $dst">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Control-Flow Instructions
|
||||
|
48
test/CodeGen/Thumb2/thumb2-select.ll
Normal file
48
test/CodeGen/Thumb2/thumb2-select.ll
Normal file
@ -0,0 +1,48 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep moveq | count 1
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movgt | count 1
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movlt | count 1
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movle | count 1
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movls | count 1
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep movhi | count 1
|
||||
|
||||
define i32 @f1(i32 %a.s) {
|
||||
entry:
|
||||
%tmp = icmp eq i32 %a.s, 4
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
||||
|
||||
define i32 @f2(i32 %a.s) {
|
||||
entry:
|
||||
%tmp = icmp sgt i32 %a.s, 4
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
||||
|
||||
define i32 @f3(i32 %a.s, i32 %b.s) {
|
||||
entry:
|
||||
%tmp = icmp slt i32 %a.s, %b.s
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
||||
|
||||
define i32 @f4(i32 %a.s, i32 %b.s) {
|
||||
entry:
|
||||
%tmp = icmp sle i32 %a.s, %b.s
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
||||
|
||||
define i32 @f5(i32 %a.u, i32 %b.u) {
|
||||
entry:
|
||||
%tmp = icmp ule i32 %a.u, %b.u
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
||||
|
||||
define i32 @f6(i32 %a.u, i32 %b.u) {
|
||||
entry:
|
||||
%tmp = icmp ugt i32 %a.u, %b.u
|
||||
%tmp1.s = select i1 %tmp, i32 2, i32 3
|
||||
ret i32 %tmp1.s
|
||||
}
|
23
test/CodeGen/Thumb2/thumb2-select_xform.ll
Normal file
23
test/CodeGen/Thumb2/thumb2-select_xform.ll
Normal file
@ -0,0 +1,23 @@
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov | count 3
|
||||
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mvn | count 1
|
||||
|
||||
define i32 @t1(i32 %a, i32 %b, i32 %c) nounwind {
|
||||
%tmp1 = icmp sgt i32 %c, 10
|
||||
%tmp2 = select i1 %tmp1, i32 0, i32 2147483647
|
||||
%tmp3 = add i32 %tmp2, %b
|
||||
ret i32 %tmp3
|
||||
}
|
||||
|
||||
define i32 @t2(i32 %a, i32 %b, i32 %c) nounwind {
|
||||
%tmp1 = icmp sgt i32 %c, 10
|
||||
%tmp2 = select i1 %tmp1, i32 0, i32 2147483648
|
||||
%tmp3 = add i32 %tmp2, %b
|
||||
ret i32 %tmp3
|
||||
}
|
||||
|
||||
define i32 @t3(i32 %a, i32 %b, i32 %c, i32 %d) nounwind {
|
||||
%tmp1 = icmp sgt i32 %c, 10
|
||||
%tmp2 = select i1 %tmp1, i32 0, i32 10
|
||||
%tmp3 = sub i32 %b, %tmp2
|
||||
ret i32 %tmp3
|
||||
}
|
Loading…
Reference in New Issue
Block a user