Commit 4a5e6d05 by John Porto

Subzero. ARM32. Implements bool folding.

parent 57586f73
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "IceGlobalInits.h" #include "IceGlobalInits.h"
#include "IceInstARM32.def" #include "IceInstARM32.def"
#include "IceInstARM32.h" #include "IceInstARM32.h"
#include "IceInstVarIter.h"
#include "IceLiveness.h" #include "IceLiveness.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IcePhiLoweringImpl.h" #include "IcePhiLoweringImpl.h"
...@@ -1803,22 +1804,46 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) { ...@@ -1803,22 +1804,46 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) {
} }
} }
void TargetARM32::lowerBr(const InstBr *Inst) { void TargetARM32::lowerBr(const InstBr *Instr) {
if (Inst->isUnconditional()) { if (Instr->isUnconditional()) {
_br(Inst->getTargetUnconditional()); _br(Instr->getTargetUnconditional());
return; return;
} }
Operand *Cond = Inst->getCondition(); Operand *Cond = Instr->getCondition();
// TODO(jvoung): Handle folding opportunities.
CondARM32::Cond BrCondTrue0 = CondARM32::NE;
CondARM32::Cond BrCondTrue1 = CondARM32::kNone;
CondARM32::Cond BrCondFalse = CondARM32::kNone;
if (!_mov_i1_to_flags(Cond, &BrCondTrue0, &BrCondTrue1, &BrCondFalse)) {
// "Cond" was not fold.
Type Ty = Cond->getType(); Type Ty = Cond->getType();
Variable *Src0R = legalizeToReg(Cond); Variable *Src0R = legalizeToReg(Cond);
assert(Ty == IceType_i1); assert(Ty == IceType_i1);
if (Ty != IceType_i32) if (Ty != IceType_i32)
_uxt(Src0R, Src0R); _uxt(Src0R, Src0R);
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *_0 = Ctx->getConstantZero(IceType_i32);
_cmp(Src0R, Zero); _cmp(Src0R, _0);
_br(Inst->getTargetTrue(), Inst->getTargetFalse(), CondARM32::NE); BrCondTrue0 = CondARM32::NE;
}
if (BrCondTrue1 != CondARM32::kNone) {
_br(Instr->getTargetTrue(), BrCondTrue1);
}
if (BrCondTrue0 == CondARM32::kNone) {
assert(BrCondTrue1 == CondARM32::kNone);
_br(Instr->getTargetFalse());
return;
}
if (BrCondTrue0 == CondARM32::AL) {
assert(BrCondTrue1 == CondARM32::kNone);
assert(BrCondFalse == CondARM32::kNone);
_br(Instr->getTargetTrue());
return;
}
_br(Instr->getTargetTrue(), Instr->getTargetFalse(), BrCondTrue0);
} }
void TargetARM32::lowerCall(const InstCall *Instr) { void TargetARM32::lowerCall(const InstCall *Instr) {
...@@ -2050,13 +2075,22 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2050,13 +2075,22 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
if (Src0->getType() == IceType_i32) { if (Src0->getType() == IceType_i32) {
Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex); Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
_mov(T_Lo, Src0RF); _mov(T_Lo, Src0RF);
} else if (Src0->getType() == IceType_i1) { } else if (Src0->getType() != IceType_i1) {
Variable *Src0R = legalizeToReg(Src0); Variable *Src0R = legalizeToReg(Src0);
_lsl(T_Lo, Src0R, ShiftAmt); _sxt(T_Lo, Src0R);
_asr(T_Lo, T_Lo, ShiftAmt); } else {
CondARM32::Cond CondTrue0, CondTrue1, CondFalse;
if (_mov_i1_to_flags(Src0, &CondTrue0, &CondTrue1, &CondFalse)) {
// Handle bool folding.
Constant *_0 = Ctx->getConstantZero(IceType_i32);
Operand *_m1 =
legalize(Ctx->getConstantInt32(-1), Legal_Reg | Legal_Flex);
_cmov(T_Lo, _m1, CondTrue0, CondTrue1, _0, CondFalse);
} else { } else {
Variable *Src0R = legalizeToReg(Src0); Variable *Src0R = legalizeToReg(Src0);
_sxt(T_Lo, Src0R); _lsl(T_Lo, Src0R, ShiftAmt);
_asr(T_Lo, T_Lo, ShiftAmt);
}
} }
_mov(DestLo, T_Lo); _mov(DestLo, T_Lo);
Variable *T_Hi = makeReg(DestHi->getType()); Variable *T_Hi = makeReg(DestHi->getType());
...@@ -2068,22 +2102,31 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2068,22 +2102,31 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
_mov(T_Hi, T_Lo); _mov(T_Hi, T_Lo);
} }
_mov(DestHi, T_Hi); _mov(DestHi, T_Hi);
} else if (Src0->getType() == IceType_i1) { } else if (Src0->getType() != IceType_i1) {
// t1 = sxt src; dst = t1
Variable *Src0R = legalizeToReg(Src0);
Variable *T = makeReg(Dest->getType());
_sxt(T, Src0R);
_mov(Dest, T);
} else {
Variable *T = makeReg(Dest->getType());
CondARM32::Cond CondTrue0, CondTrue1, CondFalse;
if (_mov_i1_to_flags(Src0, &CondTrue0, &CondTrue1, &CondFalse)) {
// Handle bool folding.
Constant *_0 = Ctx->getConstantZero(IceType_i32);
Operand *_m1 =
legalize(Ctx->getConstantInt32(-1), Legal_Reg | Legal_Flex);
_cmov(T, _m1, CondTrue0, CondTrue1, _0, CondFalse);
} else {
// GPR registers are 32-bit, so just use 31 as dst_bitwidth - 1. // GPR registers are 32-bit, so just use 31 as dst_bitwidth - 1.
// lsl t1, src_reg, 31 // lsl t1, src_reg, 31
// asr t1, t1, 31 // asr t1, t1, 31
// dst = t1 // dst = t1
Variable *Src0R = legalizeToReg(Src0); Variable *Src0R = legalizeToReg(Src0);
Constant *ShiftAmt = Ctx->getConstantInt32(31); Constant *ShiftAmt = Ctx->getConstantInt32(31);
Variable *T = makeReg(Dest->getType());
_lsl(T, Src0R, ShiftAmt); _lsl(T, Src0R, ShiftAmt);
_asr(T, T, ShiftAmt); _asr(T, T, ShiftAmt);
_mov(Dest, T); }
} else {
// t1 = sxt src; dst = t1
Variable *Src0R = legalizeToReg(Src0);
Variable *T = makeReg(Dest->getType());
_sxt(T, Src0R);
_mov(Dest, T); _mov(Dest, T);
} }
break; break;
...@@ -2096,10 +2139,23 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2096,10 +2139,23 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
} else if (Dest->getType() == IceType_i64) { } else if (Dest->getType() == IceType_i64) {
// t1=uxtb src; dst.lo=t1; dst.hi=0 // t1=uxtb src; dst.lo=t1; dst.hi=0
Constant *Zero = Ctx->getConstantZero(IceType_i32); Constant *_0 = Ctx->getConstantZero(IceType_i32);
Constant *_1 = Ctx->getConstantInt32(1);
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Variable *T_Lo = makeReg(DestLo->getType()); Variable *T_Lo = makeReg(DestLo->getType());
CondARM32::Cond CondTrue0, CondTrue1, CondFalse;
if (_mov_i1_to_flags(Src0, &CondTrue0, &CondTrue1, &CondFalse)) {
// Handle folding opportunities.
Variable *T_Hi = makeReg(DestLo->getType());
_mov(T_Hi, _0);
_mov(DestHi, T_Hi);
_cmov(T_Lo, _1, CondTrue0, CondTrue1, _0, CondFalse);
_mov(DestLo, T_Lo);
return;
}
// i32 and i1 can just take up the whole register. i32 doesn't need uxt, // i32 and i1 can just take up the whole register. i32 doesn't need uxt,
// while i1 will have an and mask later anyway. // while i1 will have an and mask later anyway.
if (Src0->getType() == IceType_i32 || Src0->getType() == IceType_i1) { if (Src0->getType() == IceType_i32 || Src0->getType() == IceType_i1) {
...@@ -2115,18 +2171,28 @@ void TargetARM32::lowerCast(const InstCast *Inst) { ...@@ -2115,18 +2171,28 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
} }
_mov(DestLo, T_Lo); _mov(DestLo, T_Lo);
Variable *T_Hi = makeReg(DestLo->getType()); Variable *T_Hi = makeReg(DestLo->getType());
_mov(T_Hi, Zero); _mov(T_Hi, _0);
_mov(DestHi, T_Hi); _mov(DestHi, T_Hi);
} else if (Src0->getType() == IceType_i1) { } else if (Src0->getType() == IceType_i1) {
Constant *_1 = Ctx->getConstantInt32(1);
Variable *T = makeReg(Dest->getType());
CondARM32::Cond CondTrue0, CondTrue1, CondFalse;
if (_mov_i1_to_flags(Src0, &CondTrue0, &CondTrue1, &CondFalse)) {
// Handle folding opportunities.
Constant *_0 = Ctx->getConstantZero(IceType_i32);
_cmov(T, _1, CondTrue0, CondTrue1, _0, CondFalse);
_mov(Dest, T);
return;
}
// t = Src0; t &= 1; Dest = t // t = Src0; t &= 1; Dest = t
Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex); Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
Constant *One = Ctx->getConstantInt32(1);
Variable *T = makeReg(Dest->getType());
// Just use _mov instead of _uxt since all registers are 32-bit. _uxt // Just use _mov instead of _uxt since all registers are 32-bit. _uxt
// requires the source to be a register so could have required a _mov // requires the source to be a register so could have required a _mov
// from legalize anyway. // from legalize anyway.
_mov(T, Src0RF); _mov(T, Src0RF);
_and(T, T, One); _and(T, T, _1);
_mov(Dest, T); _mov(Dest, T);
} else { } else {
// t1 = uxt src; dst = t1 // t1 = uxt src; dst = t1
...@@ -2397,8 +2463,37 @@ struct { ...@@ -2397,8 +2463,37 @@ struct {
}; };
} // end of anonymous namespace } // end of anonymous namespace
void TargetARM32::lowerFcmp(const InstFcmp *Inst) { void TargetARM32::lowerFcmpCond(const InstFcmp *Instr,
Variable *Dest = Inst->getDest(); CondARM32::Cond *CondIfTrue0,
CondARM32::Cond *CondIfTrue1,
CondARM32::Cond *CondIfFalse) {
InstFcmp::FCond Condition = Instr->getCondition();
switch (Condition) {
case InstFcmp::False:
*CondIfFalse = CondARM32::AL;
*CondIfTrue0 = *CondIfTrue1 = CondARM32::kNone;
break;
case InstFcmp::True:
*CondIfFalse = *CondIfTrue1 = CondARM32::kNone;
*CondIfTrue0 = CondARM32::AL;
break;
default: {
Variable *Src0R = legalizeToReg(Instr->getSrc(0));
Variable *Src1R = legalizeToReg(Instr->getSrc(1));
_vcmp(Src0R, Src1R);
_vmrs();
assert(Condition < llvm::array_lengthof(TableFcmp));
*CondIfTrue0 = TableFcmp[Condition].CC0;
*CondIfTrue1 = TableFcmp[Condition].CC1;
*CondIfFalse = (*CondIfTrue1 != CondARM32::kNone)
? CondARM32::AL
: InstARM32::getOppositeCondition(*CondIfTrue0);
}
}
}
void TargetARM32::lowerFcmp(const InstFcmp *Instr) {
Variable *Dest = Instr->getDest();
if (isVectorType(Dest->getType())) { if (isVectorType(Dest->getType())) {
Variable *T = makeReg(Dest->getType()); Variable *T = makeReg(Dest->getType());
Context.insert(InstFakeDef::create(Func, T)); Context.insert(InstFakeDef::create(Func, T));
...@@ -2407,48 +2502,43 @@ void TargetARM32::lowerFcmp(const InstFcmp *Inst) { ...@@ -2407,48 +2502,43 @@ void TargetARM32::lowerFcmp(const InstFcmp *Inst) {
return; return;
} }
Variable *Src0R = legalizeToReg(Inst->getSrc(0));
Variable *Src1R = legalizeToReg(Inst->getSrc(1));
Variable *T = makeReg(IceType_i32); Variable *T = makeReg(IceType_i32);
_vcmp(Src0R, Src1R); Operand *_1 = Ctx->getConstantInt32(1);
_mov(T, Ctx->getConstantZero(IceType_i32)); Operand *_0 = Ctx->getConstantZero(IceType_i32);
_vmrs();
Operand *One = Ctx->getConstantInt32(1); CondARM32::Cond CondIfTrue0, CondIfTrue1, CondIfFalse;
InstFcmp::FCond Condition = Inst->getCondition(); lowerFcmpCond(Instr, &CondIfTrue0, &CondIfTrue1, &CondIfFalse);
assert(Condition < llvm::array_lengthof(TableFcmp));
CondARM32::Cond CC0 = TableFcmp[Condition].CC0; bool RedefineT = false;
CondARM32::Cond CC1 = TableFcmp[Condition].CC1; if (CondIfFalse != CondARM32::kNone) {
if (CC0 != CondARM32::kNone) { assert(!RedefineT);
_mov(T, One, CC0); _mov(T, _0, CondIfFalse);
// If this mov is not a maybe mov, but an actual mov (i.e., CC0 == AL), we RedefineT = true;
// don't want to _set_dest_redefined so that liveness + dead-code }
// elimination will get rid of the previous assignment (i.e., T = 0) above.
// TODO(stichnot,jpp): We should be able to conditionally create the "T=0" if (CondIfTrue0 != CondARM32::kNone) {
// instruction based on CC0, instead of relying on DCE to remove it. if (RedefineT) {
if (CC0 != CondARM32::AL) _mov_redefined(T, _1, CondIfTrue0);
_set_dest_redefined(); } else {
_mov(T, _1, CondIfTrue0);
}
RedefineT = true;
} }
if (CC1 != CondARM32::kNone) {
assert(CC0 != CondARM32::kNone); if (CondIfTrue1 != CondARM32::kNone) {
assert(CC1 != CondARM32::AL); assert(RedefineT);
_mov_redefined(T, One, CC1); _mov_redefined(T, _1, CondIfTrue1);
} }
_mov(Dest, T); _mov(Dest, T);
} }
void TargetARM32::lowerIcmp(const InstIcmp *Inst) { void TargetARM32::lowerIcmpCond(const InstIcmp *Inst,
Variable *Dest = Inst->getDest(); CondARM32::Cond *CondIfTrue,
CondARM32::Cond *CondIfFalse) {
Operand *Src0 = legalizeUndef(Inst->getSrc(0)); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Operand *Src1 = legalizeUndef(Inst->getSrc(1)); Operand *Src1 = legalizeUndef(Inst->getSrc(1));
if (isVectorType(Dest->getType())) {
Variable *T = makeReg(Dest->getType());
Context.insert(InstFakeDef::create(Func, T));
_mov(Dest, T);
UnimplementedError(Func->getContext()->getFlags());
return;
}
// a=icmp cond, b, c ==> // a=icmp cond, b, c ==>
// GCC does: // GCC does:
// cmp b.hi, c.hi or cmp b.lo, c.lo // cmp b.hi, c.hi or cmp b.lo, c.lo
...@@ -2478,8 +2568,7 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2478,8 +2568,7 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
// //
// So, we are going with the GCC version since it's usually better (except // So, we are going with the GCC version since it's usually better (except
// perhaps for eq/ne). We could revisit special-casing eq/ne later. // perhaps for eq/ne). We could revisit special-casing eq/ne later.
Constant *Zero = Ctx->getConstantZero(IceType_i32);
Constant *One = Ctx->getConstantInt32(1);
if (Src0->getType() == IceType_i64) { if (Src0->getType() == IceType_i64) {
InstIcmp::ICond Conditon = Inst->getCondition(); InstIcmp::ICond Conditon = Inst->getCondition();
size_t Index = static_cast<size_t>(Conditon); size_t Index = static_cast<size_t>(Conditon);
...@@ -2497,7 +2586,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2497,7 +2586,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
Src1LoRF = legalize(loOperand(Src1), Legal_Reg | Legal_Flex); Src1LoRF = legalize(loOperand(Src1), Legal_Reg | Legal_Flex);
Src1HiRF = legalize(hiOperand(Src1), Legal_Reg | Legal_Flex); Src1HiRF = legalize(hiOperand(Src1), Legal_Reg | Legal_Flex);
} }
Variable *T = makeReg(IceType_i32);
if (TableIcmp64[Index].IsSigned) { if (TableIcmp64[Index].IsSigned) {
Variable *ScratchReg = makeReg(IceType_i32); Variable *ScratchReg = makeReg(IceType_i32);
_cmp(Src0Lo, Src1LoRF); _cmp(Src0Lo, Src1LoRF);
...@@ -2509,9 +2597,8 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2509,9 +2597,8 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
_cmp(Src0Hi, Src1HiRF); _cmp(Src0Hi, Src1HiRF);
_cmp(Src0Lo, Src1LoRF, CondARM32::EQ); _cmp(Src0Lo, Src1LoRF, CondARM32::EQ);
} }
_mov(T, One, TableIcmp64[Index].C1); *CondIfTrue = TableIcmp64[Index].C1;
_mov_redefined(T, Zero, TableIcmp64[Index].C2); *CondIfFalse = TableIcmp64[Index].C2;
_mov(Dest, T);
return; return;
} }
...@@ -2548,7 +2635,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2548,7 +2635,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
assert(ShiftAmt >= 0); assert(ShiftAmt >= 0);
Constant *ShiftConst = nullptr; Constant *ShiftConst = nullptr;
Variable *Src0R = nullptr; Variable *Src0R = nullptr;
Variable *T = makeReg(IceType_i32);
if (ShiftAmt) { if (ShiftAmt) {
ShiftConst = Ctx->getConstantInt32(ShiftAmt); ShiftConst = Ctx->getConstantInt32(ShiftAmt);
Src0R = makeReg(IceType_i32); Src0R = makeReg(IceType_i32);
...@@ -2556,7 +2642,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2556,7 +2642,6 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
} else { } else {
Src0R = legalizeToReg(Src0); Src0R = legalizeToReg(Src0);
} }
_mov(T, Zero);
if (ShiftAmt) { if (ShiftAmt) {
Variable *Src1R = legalizeToReg(Src1); Variable *Src1R = legalizeToReg(Src1);
OperandARM32FlexReg *Src1RShifted = OperandARM32FlexReg::create( OperandARM32FlexReg *Src1RShifted = OperandARM32FlexReg::create(
...@@ -2566,8 +2651,32 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) { ...@@ -2566,8 +2651,32 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex); Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
_cmp(Src0R, Src1RF); _cmp(Src0R, Src1RF);
} }
_mov_redefined(T, One, getIcmp32Mapping(Inst->getCondition())); *CondIfTrue = getIcmp32Mapping(Inst->getCondition());
*CondIfFalse = InstARM32::getOppositeCondition(*CondIfTrue);
}
void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
Variable *Dest = Inst->getDest();
if (isVectorType(Dest->getType())) {
Variable *T = makeReg(Dest->getType());
Context.insert(InstFakeDef::create(Func, T));
_mov(Dest, T);
UnimplementedError(Func->getContext()->getFlags());
return;
}
Constant *_0 = Ctx->getConstantZero(IceType_i32);
Constant *_1 = Ctx->getConstantInt32(1);
Variable *T = makeReg(IceType_i32);
CondARM32::Cond CondIfTrue, CondIfFalse;
lowerIcmpCond(Inst, &CondIfTrue, &CondIfFalse);
_mov(T, _0, CondIfFalse);
_mov_redefined(T, _1, CondIfTrue);
_mov(Dest, T); _mov(Dest, T);
return; return;
} }
...@@ -3329,7 +3438,10 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { ...@@ -3329,7 +3438,10 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
return; return;
} }
// TODO(jvoung): handle folding opportunities.
CondARM32::Cond CondIfTrue0, CondIfTrue1, CondIfFalse;
if (!_mov_i1_to_flags(Condition, &CondIfTrue0, &CondIfTrue1, &CondIfFalse)) {
// "Condition" was not fold.
// cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t
Variable *CmpOpnd0 = legalizeToReg(Condition); Variable *CmpOpnd0 = legalizeToReg(Condition);
Type CmpOpnd0Ty = CmpOpnd0->getType(); Type CmpOpnd0Ty = CmpOpnd0->getType();
...@@ -3338,47 +3450,107 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) { ...@@ -3338,47 +3450,107 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
if (CmpOpnd0Ty != IceType_i32) if (CmpOpnd0Ty != IceType_i32)
_uxt(CmpOpnd0, CmpOpnd0); _uxt(CmpOpnd0, CmpOpnd0);
_cmp(CmpOpnd0, CmpOpnd1); _cmp(CmpOpnd0, CmpOpnd1);
static constexpr CondARM32::Cond Cond = CondARM32::NE; CondIfTrue0 = CondARM32::NE;
CondIfTrue1 = CondARM32::kNone;
CondIfFalse = CondARM32::EQ;
}
if (DestTy == IceType_i64) { if (DestTy == IceType_i64) {
SrcT = legalizeUndef(SrcT); SrcT = legalizeUndef(SrcT);
SrcF = legalizeUndef(SrcF); SrcF = legalizeUndef(SrcF);
// Set the low portion. // Set the low portion.
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex);
Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex); Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex);
Variable *TLo = makeReg(SrcFLo->getType()); Variable *TLo = makeReg(SrcFLo->getType());
_mov(TLo, SrcFLo); bool RedefineTLo = false;
Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex); if (CondIfFalse != CondARM32::kNone) {
_mov_redefined(TLo, SrcTLo, Cond); _mov(TLo, SrcFLo, CondIfFalse);
RedefineTLo = true;
}
if (CondIfTrue0 != CondARM32::kNone) {
if (!RedefineTLo)
_mov(TLo, SrcTLo, CondIfTrue0);
else
_mov_redefined(TLo, SrcTLo, CondIfTrue0);
RedefineTLo = true;
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(RedefineTLo);
_mov_redefined(TLo, SrcTLo, CondIfTrue1);
}
_mov(DestLo, TLo); _mov(DestLo, TLo);
// Set the high portion. // Set the high portion.
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex);
Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex); Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex);
Variable *THi = makeReg(SrcFHi->getType()); Variable *THi = makeReg(SrcFHi->getType());
_mov(THi, SrcFHi); bool RedefineTHi = false;
Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex); if (CondIfFalse != CondARM32::kNone) {
_mov_redefined(THi, SrcTHi, Cond); _mov(THi, SrcFHi, CondIfFalse);
RedefineTHi = true;
}
if (CondIfTrue0 != CondARM32::kNone) {
if (!RedefineTHi)
_mov(THi, SrcTHi, CondIfTrue0);
else
_mov_redefined(THi, SrcTHi, CondIfTrue0);
RedefineTHi = true;
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(RedefineTHi);
_mov_redefined(THi, SrcTHi, CondIfTrue1);
}
_mov(DestHi, THi); _mov(DestHi, THi);
return; return;
} }
if (isFloatingType(DestTy)) { if (isFloatingType(DestTy)) {
Variable *T = makeReg(DestTy); SrcT = legalizeToReg(SrcT);
SrcF = legalizeToReg(SrcF); SrcF = legalizeToReg(SrcF);
Variable *T = makeReg(DestTy);
assert(DestTy == SrcF->getType()); assert(DestTy == SrcF->getType());
_mov(T, SrcF); bool RedefineT = false;
SrcT = legalizeToReg(SrcT); if (CondIfFalse != CondARM32::kNone) {
_mov(T, SrcF, CondIfFalse);
RedefineT = true;
}
if (CondIfTrue0 != CondARM32::kNone) {
if (!RedefineT)
_mov(T, SrcT, CondIfTrue0);
else
_mov_redefined(T, SrcT, CondIfTrue0);
RedefineT = true;
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(RedefineT);
_mov_redefined(T, SrcT, CondIfTrue1);
}
assert(DestTy == SrcT->getType()); assert(DestTy == SrcT->getType());
_mov(T, SrcT, Cond);
_set_dest_redefined();
_mov(Dest, T); _mov(Dest, T);
return; return;
} }
SrcF = legalize(SrcF, Legal_Reg | Legal_Flex);
Variable *T = makeReg(SrcF->getType()); Variable *T = makeReg(SrcF->getType());
_mov(T, SrcF);
SrcT = legalize(SrcT, Legal_Reg | Legal_Flex); SrcT = legalize(SrcT, Legal_Reg | Legal_Flex);
_mov_redefined(T, SrcT, Cond); SrcF = legalize(SrcF, Legal_Reg | Legal_Flex);
bool RedefineT = false;
if (CondIfFalse != CondARM32::kNone) {
_mov(T, SrcF, CondIfFalse);
RedefineT = true;
}
if (CondIfTrue0 != CondARM32::kNone) {
if (!RedefineT)
_mov(T, SrcT, CondIfTrue0);
else
_mov_redefined(T, SrcT, CondIfTrue0);
RedefineT = true;
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(RedefineT);
_mov_redefined(T, SrcT, CondIfTrue1);
}
_mov(Dest, T); _mov(Dest, T);
} }
...@@ -3786,6 +3958,126 @@ void TargetARM32::emit(const ConstantUndef *) const { ...@@ -3786,6 +3958,126 @@ void TargetARM32::emit(const ConstantUndef *) const {
llvm::report_fatal_error("undef value encountered by emitter."); llvm::report_fatal_error("undef value encountered by emitter.");
} }
void TargetARM32::lowerTruncToFlags(Operand *Src, CondARM32::Cond *CondIfTrue,
CondARM32::Cond *CondIfFalse) {
Operand *_1 = Ctx->getConstantInt32(1);
Variable *SrcR =
legalizeToReg(Src->getType() == IceType_i64 ? loOperand(Src) : Src);
_tst(SrcR, _1);
*CondIfTrue = CondARM32::NE; // NE <-> APSR.Z == 0
*CondIfFalse = CondARM32::EQ; // EQ <-> APSR.Z == 1
}
bool TargetARM32::_mov_i1_to_flags(Operand *Boolean,
CondARM32::Cond *CondIfTrue0,
CondARM32::Cond *CondIfTrue1,
CondARM32::Cond *CondIfFalse) {
*CondIfTrue0 = CondARM32::kNone;
*CondIfTrue1 = CondARM32::kNone;
*CondIfFalse = CondARM32::AL;
bool FoldOK = false;
if (const Inst *Producer = BoolComputations.getProducerOf(Boolean)) {
if (const auto *IcmpProducer = llvm::dyn_cast<InstIcmp>(Producer)) {
lowerIcmpCond(IcmpProducer, CondIfTrue0, CondIfFalse);
FoldOK = true;
} else if (const auto *FcmpProducer = llvm::dyn_cast<InstFcmp>(Producer)) {
lowerFcmpCond(FcmpProducer, CondIfTrue0, CondIfTrue1, CondIfFalse);
FoldOK = true;
} else if (const auto *CastProducer = llvm::dyn_cast<InstCast>(Producer)) {
assert(CastProducer->getCastKind() == InstCast::Trunc);
lowerTruncToFlags(CastProducer->getSrc(0), CondIfTrue0, CondIfFalse);
FoldOK = true;
}
}
return FoldOK;
}
namespace {
namespace BoolFolding {
bool shouldTrackProducer(const Inst &Instr) {
switch (static_cast<uint32_t>(Instr.getKind())) {
case Inst::Icmp:
return true;
case Inst::Fcmp:
return true;
}
if (const auto *Cast = llvm::dyn_cast<InstCast>(&Instr)) {
switch (static_cast<uint32_t>(Cast->getCastKind())) {
case InstCast::Trunc:
return true;
}
}
return false;
}
bool isValidConsumer(const Inst &Instr) {
switch (static_cast<uint32_t>(Instr.getKind())) {
case Inst::Br:
return true;
case Inst::Select:
return !isVectorType(Instr.getDest()->getType());
}
if (const auto *Cast = llvm::dyn_cast<InstCast>(&Instr)) {
switch (static_cast<uint32_t>(Cast->getCastKind())) {
case InstCast::Sext:
return !isVectorType(Instr.getDest()->getType());
case InstCast::Zext:
return !isVectorType(Instr.getDest()->getType());
}
}
return false;
}
} // end of namespace BoolFolding
} // end of anonymous namespace
void TargetARM32::BoolComputationTracker::recordProducers(CfgNode *Node) {
for (Inst &Instr : Node->getInsts()) {
// Check whether Instr is a valid producer.
Variable *Dest = Instr.getDest();
if (!Instr.isDeleted() // only consider non-deleted instructions; and
&& Dest // only instructions with an actual dest var; and
&& Dest->getType() == IceType_i1 // only bool-type dest vars; and
&& BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr.
KnownComputations.emplace(Dest->getIndex(), BoolComputationEntry(&Instr));
}
// Check each src variable against the map.
FOREACH_VAR_IN_INST(Var, Instr) {
SizeT VarNum = Var->getIndex();
auto ComputationIter = KnownComputations.find(VarNum);
if (ComputationIter == KnownComputations.end()) {
continue;
}
if (IndexOfVarOperandInInst(Var) != 0 ||
!BoolFolding::isValidConsumer(Instr)) {
// All valid consumers use Var as the first source operand
KnownComputations.erase(VarNum);
continue;
}
if (Instr.isLastUse(Var)) {
ComputationIter->second.IsLiveOut = false;
}
}
}
for (auto Iter = KnownComputations.begin(), End = KnownComputations.end();
Iter != End;) {
// Disable the folding if its dest may be live beyond this block.
if (Iter->second.IsLiveOut) {
Iter = KnownComputations.erase(Iter);
continue;
}
// Mark as "dead" rather than outright deleting. This is so that other
// peephole style optimizations during or before lowering have access to
// this instruction in undeleted form. See for example
// tryOptimizedCmpxchgCmpBr().
Iter->second.Instr->setDead();
++Iter;
}
}
TargetDataARM32::TargetDataARM32(GlobalContext *Ctx) TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {} : TargetDataLowering(Ctx) {}
......
...@@ -58,6 +58,12 @@ public: ...@@ -58,6 +58,12 @@ public:
// TODO(jvoung): return a unique_ptr. // TODO(jvoung): return a unique_ptr.
static TargetARM32 *create(Cfg *Func) { return new TargetARM32(Func); } static TargetARM32 *create(Cfg *Func) { return new TargetARM32(Func); }
void initNodeForLowering(CfgNode *Node) override {
BoolComputations.forgetProducers();
BoolComputations.recordProducers(Node);
BoolComputations.dump(Func);
}
void translateOm1() override; void translateOm1() override;
void translateO2() override; void translateO2() override;
bool doBranchOpt(Inst *I, const CfgNode *NextNode) override; bool doBranchOpt(Inst *I, const CfgNode *NextNode) override;
...@@ -130,8 +136,13 @@ protected: ...@@ -130,8 +136,13 @@ protected:
void lowerCall(const InstCall *Inst) override; void lowerCall(const InstCall *Inst) override;
void lowerCast(const InstCast *Inst) override; void lowerCast(const InstCast *Inst) override;
void lowerExtractElement(const InstExtractElement *Inst) override; void lowerExtractElement(const InstExtractElement *Inst) override;
void lowerFcmp(const InstFcmp *Inst) override; void lowerFcmpCond(const InstFcmp *Instr, CondARM32::Cond *CondIfTrue0,
void lowerIcmp(const InstIcmp *Inst) override; CondARM32::Cond *CondIfTrue1,
CondARM32::Cond *CondIfFalse);
void lowerFcmp(const InstFcmp *Instr) override;
void lowerIcmpCond(const InstIcmp *Instr, CondARM32::Cond *CondIfTrue,
CondARM32::Cond *CondIfFalse);
void lowerIcmp(const InstIcmp *Instr) override;
void lowerAtomicRMW(Variable *Dest, uint32_t Operation, Operand *Ptr, void lowerAtomicRMW(Variable *Dest, uint32_t Operation, Operand *Ptr,
Operand *Val); Operand *Val);
void lowerIntrinsicCall(const InstIntrinsicCall *Inst) override; void lowerIntrinsicCall(const InstIntrinsicCall *Inst) override;
...@@ -316,6 +327,60 @@ protected: ...@@ -316,6 +327,60 @@ protected:
Context.insert(InstFakeDef::create(Func, Instr->getDestHi())); Context.insert(InstFakeDef::create(Func, Instr->getDestHi()));
} }
} }
// _mov_i1_to_flags is used for bool folding. If "Boolean" is folded, this
// method returns true, and sets "CondIfTrue0" and "CondIfTrue1" to the
// appropriate ARM condition codes. If "Boolean" is not to be folded, then this
// method returns false.
bool _mov_i1_to_flags(Operand *Boolean, CondARM32::Cond *CondIfTrue0,
CondARM32::Cond *CondIfTrue1,
CondARM32::Cond *CondIfFalse);
// _cmov is a pseudo instruction that is used for boolean folding. It emits
// code that moves "SrcIfTrue" to dest if either "CondIfTrue0" or
// "CondIfTrue1" holds, and "SrcIfFalse", if "CondIfFalse" holds. It requires
// "Dest" to be an infinite-weight temporary.
void _cmov(Variable *Dest, Operand *SrcIfTrue, CondARM32::Cond CondIfTrue0,
CondARM32::Cond CondIfTrue1, Operand *SrcIfFalse,
CondARM32::Cond CondIfFalse) {
assert(Dest->mustHaveReg());
if (CondIfFalse == CondARM32::kNone) {
assert(CondIfTrue0 == CondARM32::AL);
assert(CondIfTrue1 == CondARM32::kNone);
}
if (CondIfTrue0 == CondARM32::kNone) {
assert(CondIfFalse == CondARM32::AL);
assert(CondIfTrue1 == CondARM32::kNone);
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(CondIfFalse == CondARM32::AL);
assert(CondIfTrue1 != CondARM32::kNone);
}
bool RedefineT = false;
if (CondIfFalse != CondARM32::kNone) {
_mov(Dest, SrcIfFalse, CondIfFalse);
RedefineT = true;
}
if (CondIfTrue0 != CondARM32::kNone) {
if (RedefineT) {
_mov_redefined(Dest, SrcIfTrue, CondIfTrue0);
} else {
_mov(Dest, SrcIfTrue, CondIfTrue0);
}
RedefineT = true;
}
if (CondIfTrue1 != CondARM32::kNone) {
assert(RedefineT);
_mov_redefined(Dest, SrcIfTrue, CondIfTrue1);
}
}
/// The Operand can only be a 16-bit immediate or a ConstantRelocatable (with /// The Operand can only be a 16-bit immediate or a ConstantRelocatable (with
/// an upper16 relocation). /// an upper16 relocation).
void _movt(Variable *Dest, Operand *Src0, void _movt(Variable *Dest, Operand *Src0,
...@@ -542,6 +607,64 @@ protected: ...@@ -542,6 +607,64 @@ protected:
private: private:
~TargetARM32() override = default; ~TargetARM32() override = default;
void lowerTruncToFlags(Operand *Src, CondARM32::Cond *CondIfTrue,
CondARM32::Cond *CondIfFalse);
class BoolComputationTracker {
public:
BoolComputationTracker() = default;
~BoolComputationTracker() = default;
void forgetProducers() { KnownComputations.clear(); }
void recordProducers(CfgNode *Node);
const Inst *getProducerOf(const Operand *Opnd) const {
auto *Var = llvm::dyn_cast<Variable>(Opnd);
if (Var == nullptr) {
return nullptr;
}
auto Iter = KnownComputations.find(Var->getIndex());
if (Iter == KnownComputations.end()) {
return nullptr;
}
return Iter->second.Instr;
}
void dump(const Cfg *Func) const {
if (!BuildDefs::dump() || !Func->isVerbose(IceV_Folding))
return;
OstreamLocker L(Func->getContext());
Ostream &Str = Func->getContext()->getStrDump();
Str << "foldable producer:\n ";
for (const auto &Computation : KnownComputations) {
Str << " ";
Computation.second.Instr->dump(Func);
Str << "\n";
}
Str << "\n";
}
private:
class BoolComputationEntry {
public:
explicit BoolComputationEntry(Inst *I) : Instr(I) {}
Inst *const Instr;
// Boolean folding is disabled for variables whose live range is multi
// block. We conservatively initialize IsLiveOut to true, and set it to
// false once we find the end of the live range for the variable defined
// by this instruction. If liveness analysis is not performed (e.g., in
// Om1 mode) IsLiveOut will never be set to false, and folding will be
// disabled.
bool IsLiveOut = true;
};
using BoolComputationMap = std::unordered_map<SizeT, BoolComputationEntry>;
BoolComputationMap KnownComputations;
};
BoolComputationTracker BoolComputations;
}; };
class TargetDataARM32 final : public TargetDataLowering { class TargetDataARM32 final : public TargetDataLowering {
......
...@@ -53,40 +53,40 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) { ...@@ -53,40 +53,40 @@ define internal void @mult_fwd_branches(i32 %a, i32 %b) {
%cmp = icmp slt i32 %a, %b %cmp = icmp slt i32 %a, %b
; ASM-NEXT: ldr r0, [sp, #8] ; ASM-NEXT: ldr r0, [sp, #8]
; ASM-NEXT: mov r1, #0 ; ASM-NEXT: ldr r1, [sp, #4]
; ASM-NEXT: ldr r2, [sp, #4] ; ASM-NEXT: cmp r0, r1
; ASM-NEXT: cmp r0, r2 ; ASM-NEXT: movge r0, #0
; ASM-NEXT: movlt r1, #1 ; ASM-NEXT: movlt r0, #1
; ASM-NEXT: str r1, [sp] ; ASM-NEXT: str r0, [sp]
; DIS-NEXT: c: e59d0008 ; DIS-NEXT: c: e59d0008
; DIS-NEXT: 10: e3a01000 ; DIS-NEXT: 10: e59d1004
; DIS-NEXT: 14: e59d2004 ; DIS-NEXT: 14: e1500001
; DIS-NEXT: 18: e1500002 ; DIS-NEXT: 18: a3a00000
; DIS-NEXT: 1c: b3a01001 ; DIS-NEXT: 1c: b3a00001
; DIS-NEXT: 20: e58d1000 ; DIS-NEXT: 20: e58d0000
; IASM-NEXT: .byte 0x8 ; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; IASM-NEXT: mov r1, #0
; IASM-NEXT: .byte 0x4 ; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x20 ; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x9d ; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
; IASM-NEXT: .byte 0x2 ; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x50 ; IASM-NEXT: .byte 0x50
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
; IASM-NEXT: movlt r1, #1 ; IASM-NEXT: movge r0, #0
; IASM-NEXT: movlt r0, #1
; IASM-NEXT: .byte 0x0 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x10 ; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5 ; IASM-NEXT: .byte 0xe5
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
; RUN: --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix ARM32-O2 %s
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble --target arm32 \ ; RUN: --command %p2i --filetype=asm --assemble --disassemble --target arm32 \
; RUN: -i %s --args -Om1 --skip-unimplemented \ ; RUN: -i %s --args -Om1 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix ARM32-OM1 %s
@__init_array_start = internal constant [0 x i8] zeroinitializer, align 4 @__init_array_start = internal constant [0 x i8] zeroinitializer, align 4
@__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4 @__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4
...@@ -849,8 +849,11 @@ entry: ...@@ -849,8 +849,11 @@ entry:
; OPTM1-NOT: and eax,0x1 ; OPTM1-NOT: and eax,0x1
; ARM32-LABEL: trunc64To1 ; ARM32-LABEL: trunc64To1
; ARM32: and r0, r0, #1 ; ARM32-OM1: and r0, r0, #1
; ARM32: and r0, r0, #1 ; ARM32-OM1: and r0, r0, #1
; ARM32-O2: tst r0, #1
; ARM32-O2: moveq [[RES:r[0-9]+]], #0
; ARM32-O2: movne [[RES]], #1
define internal i64 @sext32To64(i32 %a) { define internal i64 @sext32To64(i32 %a) {
entry: entry:
...@@ -921,8 +924,12 @@ entry: ...@@ -921,8 +924,12 @@ entry:
; OPTM1: sar {{.*}},0x1f ; OPTM1: sar {{.*}},0x1f
; ARM32-LABEL: sext1To64 ; ARM32-LABEL: sext1To64
; ARM32: lsl {{.*}}, #31 ; ARM32-OM1: lsl {{.*}}, #31
; ARM32: asr {{.*}}, #31 ; ARM32-OM1: asr {{.*}}, #31
; ARM32-O2: tst r0, #1
; ARM32-O2: mvn [[M1:r[0-9]+]], #0
; ARM32-O2: moveq [[RES:r[0-9]+]], #0
; ARM32-O2: movne [[RES]], [[M1]]
define internal i64 @zext32To64(i32 %a) { define internal i64 @zext32To64(i32 %a) {
entry: entry:
...@@ -991,8 +998,11 @@ entry: ...@@ -991,8 +998,11 @@ entry:
; OPTM1: mov {{.*}},0x0 ; OPTM1: mov {{.*}},0x0
; ARM32-LABEL: zext1To64 ; ARM32-LABEL: zext1To64
; ARM32: and {{.*}}, #1 ; ARM32-OM1: and {{.*}}, #1
; ARM32: mov {{.*}}, #0 ; ARM32-OM1: mov {{.*}}, #0
; ARM32-O2: tst r0, #1
; ARM32-O2: moveq {{[^,]*}}, #0
; ARM32-O2: movne {{[^,]*}}, #1
define internal void @icmpEq64(i64 %a, i64 %b, i64 %c, i64 %d) { define internal void @icmpEq64(i64 %a, i64 %b, i64 %c, i64 %d) {
entry: entry:
...@@ -1051,13 +1061,17 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -1051,13 +1061,17 @@ if.end3: ; preds = %if.then2, %if.end
; ARM32-LABEL: icmpEq64 ; ARM32-LABEL: icmpEq64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: moveq ; ARM32-OM1: movne
; ARM32: movne ; ARM32-OM1: moveq
; ARM32-OM1: cmp
; ARM32-O2: bne
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: moveq ; ARM32-OM1: movne
; ARM32: movne ; ARM32-OM1: moveq
; ARM32-OM1: cmp
; ARM32-O2: bne
; ARM32: bl ; ARM32: bl
declare void @func() declare void @func()
...@@ -1119,13 +1133,17 @@ if.end3: ; preds = %if.end, %if.then2 ...@@ -1119,13 +1133,17 @@ if.end3: ; preds = %if.end, %if.then2
; ARM32-LABEL: icmpNe64 ; ARM32-LABEL: icmpNe64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movne ; ARM32-OM1: moveq
; ARM32: moveq ; ARM32-OM1: movne
; ARM32-OM1: cmp
; ARM32-O2: beq
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movne ; ARM32-OM1: moveq
; ARM32: moveq ; ARM32-OM1: movne
; ARM32-OM1: cmp
; ARM32-O2: beq
; ARM32: bl ; ARM32: bl
define internal void @icmpGt64(i64 %a, i64 %b, i64 %c, i64 %d) { define internal void @icmpGt64(i64 %a, i64 %b, i64 %c, i64 %d) {
...@@ -1171,13 +1189,17 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -1171,13 +1189,17 @@ if.end3: ; preds = %if.then2, %if.end
; ARM32-LABEL: icmpGt64 ; ARM32-LABEL: icmpGt64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movhi ; ARM32-OM1: movls
; ARM32: movls ; ARM32-OM1: movhi
; ARM32-OM1: cmp
; ARM32-O2: bls
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movlt ; ARM32-OM1: movge
; ARM32: movge ; ARM32-OM1: movlt
; ARM32-OM1: cmp
; ARM32-O2: bge
; ARM32: bl ; ARM32: bl
define internal void @icmpGe64(i64 %a, i64 %b, i64 %c, i64 %d) { define internal void @icmpGe64(i64 %a, i64 %b, i64 %c, i64 %d) {
...@@ -1223,13 +1245,17 @@ if.end3: ; preds = %if.end, %if.then2 ...@@ -1223,13 +1245,17 @@ if.end3: ; preds = %if.end, %if.then2
; ARM32-LABEL: icmpGe64 ; ARM32-LABEL: icmpGe64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcs ; ARM32-OM1: movcc
; ARM32: movcc ; ARM32-OM1: movcs
; ARM32-OM1: cmp
; ARM32-O2: bcc
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movge ; ARM32-OM1: movlt
; ARM32: movlt ; ARM32-OM1: movge
; ARM32-OM1: cmp
; ARM32-O2: blt
; ARM32: bl ; ARM32: bl
define internal void @icmpLt64(i64 %a, i64 %b, i64 %c, i64 %d) { define internal void @icmpLt64(i64 %a, i64 %b, i64 %c, i64 %d) {
...@@ -1275,13 +1301,17 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -1275,13 +1301,17 @@ if.end3: ; preds = %if.then2, %if.end
; ARM32-LABEL: icmpLt64 ; ARM32-LABEL: icmpLt64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcc ; ARM32-OM1: movcs
; ARM32: movcs ; ARM32-OM1: movcc
; ARM32-OM1: cmp
; ARM32-O2: bcs
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movlt ; ARM32-OM1: movge
; ARM32: movge ; ARM32-OM1: movlt
; ARM32-OM1: cmp
; ARM32-O2: bge
; ARM32: bl ; ARM32: bl
define internal void @icmpLe64(i64 %a, i64 %b, i64 %c, i64 %d) { define internal void @icmpLe64(i64 %a, i64 %b, i64 %c, i64 %d) {
...@@ -1327,13 +1357,16 @@ if.end3: ; preds = %if.end, %if.then2 ...@@ -1327,13 +1357,16 @@ if.end3: ; preds = %if.end, %if.then2
; ARM32-LABEL: icmpLe64 ; ARM32-LABEL: icmpLe64
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movls ; ARM32-OM1: movhi
; ARM32: movhi ; ARM32-OM1: movls
; ARM32-OM1: cmp
; ARM32-O2: bhi
; ARM32: bl ; ARM32: bl
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movge ; ARM32-OM1: movlt
; ARM32: movlt ; ARM32-OM1: movge
; ARM32-O2: blt
; ARM32: bl ; ARM32: bl
define internal i32 @icmpEq64Bool(i64 %a, i64 %b) { define internal i32 @icmpEq64Bool(i64 %a, i64 %b) {
...@@ -1351,8 +1384,8 @@ entry: ...@@ -1351,8 +1384,8 @@ entry:
; OPTM1: je ; OPTM1: je
; ARM32-LABEL: icmpEq64Bool ; ARM32-LABEL: icmpEq64Bool
; ARM32: moveq
; ARM32: movne ; ARM32: movne
; ARM32: moveq
define internal i32 @icmpNe64Bool(i64 %a, i64 %b) { define internal i32 @icmpNe64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1369,8 +1402,8 @@ entry: ...@@ -1369,8 +1402,8 @@ entry:
; OPTM1: jne ; OPTM1: jne
; ARM32-LABEL: icmpNe64Bool ; ARM32-LABEL: icmpNe64Bool
; ARM32: movne
; ARM32: moveq ; ARM32: moveq
; ARM32: movne
define internal i32 @icmpSgt64Bool(i64 %a, i64 %b) { define internal i32 @icmpSgt64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1395,8 +1428,8 @@ entry: ...@@ -1395,8 +1428,8 @@ entry:
; ARM32-LABEL: icmpSgt64Bool ; ARM32-LABEL: icmpSgt64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movlt
; ARM32: movge ; ARM32: movge
; ARM32: movlt
define internal i32 @icmpUgt64Bool(i64 %a, i64 %b) { define internal i32 @icmpUgt64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1421,8 +1454,8 @@ entry: ...@@ -1421,8 +1454,8 @@ entry:
; ARM32-LABEL: icmpUgt64Bool ; ARM32-LABEL: icmpUgt64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movhi
; ARM32: movls ; ARM32: movls
; ARM32: movhi
define internal i32 @icmpSge64Bool(i64 %a, i64 %b) { define internal i32 @icmpSge64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1447,8 +1480,8 @@ entry: ...@@ -1447,8 +1480,8 @@ entry:
; ARM32-LABEL: icmpSge64Bool ; ARM32-LABEL: icmpSge64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movge
; ARM32: movlt ; ARM32: movlt
; ARM32: movge
define internal i32 @icmpUge64Bool(i64 %a, i64 %b) { define internal i32 @icmpUge64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1473,8 +1506,8 @@ entry: ...@@ -1473,8 +1506,8 @@ entry:
; ARM32-LABEL: icmpUge64Bool ; ARM32-LABEL: icmpUge64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcs
; ARM32: movcc ; ARM32: movcc
; ARM32: movcs
define internal i32 @icmpSlt64Bool(i64 %a, i64 %b) { define internal i32 @icmpSlt64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1499,8 +1532,8 @@ entry: ...@@ -1499,8 +1532,8 @@ entry:
; ARM32-LABEL: icmpSlt64Bool ; ARM32-LABEL: icmpSlt64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movlt
; ARM32: movge ; ARM32: movge
; ARM32: movlt
define internal i32 @icmpUlt64Bool(i64 %a, i64 %b) { define internal i32 @icmpUlt64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1525,8 +1558,8 @@ entry: ...@@ -1525,8 +1558,8 @@ entry:
; ARM32-LABEL: icmpUlt64Bool ; ARM32-LABEL: icmpUlt64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcc
; ARM32: movcs ; ARM32: movcs
; ARM32: movcc
define internal i32 @icmpSle64Bool(i64 %a, i64 %b) { define internal i32 @icmpSle64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1551,8 +1584,8 @@ entry: ...@@ -1551,8 +1584,8 @@ entry:
; ARM32-LABEL: icmpSle64Bool ; ARM32-LABEL: icmpSle64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: sbcs ; ARM32: sbcs
; ARM32: movge
; ARM32: movlt ; ARM32: movlt
; ARM32: movge
define internal i32 @icmpUle64Bool(i64 %a, i64 %b) { define internal i32 @icmpUle64Bool(i64 %a, i64 %b) {
entry: entry:
...@@ -1577,8 +1610,8 @@ entry: ...@@ -1577,8 +1610,8 @@ entry:
; ARM32-LABEL: icmpUle64Bool ; ARM32-LABEL: icmpUle64Bool
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movls
; ARM32: movhi ; ARM32: movhi
; ARM32: movls
define internal i64 @load64(i32 %a) { define internal i64 @load64(i32 %a) {
entry: entry:
...@@ -1666,15 +1699,15 @@ entry: ...@@ -1666,15 +1699,15 @@ entry:
; OPTM1: cmovne ; OPTM1: cmovne
; ARM32-LABEL: select64VarVar ; ARM32-LABEL: select64VarVar
; The initial compare.
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcc ; ARM32-OM1: movcs
; ARM32: movcs ; ARM32-OM1: movcc
; The non-folded compare for the select. ; ARM32-OM1: cmp
; ARM32: cmp ; ARM32-OM1: movne
; ARM32: movne ; ARM32-O2: movcc
; ARM32: movne ; ARM32-OM1: movne
; ARM32-O2: movcc
define internal i64 @select64VarConst(i64 %a, i64 %b) { define internal i64 @select64VarConst(i64 %a, i64 %b) {
entry: entry:
...@@ -1703,15 +1736,17 @@ entry: ...@@ -1703,15 +1736,17 @@ entry:
; ARM32-LABEL: select64VarConst ; ARM32-LABEL: select64VarConst
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcc ; ARM32-OM1: movcs
; ARM32: movcs ; ARM32-OM1: movcc
; ARM32: cmp ; ARM32-OM1: cmp
; ARM32: movw ; ARM32: movw
; ARM32: movt ; ARM32: movt
; ARM32: movne ; ARM32-OM1: movne
; ARM32-O2: movcc
; ARM32: movw ; ARM32: movw
; ARM32: movt ; ARM32: movt
; ARM32: movne ; ARM32-OM1: movne
; ARM32-O2: movcc
define internal i64 @select64ConstVar(i64 %a, i64 %b) { define internal i64 @select64ConstVar(i64 %a, i64 %b) {
entry: entry:
...@@ -1740,15 +1775,17 @@ entry: ...@@ -1740,15 +1775,17 @@ entry:
; ARM32-LABEL: select64ConstVar ; ARM32-LABEL: select64ConstVar
; ARM32: cmp ; ARM32: cmp
; ARM32: cmpeq ; ARM32: cmpeq
; ARM32: movcc ; ARM32-OM1: movcs
; ARM32: movcs ; ARM32-OM1: movcc
; ARM32: cmp ; ARM32-OM1: cmp
; ARM32: movw ; ARM32: movw
; ARM32: movt ; ARM32: movt
; ARM32: movne ; ARM32-OM1: movne
; ARM32-O2: movcc
; ARM32: movw ; ARM32: movw
; ARM32: movt ; ARM32: movt
; ARM32: movne ; ARM32-OM1: movne
; ARM32-O2: movcc
define internal void @icmpEq64Imm() { define internal void @icmpEq64Imm() {
entry: entry:
......
...@@ -28,8 +28,12 @@ branch2: ...@@ -28,8 +28,12 @@ branch2:
; CHECK: cmp ; CHECK: cmp
; CHECK: jge ; CHECK: jge
; ARM32-LABEL: fold_cmp_br ; ARM32-LABEL: fold_cmp_br
; ARM32: cmp ; ARM32: cmp r0, r1
; ARM32: beq ; ARM32: bge
; ARM32: mov r0, #1
; ARM32: bx lr
; ARM32: mov r0, #2
; ARM32: bx lr
; Cmp/branch folding with intervening instructions. ; Cmp/branch folding with intervening instructions.
...@@ -51,11 +55,13 @@ branch2: ...@@ -51,11 +55,13 @@ branch2:
; CHECK: jge ; CHECK: jge
; ARM32-LABEL: fold_cmp_br_intervening_insts ; ARM32-LABEL: fold_cmp_br_intervening_insts
; ARM32: push {{[{].*[}]}} ; ARM32: push {{[{].*[}]}}
; ARM32: movlt [[TMP:r[0-9]+]], #1 ; ARM32: bl use_value
; ARM32: mov [[P:r[4-7]]], [[TMP]] ; ARM32: cmp {{r[0-9]+}}, {{r[0-9]+}}
; ARM32: bl ; ARM32: bge
; ARM32: cmp [[P]], #0 ; ARM32: mov r0, #1
; ARM32: beq ; ARM32: bx lr
; ARM32: mov r0, #2
; ARM32: bx lr
; Cmp/branch non-folding because of live-out. ; Cmp/branch non-folding because of live-out.
...@@ -102,13 +108,14 @@ branch2: ...@@ -102,13 +108,14 @@ branch2:
; CHECK: cmp ; CHECK: cmp
; CHECK: je ; CHECK: je
; ARM32-LABEL: no_fold_cmp_br_non_whitelist ; ARM32-LABEL: no_fold_cmp_br_non_whitelist
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r1 ; ARM32: cmp r0, r1
; ARM32: movge [[R:r[0-9]+]], #0
; ARM32: movlt [[R]], #1 ; ARM32: movlt [[R]], #1
; ARM32: mov [[R2:r[0-9]+]], [[R]] ; ARM32: cmp r0, r1
; ARM32: and [[R3:r[0-9]+]], [[R2]], #1 ; ARM32: bge
; ARM32: cmp [[R]] ; ARM32: bx lr
; ARM32: beq ; ARM32: mov r0, #2
; ARM32: bx lr
; Basic cmp/select folding. ; Basic cmp/select folding.
...@@ -123,11 +130,8 @@ entry: ...@@ -123,11 +130,8 @@ entry:
; CHECK: cmp ; CHECK: cmp
; CHECK: cmovl ; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select ; ARM32-LABEL: fold_cmp_select
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r1 ; ARM32: cmp r0, r1
; ARM32: movlt [[R]], #1 ; ARM32: movlt {{r[0-9]+}}, r0
; ARM32: cmp [[R]], #0
; 64-bit cmp/select folding. ; 64-bit cmp/select folding.
define internal i64 @fold_cmp_select_64(i64 %arg1, i64 %arg2) { define internal i64 @fold_cmp_select_64(i64 %arg1, i64 %arg2) {
...@@ -144,14 +148,11 @@ entry: ...@@ -144,14 +148,11 @@ entry:
; CHECK: cmovl ; CHECK: cmovl
; CHECK: cmovl ; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_64 ; ARM32-LABEL: fold_cmp_select_64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r2 ; ARM32: cmp r0, r2
; ARM32: movlt [[R]], #1 ; ARM32: movlt [[LOW:r[0-9]+]], r0
; ARM32: cmp [[R]], #0 ; ARM32: movlt [[HIGH:r[0-9]+]], r1
; ARM32: movne ; ARM32: mov r0, [[LOW]]
; ARM32: movne ; ARM32: mov r1, [[HIGH]]
; ARM32-DAG: mov r0
; ARM32-DAG: mov r1
; ARM32: bx lr ; ARM32: bx lr
...@@ -168,12 +169,10 @@ entry: ...@@ -168,12 +169,10 @@ entry:
; CHECK: cmovl ; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_64_undef ; ARM32-LABEL: fold_cmp_select_64_undef
; ARM32: cmp {{r[0-9]+}}, r0 ; ARM32: cmp {{r[0-9]+}}, r0
; ARM32: movlt [[R:r[0-9]+]], #1 ; ARM32: movge
; ARM32: cmp [[R]] ; ARM32: movlt
; ARM32: movne ; ARM32: movge
; ARM32: movne ; ARM32: movlt
; ARM32-DAG: mov r0
; ARM32-DAG: mov r1
; ARM32: bx lr ; ARM32: bx lr
...@@ -192,17 +191,10 @@ entry: ...@@ -192,17 +191,10 @@ entry:
; CHECK: cmp ; CHECK: cmp
; CHECK: cmovl ; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_intervening_insts ; ARM32-LABEL: fold_cmp_select_intervening_insts
; ARM32: mov [[RES0:r[4-7]+]], r0
; ARM32: mov [[RES1:r[4-7]+]], r1
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r{{[0-9]+}}, r{{[0-9]+}}
; ARM32: movlt [[R]], #1
; ARM32: mov [[R2:r[4-7]]], [[R]]
; ARM32: bl use_value ; ARM32: bl use_value
; ARM32: cmp [[R2]], #0 ; ARM32: cmp r{{[0-9]+}}, r{{[0-9]+}}
; ARM32: movne [[RES1]], [[RES0]] ; ARM32: movlt
; ARM32: mov r0, [[RES1]] ; ARM32: bx lr
; Cmp/multi-select folding. ; Cmp/multi-select folding.
define internal i32 @fold_cmp_select_multi(i32 %arg1, i32 %arg2) { define internal i32 @fold_cmp_select_multi(i32 %arg1, i32 %arg2) {
...@@ -226,20 +218,14 @@ entry: ...@@ -226,20 +218,14 @@ entry:
; CHECK: add ; CHECK: add
; CHECK: add ; CHECK: add
; ARM32-LABEL: fold_cmp_select_multi ; ARM32-LABEL: fold_cmp_select_multi
; ARM32: mov [[T0:r[0-9]+]], #0
; ARM32: cmp r0, r1 ; ARM32: cmp r0, r1
; ARM32: movlt [[T0]], #1 ; ARM32: movlt {{r[0-9]+}}, r0
; ARM32: uxtb [[T1:r[0-9]+]], [[T1]] ; ARM32: cmp r0, r1
; ARM32-NEXT: cmp [[T1]], #0 ; ARM32: movlt {{r[0-9]+}}, r1
; ARM32: movne [[T2:r[0-9]+]], r0 ; ARM32: cmp r0, r1
; ARM32: uxtb [[T3:r[0-9]+]], [[T3]] ; ARM32: movlt {{r[0-9]+}}, #123
; ARM32-NEXT: cmp [[T3]], #0 ; ARM32: add
; ARM32: movne [[T4:r[0-9]+]], r1 ; ARM32: add
; ARM32: uxtb [[T5:r[0-9]+]], [[T5]]
; ARM32-NEXT: cmp [[T5]], #0
; ARM32: movne [[T6:r[0-9]+]], #123
; ARM32: add [[T7:r[0-9]+]], [[T2]], [[T4]]
; ARM32: add {{r[0-9]+}}, [[T7]], [[T6]]
; ARM32: bx lr ; ARM32: bx lr
...@@ -269,21 +255,21 @@ next: ...@@ -269,21 +255,21 @@ next:
; CHECK: add ; CHECK: add
; ARM32-LABEL: no_fold_cmp_select_multi_liveout ; ARM32-LABEL: no_fold_cmp_select_multi_liveout
; ARM32-LABEL: fold_cmp_select_multi ; ARM32-LABEL: fold_cmp_select_multi
; ARM32: mov [[T0:r[0-9]+]], #0
; ARM32: cmp r0, r1 ; ARM32: cmp r0, r1
; ARM32: movge [[T0:r[0-9]+]], #0
; ARM32: movlt [[T0]], #1 ; ARM32: movlt [[T0]], #1
; ARM32: uxtb [[T2:r[0-9]+]], [[T2]] ; ARM32: uxtb [[T1:r[0-9]+]], [[T1]]
; ARM32-NEXT: cmp [[T2]], #0 ; ARM32-NEXT: cmp [[T1]], #0
; ARM32: movne [[T1]], r0 ; ARM32: movne [[T2:r[0-9]+]], r0
; ARM32: uxtb [[T4:r[0-9]+]], [[T4]] ; ARM32: uxtb [[T3:r[0-9]+]], [[T3]]
; ARM32-NEXT: cmp [[T4]], #0 ; ARM32-NEXT: cmp [[T3]], #0
; ARM32: movne [[T3]], r1 ; ARM32: movne [[T4:r[0-9]+]], r1
; ARM32-LABEL: .Lno_fold_cmp_select_multi_liveout$next: ; ARM32-LABEL: .Lno_fold_cmp_select_multi_liveout$next:
; ARM32: uxtb [[T5:r[0-9]+]], [[T5]] ; ARM32: uxtb [[T5:r[0-9]+]], [[T5]]
; ARM32: cmp [[T5]], #0 ; ARM32: cmp [[T5]], #0
; ARM32: movne [[T6:r[0-9]+]], #123 ; ARM32: movne [[T6:r[0-9]+]], #123
; ARM32: add [[T7:r[0-9]+]], [[T2]], [[T4]] ; ARM32: add
; ARM32: add {{r[0-9]+}}, [[T7]], [[T6]] ; ARM32: add
; ARM32: bx lr ; ARM32: bx lr
; Cmp/multi-select non-folding because of extra non-whitelisted uses. ; Cmp/multi-select non-folding because of extra non-whitelisted uses.
...@@ -314,19 +300,19 @@ entry: ...@@ -314,19 +300,19 @@ entry:
; CHECK: add ; CHECK: add
; CHECK: add ; CHECK: add
; ARM32-LABEL: no_fold_cmp_select_multi_non_whitelist ; ARM32-LABEL: no_fold_cmp_select_multi_non_whitelist
; ARM32: mov [[T0:r[0-9]+]], #0
; ARM32: cmp r0, r1 ; ARM32: cmp r0, r1
; ARM32: movlt [[T0]], #1 ; ARM32: movge [[R0:r[0-9]+]]
; ARM32: uxtb [[T1:r[0-9]+]], [[T1]] ; ARM32: movlt [[R0]]
; ARM32-NEXT: cmp [[T1]], #0 ; ARM32: cmp r0, r1
; ARM32: movne [[T2:r[0-9]+]], r0 ; ARM32: movge [[R1:r[0-9]+]]
; ARM32: uxtb [[T3:r[0-9]+]], [[T3]] ; ARM32: movlt [[R1]]
; ARM32-NEXT: cmp [[T3]], #0 ; ARM32: cmp r0, r1
; ARM32: movne [[T4:r[0-9]+]], r1 ; ARM32: movge [[R2:r[0-9]+]]
; ARM32: uxtb [[T5:r[0-9]+]], [[T5]] ; ARM32: movlt [[R2]]
; ARM32-NEXT: cmp [[T5]], #0 ; ARM32: cmp r0, r1
; ARM32: movne [[T6:r[0-9]+]], #123 ; ARM32: movge [[R3:r[0-9]+]]
; ARM32: and [[T7:r[0-9]+]], [[T0]], #1 ; ARM32: movlt [[R3]]
; ARM32: add [[T8:r[0-9]+]], [[T2]], [[T4]] ; ARM32: add
; ARM32: add {{r[0-9]+}}, [[T8]], [[T7]] ; ARM32: add
; ARM32: add
; ARM32: bx lr ; ARM32: bx lr
...@@ -14,14 +14,14 @@ ...@@ -14,14 +14,14 @@
; when possible. ; when possible.
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -O2 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32O2 %s ; RUN: --command FileCheck --check-prefix ARM32O2 %s
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -Om1 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck \ ; RUN: --command FileCheck \
...@@ -95,10 +95,7 @@ target: ...@@ -95,10 +95,7 @@ target:
; Note that compare and branch folding isn't implemented yet (unlike x86-32). ; Note that compare and branch folding isn't implemented yet (unlike x86-32).
; ARM32O2-LABEL: testCondFallthroughToNextBlock ; ARM32O2-LABEL: testCondFallthroughToNextBlock
; ARM32O2: cmp {{.*}}, #123 ; ARM32O2: cmp {{.*}}, #123
; ARM32O2-NEXT: movge {{.*}}, #1 ; ARM32O2-NEXT: bge
; ARM32O2-NEXT: uxtb
; ARM32O2-NEXT: cmp {{.*}}, #0
; ARM32O2-NEXT: bne
; ARM32O2-NEXT: bl ; ARM32O2-NEXT: bl
; ARM32O2: bx lr ; ARM32O2: bx lr
; ARM32O2: bl ; ARM32O2: bl
...@@ -106,7 +103,8 @@ target: ...@@ -106,7 +103,8 @@ target:
; ARM32OM1-LABEL: testCondFallthroughToNextBlock ; ARM32OM1-LABEL: testCondFallthroughToNextBlock
; ARM32OM1: cmp {{.*}}, #123 ; ARM32OM1: cmp {{.*}}, #123
; ARM32OM1-NEXT: movge {{.*}}, #1 ; ARM32OM1: movlt {{.*}}, #0
; ARM32OM1: movge {{.*}}, #1
; ARM32OM1: cmp {{.*}}, #0 ; ARM32OM1: cmp {{.*}}, #0
; ARM32OM1: bne ; ARM32OM1: bne
; ARM32OM1: b ; ARM32OM1: b
...@@ -154,10 +152,7 @@ target: ...@@ -154,10 +152,7 @@ target:
; (compared to x86-32). ; (compared to x86-32).
; ARM32O2-LABEL: testCondTargetNextBlock ; ARM32O2-LABEL: testCondTargetNextBlock
; ARM32O2: cmp {{.*}}, #123 ; ARM32O2: cmp {{.*}}, #123
; ARM32O2-NEXT: movge {{.*}}, #1 ; ARM32O2-NEXT: blt
; ARM32O2-NEXT: uxtb
; ARM32O2-NEXT: cmp {{.*}}, #0
; ARM32O2-NEXT: beq
; ARM32O2-NEXT: bl ; ARM32O2-NEXT: bl
; ARM32O2: bx lr ; ARM32O2: bx lr
; ARM32O2: bl ; ARM32O2: bl
......
...@@ -9,16 +9,16 @@ ...@@ -9,16 +9,16 @@
; RUN: -allow-externally-defined-symbols | FileCheck %s ; RUN: -allow-externally-defined-symbols | FileCheck %s
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \ ; RUN: --target arm32 -i %s --args -O2 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32 ; RUN: --check-prefix=ARM32 --check-prefix=ARM32-O2
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \ ; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -Om1 --skip-unimplemented \ ; RUN: --target arm32 -i %s --args -Om1 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \ ; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32 ; RUN: --check-prefix=ARM32 --check-prefix=ARM32-OM1
define internal void @fcmpEq(float %a, float %b, double %c, double %d) { define internal void @fcmpEq(float %a, float %b, double %c, double %d) {
entry: entry:
...@@ -51,13 +51,16 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -51,13 +51,16 @@ if.end3: ; preds = %if.then2, %if.end
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpEq ; ARM32-LABEL: fcmpEq
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: moveq [[R0]], #1 ; ARM32-OM1: movne [[R0:r[0-9]+]], #0
; ARM32-OM1: moveq [[R0]], #1
; ARM32-O2: bne
; ARM32: bl func
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: moveq [[R1]], #1 ; ARM32-OM1: movne [[R1:r[0-9]+]], #0
; ARM32-OM1: moveq [[R1]], #1
; ARM32-O2: bne
declare void @func() declare void @func()
...@@ -92,13 +95,15 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -92,13 +95,15 @@ if.end3: ; preds = %if.then2, %if.end
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpNe ; ARM32-LABEL: fcmpNe
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movne [[R0]], #1 ; ARM32-OM1: moveq [[R0:r[0-9]+]], #0
; ARM32-OM1: movne [[R0]], #1
; ARM32-O2: beq
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movne [[R1]], #1 ; ARM32-OM1: moveq [[R1:r[0-9]+]], #0
; ARM32-OM1: movne [[R1]], #1
; ARM32-O2: beq
define internal void @fcmpGt(float %a, float %b, double %c, double %d) { define internal void @fcmpGt(float %a, float %b, double %c, double %d) {
entry: entry:
...@@ -129,13 +134,15 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -129,13 +134,15 @@ if.end3: ; preds = %if.then2, %if.end
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpGt ; ARM32-LABEL: fcmpGt
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movgt [[R0]], #1 ; ARM32-OM1: movle [[R0:r[0-9]+]], #0
; ARM32-OM1: movgt [[R0]], #1
; ARM32-O2: ble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movgt [[R1]], #1 ; ARM32-OM1: movle [[R1:r[0-9]+]], #0
; ARM32-OM1: movgt [[R1]], #1
; ARM32-O2: ble
define internal void @fcmpGe(float %a, float %b, double %c, double %d) { define internal void @fcmpGe(float %a, float %b, double %c, double %d) {
entry: entry:
...@@ -166,13 +173,15 @@ if.end3: ; preds = %if.end, %if.then2 ...@@ -166,13 +173,15 @@ if.end3: ; preds = %if.end, %if.then2
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpGe ; ARM32-LABEL: fcmpGe
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movlt [[R0]], #1 ; ARM32-OM1: movge [[R0:r[0-9]+]], #0
; ARM32-OM1: movlt [[R0]], #1
; ARM32-O2: blt
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movlt [[R1]], #1 ; ARM32-OM1: movge [[R1:r[0-9]+]], #0
; ARM32-OM1: movlt [[R1]], #1
; ARM32-O2: blt
define internal void @fcmpLt(float %a, float %b, double %c, double %d) { define internal void @fcmpLt(float %a, float %b, double %c, double %d) {
entry: entry:
...@@ -203,13 +212,15 @@ if.end3: ; preds = %if.then2, %if.end ...@@ -203,13 +212,15 @@ if.end3: ; preds = %if.then2, %if.end
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpLt ; ARM32-LABEL: fcmpLt
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movmi [[R0]], #1 ; ARM32-OM1: movpl [[R0:r[0-9]+]], #0
; ARM32-OM1: movmi [[R0]], #1
; ARM32-O2: bpl
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movmi [[R1]], #1 ; ARM32-OM1: movpl [[R1:r[0-9]+]], #0
; ARM32-OM1: movmi [[R1]], #1
; ARM32-O2: bpl
define internal void @fcmpLe(float %a, float %b, double %c, double %d) { define internal void @fcmpLe(float %a, float %b, double %c, double %d) {
entry: entry:
...@@ -240,13 +251,15 @@ if.end3: ; preds = %if.end, %if.then2 ...@@ -240,13 +251,15 @@ if.end3: ; preds = %if.end, %if.then2
; CHECK: call {{.*}} R_{{.*}} func ; CHECK: call {{.*}} R_{{.*}} func
; ARM32-LABEL: fcmpLe ; ARM32-LABEL: fcmpLe
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R0:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movhi [[R0]], #1 ; ARM32-OM1: movls [[R0:r[0-9]+]], #0
; ARM32-OM1: movhi [[R0]], #1
; ARM32-O2: bhi
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R1:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movhi [[R1]], #1 ; ARM32-OM1: movls [[R1:r[0-9]+]], #0
; ARM32-OM1: movhi [[R1]], #1
; ARM32-O2: bhi
define internal i32 @fcmpFalseFloat(float %a, float %b) { define internal i32 @fcmpFalseFloat(float %a, float %b) {
entry: entry:
...@@ -257,7 +270,6 @@ entry: ...@@ -257,7 +270,6 @@ entry:
; CHECK-LABEL: fcmpFalseFloat ; CHECK-LABEL: fcmpFalseFloat
; CHECK: mov {{.*}},0x0 ; CHECK: mov {{.*}},0x0
; ARM32-LABEL: fcmpFalseFloat ; ARM32-LABEL: fcmpFalseFloat
; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0 ; ARM32: mov [[R:r[0-9]+]], #0
define internal i32 @fcmpFalseDouble(double %a, double %b) { define internal i32 @fcmpFalseDouble(double %a, double %b) {
...@@ -269,7 +281,6 @@ entry: ...@@ -269,7 +281,6 @@ entry:
; CHECK-LABEL: fcmpFalseDouble ; CHECK-LABEL: fcmpFalseDouble
; CHECK: mov {{.*}},0x0 ; CHECK: mov {{.*}},0x0
; ARM32-LABEL: fcmpFalseDouble ; ARM32-LABEL: fcmpFalseDouble
; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0 ; ARM32: mov [[R:r[0-9]+]], #0
define internal i32 @fcmpOeqFloat(float %a, float %b) { define internal i32 @fcmpOeqFloat(float %a, float %b) {
...@@ -284,8 +295,8 @@ entry: ...@@ -284,8 +295,8 @@ entry:
; CHECK: jp ; CHECK: jp
; ARM32-LABEL: fcmpOeqFloat ; ARM32-LABEL: fcmpOeqFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movne [[R:r[0-9]+]], #0
; ARM32: moveq [[R]], #1 ; ARM32: moveq [[R]], #1
define internal i32 @fcmpOeqDouble(double %a, double %b) { define internal i32 @fcmpOeqDouble(double %a, double %b) {
...@@ -300,8 +311,8 @@ entry: ...@@ -300,8 +311,8 @@ entry:
; CHECK: jp ; CHECK: jp
; ARM32-LABEL: fcmpOeqDouble ; ARM32-LABEL: fcmpOeqDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movne [[R:r[0-9]+]], #0
; ARM32: moveq [[R]], #1 ; ARM32: moveq [[R]], #1
define internal i32 @fcmpOgtFloat(float %a, float %b) { define internal i32 @fcmpOgtFloat(float %a, float %b) {
...@@ -315,8 +326,8 @@ entry: ...@@ -315,8 +326,8 @@ entry:
; CHECK: seta ; CHECK: seta
; ARM32-LABEL: fcmpOgtFloat ; ARM32-LABEL: fcmpOgtFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movle [[R:r[0-9]+]], #0
; ARM32: movgt [[R]], #1 ; ARM32: movgt [[R]], #1
define internal i32 @fcmpOgtDouble(double %a, double %b) { define internal i32 @fcmpOgtDouble(double %a, double %b) {
...@@ -330,8 +341,8 @@ entry: ...@@ -330,8 +341,8 @@ entry:
; CHECK: seta ; CHECK: seta
; ARM32-LABEL: fcmpOgtDouble ; ARM32-LABEL: fcmpOgtDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movle [[R:r[0-9]+]], #0
; ARM32: movgt [[R]], #1 ; ARM32: movgt [[R]], #1
define internal i32 @fcmpOgeFloat(float %a, float %b) { define internal i32 @fcmpOgeFloat(float %a, float %b) {
...@@ -345,8 +356,8 @@ entry: ...@@ -345,8 +356,8 @@ entry:
; CHECK: setae ; CHECK: setae
; ARM32-LABEL: fcmpOgeFloat ; ARM32-LABEL: fcmpOgeFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movlt [[R:r[0-9]+]], #0
; ARM32: movge [[R]], #1 ; ARM32: movge [[R]], #1
define internal i32 @fcmpOgeDouble(double %a, double %b) { define internal i32 @fcmpOgeDouble(double %a, double %b) {
...@@ -360,8 +371,8 @@ entry: ...@@ -360,8 +371,8 @@ entry:
; CHECK: setae ; CHECK: setae
; ARM32-LABEL: fcmpOgeDouble ; ARM32-LABEL: fcmpOgeDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movlt [[R:r[0-9]+]], #0
; ARM32: movge [[R]], #1 ; ARM32: movge [[R]], #1
define internal i32 @fcmpOltFloat(float %a, float %b) { define internal i32 @fcmpOltFloat(float %a, float %b) {
...@@ -375,8 +386,8 @@ entry: ...@@ -375,8 +386,8 @@ entry:
; CHECK: seta ; CHECK: seta
; ARM32-LABEL: fcmpOltFloat ; ARM32-LABEL: fcmpOltFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movpl [[R:r[0-9]+]], #0
; ARM32: movmi [[R]], #1 ; ARM32: movmi [[R]], #1
define internal i32 @fcmpOltDouble(double %a, double %b) { define internal i32 @fcmpOltDouble(double %a, double %b) {
...@@ -390,8 +401,8 @@ entry: ...@@ -390,8 +401,8 @@ entry:
; CHECK: seta ; CHECK: seta
; ARM32-LABEL: fcmpOltDouble ; ARM32-LABEL: fcmpOltDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movpl [[R:r[0-9]+]], #0
; ARM32: movmi [[R]], #1 ; ARM32: movmi [[R]], #1
define internal i32 @fcmpOleFloat(float %a, float %b) { define internal i32 @fcmpOleFloat(float %a, float %b) {
...@@ -405,8 +416,8 @@ entry: ...@@ -405,8 +416,8 @@ entry:
; CHECK: setae ; CHECK: setae
; ARM32-LABEL: fcmpOleFloat ; ARM32-LABEL: fcmpOleFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movhi [[R:r[0-9]+]], #0
; ARM32: movls [[R]], #1 ; ARM32: movls [[R]], #1
define internal i32 @fcmpOleDouble(double %a, double %b) { define internal i32 @fcmpOleDouble(double %a, double %b) {
...@@ -420,8 +431,8 @@ entry: ...@@ -420,8 +431,8 @@ entry:
; CHECK: setae ; CHECK: setae
; ARM32-LABEL: fcmpOleDouble ; ARM32-LABEL: fcmpOleDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movhi [[R:r[0-9]+]], #0
; ARM32: movls [[R]], #1 ; ARM32: movls [[R]], #1
define internal i32 @fcmpOneFloat(float %a, float %b) { define internal i32 @fcmpOneFloat(float %a, float %b) {
...@@ -435,8 +446,8 @@ entry: ...@@ -435,8 +446,8 @@ entry:
; CHECK: setne ; CHECK: setne
; ARM32-LABEL: fcmpOneFloat ; ARM32-LABEL: fcmpOneFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: movmi [[R]], #1 ; ARM32: movmi [[R]], #1
; ARM32: movgt [[R]], #1 ; ARM32: movgt [[R]], #1
...@@ -451,8 +462,8 @@ entry: ...@@ -451,8 +462,8 @@ entry:
; CHECK: setne ; CHECK: setne
; ARM32-LABEL: fcmpOneDouble ; ARM32-LABEL: fcmpOneDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: movmi [[R]], #1 ; ARM32: movmi [[R]], #1
; ARM32: movgt [[R]], #1 ; ARM32: movgt [[R]], #1
...@@ -467,8 +478,8 @@ entry: ...@@ -467,8 +478,8 @@ entry:
; CHECK: setnp ; CHECK: setnp
; ARM32-LABEL: fcmpOrdFloat ; ARM32-LABEL: fcmpOrdFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movvs [[R:r[0-9]+]], #0
; ARM32: movvc [[R]], #1 ; ARM32: movvc [[R]], #1
define internal i32 @fcmpOrdDouble(double %a, double %b) { define internal i32 @fcmpOrdDouble(double %a, double %b) {
...@@ -482,8 +493,8 @@ entry: ...@@ -482,8 +493,8 @@ entry:
; CHECK: setnp ; CHECK: setnp
; ARM32-LABEL: fcmpOrdDouble ; ARM32-LABEL: fcmpOrdDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movvs [[R:r[0-9]+]], #0
; ARM32: movvc [[R]], #1 ; ARM32: movvc [[R]], #1
define internal i32 @fcmpUeqFloat(float %a, float %b) { define internal i32 @fcmpUeqFloat(float %a, float %b) {
...@@ -497,8 +508,8 @@ entry: ...@@ -497,8 +508,8 @@ entry:
; CHECK: sete ; CHECK: sete
; ARM32-LABEL: fcmpUeqFloat ; ARM32-LABEL: fcmpUeqFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: moveq [[R]], #1 ; ARM32: moveq [[R]], #1
; ARM32: movvs [[R]], #1 ; ARM32: movvs [[R]], #1
...@@ -513,8 +524,8 @@ entry: ...@@ -513,8 +524,8 @@ entry:
; CHECK: sete ; CHECK: sete
; ARM32-LABEL: fcmpUeqDouble ; ARM32-LABEL: fcmpUeqDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: moveq [[R]], #1 ; ARM32: moveq [[R]], #1
; ARM32: movvs [[R]], #1 ; ARM32: movvs [[R]], #1
...@@ -529,8 +540,8 @@ entry: ...@@ -529,8 +540,8 @@ entry:
; CHECK: setb ; CHECK: setb
; ARM32-LABEL: fcmpUgtFloat ; ARM32-LABEL: fcmpUgtFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movls [[R:r[0-9]+]], #0
; ARM32: movhi [[R]], #1 ; ARM32: movhi [[R]], #1
define internal i32 @fcmpUgtDouble(double %a, double %b) { define internal i32 @fcmpUgtDouble(double %a, double %b) {
...@@ -544,8 +555,8 @@ entry: ...@@ -544,8 +555,8 @@ entry:
; CHECK: setb ; CHECK: setb
; ARM32-LABEL: fcmpUgtDouble ; ARM32-LABEL: fcmpUgtDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movls [[R:r[0-9]+]], #0
; ARM32: movhi [[R]], #1 ; ARM32: movhi [[R]], #1
define internal i32 @fcmpUgeFloat(float %a, float %b) { define internal i32 @fcmpUgeFloat(float %a, float %b) {
...@@ -559,8 +570,8 @@ entry: ...@@ -559,8 +570,8 @@ entry:
; CHECK: setbe ; CHECK: setbe
; ARM32-LABEL: fcmpUgeFloat ; ARM32-LABEL: fcmpUgeFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movmi [[R:r[0-9]+]], #0
; ARM32: movpl [[R]], #1 ; ARM32: movpl [[R]], #1
define internal i32 @fcmpUgeDouble(double %a, double %b) { define internal i32 @fcmpUgeDouble(double %a, double %b) {
...@@ -574,8 +585,8 @@ entry: ...@@ -574,8 +585,8 @@ entry:
; CHECK: setbe ; CHECK: setbe
; ARM32-LABEL: fcmpUgeDouble ; ARM32-LABEL: fcmpUgeDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movmi [[R:r[0-9]+]], #0
; ARM32: movpl [[R]], #1 ; ARM32: movpl [[R]], #1
define internal i32 @fcmpUltFloat(float %a, float %b) { define internal i32 @fcmpUltFloat(float %a, float %b) {
...@@ -589,8 +600,8 @@ entry: ...@@ -589,8 +600,8 @@ entry:
; CHECK: setb ; CHECK: setb
; ARM32-LABEL: fcmpUltFloat ; ARM32-LABEL: fcmpUltFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movge [[R:r[0-9]+]], #0
; ARM32: movlt [[R]], #1 ; ARM32: movlt [[R]], #1
define internal i32 @fcmpUltDouble(double %a, double %b) { define internal i32 @fcmpUltDouble(double %a, double %b) {
...@@ -604,8 +615,8 @@ entry: ...@@ -604,8 +615,8 @@ entry:
; CHECK: setb ; CHECK: setb
; ARM32-LABEL: fcmpUltDouble ; ARM32-LABEL: fcmpUltDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movge [[R:r[0-9]+]], #0
; ARM32: movlt [[R]], #1 ; ARM32: movlt [[R]], #1
define internal i32 @fcmpUleFloat(float %a, float %b) { define internal i32 @fcmpUleFloat(float %a, float %b) {
...@@ -619,8 +630,8 @@ entry: ...@@ -619,8 +630,8 @@ entry:
; CHECK: setbe ; CHECK: setbe
; ARM32-LABEL: fcmpUleFloat ; ARM32-LABEL: fcmpUleFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movgt [[R:r[0-9]+]], #0
; ARM32: movle [[R]], #1 ; ARM32: movle [[R]], #1
define internal i32 @fcmpUleDouble(double %a, double %b) { define internal i32 @fcmpUleDouble(double %a, double %b) {
...@@ -634,8 +645,8 @@ entry: ...@@ -634,8 +645,8 @@ entry:
; CHECK: setbe ; CHECK: setbe
; ARM32-LABEL: fcmpUleDouble ; ARM32-LABEL: fcmpUleDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movgt [[R:r[0-9]+]], #0
; ARM32: movle [[R]], #1 ; ARM32: movle [[R]], #1
define internal i32 @fcmpUneFloat(float %a, float %b) { define internal i32 @fcmpUneFloat(float %a, float %b) {
...@@ -650,8 +661,8 @@ entry: ...@@ -650,8 +661,8 @@ entry:
; CHECK: jp ; CHECK: jp
; ARM32-LABEL: fcmpUneFloat ; ARM32-LABEL: fcmpUneFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: moveq [[R:r[0-9]+]], #0
; ARM32: movne [[R]], #1 ; ARM32: movne [[R]], #1
define internal i32 @fcmpUneDouble(double %a, double %b) { define internal i32 @fcmpUneDouble(double %a, double %b) {
...@@ -666,8 +677,8 @@ entry: ...@@ -666,8 +677,8 @@ entry:
; CHECK: jp ; CHECK: jp
; ARM32-LABEL: fcmpUneDouble ; ARM32-LABEL: fcmpUneDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: moveq [[R:r[0-9]+]], #0
; ARM32: movne [[R]], #1 ; ARM32: movne [[R]], #1
define internal i32 @fcmpUnoFloat(float %a, float %b) { define internal i32 @fcmpUnoFloat(float %a, float %b) {
...@@ -681,8 +692,8 @@ entry: ...@@ -681,8 +692,8 @@ entry:
; CHECK: setp ; CHECK: setp
; ARM32-LABEL: fcmpUnoFloat ; ARM32-LABEL: fcmpUnoFloat
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movvc [[R:r[0-9]+]], #0
; ARM32: movvs [[R]], #1 ; ARM32: movvs [[R]], #1
define internal i32 @fcmpUnoDouble(double %a, double %b) { define internal i32 @fcmpUnoDouble(double %a, double %b) {
...@@ -696,8 +707,8 @@ entry: ...@@ -696,8 +707,8 @@ entry:
; CHECK: setp ; CHECK: setp
; ARM32-LABEL: fcmpUnoDouble ; ARM32-LABEL: fcmpUnoDouble
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: vmrs ; ARM32: vmrs
; ARM32: movvc [[R:r[0-9]+]], #0
; ARM32: movvs [[R]], #1 ; ARM32: movvs [[R]], #1
define internal i32 @fcmpTrueFloat(float %a, float %b) { define internal i32 @fcmpTrueFloat(float %a, float %b) {
...@@ -709,8 +720,7 @@ entry: ...@@ -709,8 +720,7 @@ entry:
; CHECK-LABEL: fcmpTrueFloat ; CHECK-LABEL: fcmpTrueFloat
; CHECK: mov {{.*}},0x1 ; CHECK: mov {{.*}},0x1
; ARM32-LABEL: fcmpTrueFloat ; ARM32-LABEL: fcmpTrueFloat
; ARM32: vcmp.f32 ; ARM32: mov {{r[0-9]+}}, #1
; ARM32: mov [[R]], #1
define internal i32 @fcmpTrueDouble(double %a, double %b) { define internal i32 @fcmpTrueDouble(double %a, double %b) {
entry: entry:
...@@ -721,8 +731,7 @@ entry: ...@@ -721,8 +731,7 @@ entry:
; CHECK-LABEL: fcmpTrueDouble ; CHECK-LABEL: fcmpTrueDouble
; CHECK: mov {{.*}},0x1 ; CHECK: mov {{.*}},0x1
; ARM32-LABEL: fcmpTrueDouble ; ARM32-LABEL: fcmpTrueDouble
; ARM32: vcmp.f64 ; ARM32: mov {{r[0-9]+}}, #1
; ARM32: mov [[R]], #1
define internal float @selectFloatVarVar(float %a, float %b) { define internal float @selectFloatVarVar(float %a, float %b) {
entry: entry:
...@@ -736,7 +745,8 @@ entry: ...@@ -736,7 +745,8 @@ entry:
; CHECK: fld ; CHECK: fld
; ARM32-LABEL: selectFloatVarVar ; ARM32-LABEL: selectFloatVarVar
; ARM32: vcmp.f32 ; ARM32: vcmp.f32
; ARM32: vmovne.f32 s{{[0-9]+}} ; ARM32-OM1: vmovne.f32 s{{[0-9]+}}
; ARM32-O2: vmovmi.f32 s{{[0-9]+}}
; ARM32: bx ; ARM32: bx
define internal double @selectDoubleVarVar(double %a, double %b) { define internal double @selectDoubleVarVar(double %a, double %b) {
...@@ -751,5 +761,6 @@ entry: ...@@ -751,5 +761,6 @@ entry:
; CHECK: fld ; CHECK: fld
; ARM32-LABEL: selectDoubleVarVar ; ARM32-LABEL: selectDoubleVarVar
; ARM32: vcmp.f64 ; ARM32: vcmp.f64
; ARM32: vmovne.f64 d{{[0-9]+}} ; ARM32-OM1: vmovne.f64 d{{[0-9]+}}
; ARM32-O2: vmovmi.f64 d{{[0-9]+}}
; ARM32: bx ; ARM32: bx
...@@ -12,16 +12,16 @@ ...@@ -12,16 +12,16 @@
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -O2 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix ARM32-O2 %s
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -Om1 \
; RUN: -allow-externally-defined-symbols \ ; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 --check-prefix ARM32-OM1 %s
define internal void @testSelect(i32 %a, i32 %b) { define internal void @testSelect(i32 %a, i32 %b) {
entry: entry:
...@@ -51,12 +51,16 @@ declare void @useInt(i32 %x) ...@@ -51,12 +51,16 @@ declare void @useInt(i32 %x)
; CHECK: ret ; CHECK: ret
; ARM32-LABEL: testSelect ; ARM32-LABEL: testSelect
; ARM32: cmp ; ARM32: cmp
; ARM32: cmp ; ARM32-OM1: cmp
; ARM32: bl {{.*}} useInt ; ARM32: bl {{.*}} useInt
; ARM32: cmp ; ARM32: cmp
; ARM32: cmp ; ARM32-Om1: cmp
; ARM32: mov {{.*}}, #20 ; ARM32-Om1: mov {{.*}}, #20
; ARM32: movne {{.*}}, #10 ; ARM32-Om1: movne {{.*}}, #10
; ARM32-O2: movle [[REG:r[0-9]+]], #20
; ARM32-O2: movgt [[REG]], #10
; ARM32: bl {{.*}} useInt
; ARM32: bl {{.*}} useInt
; ARM32: bl {{.*}} useInt ; ARM32: bl {{.*}} useInt
; ARM32: bx lr ; ARM32: bx lr
......
...@@ -8,17 +8,10 @@ ...@@ -8,17 +8,10 @@
; RUN: --target x8632 -i %s --args -Om1 \ ; RUN: --target x8632 -i %s --args -Om1 \
; RUN: | %if --need=target_X8632 --command FileCheck %s ; RUN: | %if --need=target_X8632 --command FileCheck %s
; TODO(jvoung): Stop skipping unimplemented parts (via --skip-unimplemented) ; TODO(jpp): Switch to --filetype=obj when possible.
; once enough infrastructure is in. Also, switch to --filetype=obj
; when possible.
; RUN: %if --need=target_ARM32 --need=allow_dump \ ; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \ ; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \ ; RUN: --disassemble --target arm32 -i %s --args -O2 \
; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s
; RUN: %if --need=target_ARM32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble \
; RUN: --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 %s
...@@ -73,7 +66,9 @@ entry: ...@@ -73,7 +66,9 @@ entry:
; CHECK-LABEL: testTrunc ; CHECK-LABEL: testTrunc
; CHECK: and {{.*}},0x1 ; CHECK: and {{.*}},0x1
; ARM32-LABEL: testTrunc ; ARM32-LABEL: testTrunc
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], #1
; Test zext to i8. ; Test zext to i8.
define internal i32 @testZextI8(i32 %arg) { define internal i32 @testZextI8(i32 %arg) {
...@@ -89,8 +84,10 @@ entry: ...@@ -89,8 +84,10 @@ entry:
; match the zext i1 instruction (NOTE: no mov need between i1 and i8). ; match the zext i1 instruction (NOTE: no mov need between i1 and i8).
; CHECK-NOT: and {{.*}},0x1 ; CHECK-NOT: and {{.*}},0x1
; ARM32-LABEL: testZextI8 ; ARM32-LABEL: testZextI8
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: and {{.*}}, #1 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], #1
; ARM32: uxtb [[REG]]
; Test zext to i16. ; Test zext to i16.
define internal i32 @testZextI16(i32 %arg) { define internal i32 @testZextI16(i32 %arg) {
...@@ -108,10 +105,10 @@ entry: ...@@ -108,10 +105,10 @@ entry:
; CHECK-NOT: and [[REG]],0x1 ; CHECK-NOT: and [[REG]],0x1
; ARM32-LABEL: testZextI16 ; ARM32-LABEL: testZextI16
; match the trunc instruction ; ARM32: tst r0, #1
; ARM32: and {{.*}}, #1 ; ARM32: moveq [[REG:r[0-9]*]], #0
; match the zext (no need to uxt into a reg if src is already in a reg) ; ARM32: movne [[REG]], #1
; ARM32: and {{.*}}, #1 ; ARM32: uxth [[REG]]
; Test zext to i32. ; Test zext to i32.
define internal i32 @testZextI32(i32 %arg) { define internal i32 @testZextI32(i32 %arg) {
...@@ -127,8 +124,9 @@ entry: ...@@ -127,8 +124,9 @@ entry:
; CHECK: movzx ; CHECK: movzx
; CHECK-NOT: and {{.*}},0x1 ; CHECK-NOT: and {{.*}},0x1
; ARM32-LABEL: testZextI32 ; ARM32-LABEL: testZextI32
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: and {{.*}}, #1 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], #1
; Test zext to i64. ; Test zext to i64.
define internal i64 @testZextI64(i32 %arg) { define internal i64 @testZextI64(i32 %arg) {
...@@ -144,9 +142,10 @@ entry: ...@@ -144,9 +142,10 @@ entry:
; CHECK: movzx ; CHECK: movzx
; CHECK: mov {{.*}},0x0 ; CHECK: mov {{.*}},0x0
; ARM32-LABEL: testZextI64 ; ARM32-LABEL: testZextI64
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: and {{.*}}, #1 ; ARM32: mov r{{[0-9]*}}, #0
; ARM32: mov {{.*}}, #0 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], #1
; Test sext to i8. ; Test sext to i8.
define internal i32 @testSextI8(i32 %arg) { define internal i32 @testSextI8(i32 %arg) {
...@@ -163,13 +162,12 @@ entry: ...@@ -163,13 +162,12 @@ entry:
; CHECK: shl [[REG:.*]],0x7 ; CHECK: shl [[REG:.*]],0x7
; CHECK-NEXT: sar [[REG]],0x7 ; CHECK-NEXT: sar [[REG]],0x7
; ;
; ARM shifts by 32, since there aren't any byte regs.
; ARM32-LABEL: testSextI8 ; ARM32-LABEL: testSextI8
; match the trunc instruction ; ARM32: tst r0, #1
; ARM32: and {{.*}}, #1 ; ARM32: mvn [[REG_M1:r[0-9]*]], #0
; match the sext i1 instruction ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: lsl {{.*}}, #31 ; ARM32: movne [[REG]], [[REG_M1]]
; ARM32-NEXT: asr {{.*}}, #31 ; ARM32: sxtb [[REG]]
; Test sext to i16. ; Test sext to i16.
define internal i32 @testSextI16(i32 %arg) { define internal i32 @testSextI16(i32 %arg) {
...@@ -188,9 +186,11 @@ entry: ...@@ -188,9 +186,11 @@ entry:
; CHECK-NEXT: sar [[REG]],0xf ; CHECK-NEXT: sar [[REG]],0xf
; ARM32-LABEL: testSextI16 ; ARM32-LABEL: testSextI16
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: lsl {{.*}}, #31 ; ARM32: mvn [[REG_M1:r[0-9]*]], #0
; ARM32-NEXT: asr {{.*}}, #31 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], [[REG_M1]]
; ARM32: sxth [[REG]]
; Test sext to i32. ; Test sext to i32.
define internal i32 @testSextI32(i32 %arg) { define internal i32 @testSextI32(i32 %arg) {
...@@ -208,9 +208,10 @@ entry: ...@@ -208,9 +208,10 @@ entry:
; CHECK-NEXT: sar [[REG]],0x1f ; CHECK-NEXT: sar [[REG]],0x1f
; ARM32-LABEL: testSextI32 ; ARM32-LABEL: testSextI32
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: lsl {{.*}}, #31 ; ARM32: mvn [[REG_M1:r[0-9]*]], #0
; ARM32-NEXT: asr {{.*}}, #31 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32: movne [[REG]], [[REG_M1]]
; Test sext to i64. ; Test sext to i64.
define internal i64 @testSextI64(i32 %arg) { define internal i64 @testSextI64(i32 %arg) {
...@@ -228,10 +229,11 @@ entry: ...@@ -228,10 +229,11 @@ entry:
; CHECK-NEXT: sar [[REG]],0x1f ; CHECK-NEXT: sar [[REG]],0x1f
; ARM32-LABEL: testSextI64 ; ARM32-LABEL: testSextI64
; ARM32: and {{.*}}, #1 ; ARM32: tst r0, #1
; ARM32: lsl {{.*}}, #31 ; ARM32: mvn [[REG_M1:r[0-9]*]], #0
; ARM32-NEXT: asr [[REG:r.*]], {{.*}}, #31 ; ARM32: moveq [[REG:r[0-9]*]], #0
; ARM32-NEXT: {{(mov|str).*}} [[REG]] ; ARM32: movne [[REG]], [[REG_M1]]
; ARM32: mov r{{[0-9]+}}, [[REG]]
; Kind of like sext i1 to i32, but with an immediate source. On ARM, ; Kind of like sext i1 to i32, but with an immediate source. On ARM,
; sxtb cannot take an immediate operand, so make sure it's using a reg. ; sxtb cannot take an immediate operand, so make sure it's using a reg.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment