Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Unified Diff: src/IceTargetLoweringARM32.cpp

Issue 1417393003: Subzero. ARM32. New bool folding. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Fixes lit tests. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/IceTargetLoweringARM32.cpp
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 17bd1b5876fc6f1cbaf0210859dabf61802b779f..4fad50b1d206990f75708baf5ad9e96adc3f4745 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -1044,7 +1044,11 @@ void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr,
}
if (Legalized) {
- _mov(Dest, Src);
+ if (MovInstr->isDestRedefined()) {
+ _mov_redefined(Dest, Src, MovInstr->getPredicate());
+ } else {
+ _mov(Dest, Src, MovInstr->getPredicate());
+ }
MovInstr->setDeleted();
}
}
@@ -1346,8 +1350,57 @@ void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R,
return;
}
+TargetARM32::SafeBoolChain
+TargetARM32::lowerInt1Arithmetic(const InstArithmetic *Inst) {
+ Variable *Dest = Inst->getDest();
+ assert(Dest->getType() == IceType_i1);
+
+ // So folding didn't work for Inst. Not a problem: We just need to
+ // materialize the Sources, and perform the operation. We create reguar
Jim Stichnoth 2015/11/11 18:55:04 regular
John 2015/11/11 22:19:44 Done.
+ // Variables (and not infinite-weight ones) because this call might recurse a
+ // lot, and we might end up with tons of infinite weight temporaries.
+ assert(Inst->getSrcSize() == 2);
+ Variable *Src0 = Func->makeVariable(IceType_i1);
Jim Stichnoth 2015/11/11 18:55:04 Can you do this instead? Variable *Src0 = mak
John 2015/11/11 22:19:44 N/A
+ SafeBoolChain Src0Safe = lowerInt1(Src0, Inst->getSrc(0));
+
+ Operand *Src1 = Inst->getSrc(1);
+ SafeBoolChain Src1Safe = SBC_Yes;
+
+ if (!llvm::isa<Constant>(Src1)) {
+ Variable *Src1V = Func->makeVariable(IceType_i1);
+ Src1Safe = lowerInt1(Src1V, Src1);
+ Src1 = Src1V;
+ }
+
+ Variable *T = makeReg(IceType_i1);
+ Src0 = legalizeToReg(Src0);
+ Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
+ switch (Inst->getOp()) {
+ default:
+ // If this Unreachable is ever executed, add the offending operation to
+ // the list of valid consumers.
+ llvm_unreachable("Unhandled i1 Op");
Jim Stichnoth 2015/11/11 18:55:04 llvm::report_fatal_error here and below
John 2015/11/11 22:19:46 Done.
+ case InstArithmetic::And:
+ _and(T, Src0, Src1RF);
+ break;
+ case InstArithmetic::Or:
+ _orr(T, Src0, Src1RF);
+ break;
+ case InstArithmetic::Xor:
+ _eor(T, Src0, Src1RF);
+ break;
+ }
+ _mov(Dest, T);
+ return Src0Safe == SBC_Yes && Src1Safe == SBC_Yes ? SBC_Yes : SBC_No;
+}
+
void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) {
Variable *Dest = Inst->getDest();
+ if (Dest->getType() == IceType_i1) {
+ lowerInt1Arithmetic(Inst);
+ return;
+ }
+
// TODO(jvoung): Should be able to flip Src0 and Src1 if it is easier to
// legalize Src0 to flex or Src1 to flex and there is a reversible
// instruction. E.g., reverse subtract with immediate, register vs register,
@@ -1814,46 +1867,129 @@ void TargetARM32::lowerAssign(const InstAssign *Inst) {
}
}
+TargetARM32::ShortCircuitCondAndLabel TargetARM32::lowerInt1ForBranch(
+ Operand *Boolean, const LowerInt1BranchTarget &TargetTrue,
+ const LowerInt1BranchTarget &TargetFalse, uint32_t ShortCircuitable) {
+ InstARM32Label *NewShortCircuitLabel = nullptr;
+ Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
+
+ const Inst *Producer = BoolComputations.getProducerOf(Boolean);
+
+ if (Producer == nullptr) {
+ // No producer, no problem: just do emit codee to perform (Boolean & 1) and
Jim Stichnoth 2015/11/11 18:55:04 codee?
John 2015/11/11 22:19:46 Done.
+ // set the flags register. The branch should be taken if the resulting flags
+ // indicate a non-zero result.
+ _tst(legalizeToReg(Boolean), _1);
+ return ShortCircuitCondAndLabel(CondWhenTrue(CondARM32::NE));
+ }
+
+ switch (Producer->getKind()) {
+ default:
+ llvm_unreachable("Unexpected producer.");
+ case Inst::Icmp: {
+ return ShortCircuitCondAndLabel(
+ lowerIcmpCond(llvm::cast<InstIcmp>(Producer)));
+ } break;
+ case Inst::Fcmp: {
+ return ShortCircuitCondAndLabel(
+ lowerFcmpCond(llvm::cast<InstFcmp>(Producer)));
+ } break;
+ case Inst::Cast: {
+ const auto *CastProducer = llvm::cast<InstCast>(Producer);
+ assert(CastProducer->getCastKind() == InstCast::Trunc);
+ Operand *Src = CastProducer->getSrc(0);
+ if (Src->getType() == IceType_i64)
+ Src = loOperand(Src);
+ _tst(legalizeToReg(Src), _1);
+ return ShortCircuitCondAndLabel(CondWhenTrue(CondARM32::NE));
+ } break;
+ case Inst::Arithmetic: {
+ const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
+ switch (ArithProducer->getOp()) {
+ default:
+ llvm_unreachable("Unhandled Arithmetic Producer.");
+ case InstArithmetic::And: {
+ if (!(ShortCircuitable & SC_And)) {
+ NewShortCircuitLabel = InstARM32Label::create(Func, this);
+ }
+
+ LowerInt1BranchTarget NewTarget =
+ TargetFalse.createForLabelOrDuplicate(NewShortCircuitLabel);
+
+ ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
+ Producer->getSrc(0), TargetTrue, NewTarget, SC_And);
+ const CondWhenTrue &Cond = CondAndLabel.Cond;
+
+ _br_short_circuit(NewTarget, Cond.invert());
+
+ InstARM32Label *const ShortCircuitLabel = CondAndLabel.ShortCircuitTarget;
+ if (ShortCircuitLabel != nullptr)
+ Context.insert(ShortCircuitLabel);
+
+ return ShortCircuitCondAndLabel(
+ lowerInt1ForBranch(Producer->getSrc(1), TargetTrue, NewTarget, SC_All)
+ .assertNoLabelAndReturnCond(),
+ NewShortCircuitLabel);
+ } break;
+ case InstArithmetic::Or: {
+ if (!(ShortCircuitable & SC_Or)) {
+ NewShortCircuitLabel = InstARM32Label::create(Func, this);
+ }
+
+ LowerInt1BranchTarget NewTarget =
+ TargetTrue.createForLabelOrDuplicate(NewShortCircuitLabel);
+
+ ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
+ Producer->getSrc(0), NewTarget, TargetFalse, SC_Or);
+ const CondWhenTrue &Cond = CondAndLabel.Cond;
+
+ _br_short_circuit(NewTarget, Cond);
+
+ InstARM32Label *const ShortCircuitLabel = CondAndLabel.ShortCircuitTarget;
+ if (ShortCircuitLabel != nullptr)
+ Context.insert(ShortCircuitLabel);
+
+ return ShortCircuitCondAndLabel(lowerInt1ForBranch(Producer->getSrc(1),
+ NewTarget, TargetFalse,
+ SC_All)
+ .assertNoLabelAndReturnCond(),
+ NewShortCircuitLabel);
+ } break;
+ }
+ }
+ }
+}
+
void TargetARM32::lowerBr(const InstBr *Instr) {
if (Instr->isUnconditional()) {
_br(Instr->getTargetUnconditional());
return;
}
- Operand *Cond = Instr->getCondition();
-
- 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 folded.
- Type Ty = Cond->getType();
- Variable *Src0R = legalizeToReg(Cond);
- assert(Ty == IceType_i1);
- if (Ty != IceType_i32)
- _uxt(Src0R, Src0R);
- Constant *_0 = Ctx->getConstantZero(IceType_i32);
- _cmp(Src0R, _0);
- BrCondTrue0 = CondARM32::NE;
- }
- if (BrCondTrue1 != CondARM32::kNone) {
- _br(Instr->getTargetTrue(), BrCondTrue1);
- }
+ CfgNode *TargetTrue = Instr->getTargetTrue();
+ CfgNode *TargetFalse = Instr->getTargetFalse();
+ ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
+ Instr->getCondition(), LowerInt1BranchTarget(TargetTrue),
+ LowerInt1BranchTarget(TargetFalse), SC_All);
+ assert(CondAndLabel.ShortCircuitTarget == nullptr);
- if (BrCondTrue0 == CondARM32::kNone) {
- assert(BrCondTrue1 == CondARM32::kNone);
- _br(Instr->getTargetFalse());
- return;
+ const CondWhenTrue &Cond = CondAndLabel.Cond;
+ if (Cond.WhenTrue1 != CondARM32::kNone) {
+ assert(Cond.WhenTrue0 != CondARM32::AL);
+ _br(TargetTrue, Cond.WhenTrue1);
}
- if (BrCondTrue0 == CondARM32::AL) {
- assert(BrCondTrue1 == CondARM32::kNone);
- assert(BrCondFalse == CondARM32::kNone);
- _br(Instr->getTargetTrue());
- return;
+ switch (Cond.WhenTrue0) {
+ default:
+ _br(TargetTrue, TargetFalse, Cond.WhenTrue0);
+ break;
+ case CondARM32::kNone:
+ _br(TargetFalse);
+ break;
+ case CondARM32::AL:
+ _br(TargetTrue);
+ break;
}
-
- _br(Instr->getTargetTrue(), Instr->getTargetFalse(), BrCondTrue0);
}
void TargetARM32::lowerCall(const InstCall *Instr) {
@@ -1959,6 +2095,7 @@ void TargetARM32::lowerCall(const InstCall *Instr) {
case IceType_void:
break;
case IceType_i1:
+ assert(BoolComputations.getProducerOf(Dest) == nullptr);
Jim Stichnoth 2015/11/11 18:55:04 Note the deliberate fallthrough in a comment?
John 2015/11/11 22:19:44 Done.
case IceType_i8:
case IceType_i16:
case IceType_i32:
@@ -2089,18 +2226,9 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
Variable *Src0R = legalizeToReg(Src0);
_sxt(T_Lo, Src0R);
} 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 {
- Variable *Src0R = legalizeToReg(Src0);
- _lsl(T_Lo, Src0R, ShiftAmt);
- _asr(T_Lo, T_Lo, ShiftAmt);
- }
+ Operand *_0 = Ctx->getConstantZero(IceType_i32);
+ Operand *_m1 = Ctx->getConstantInt32(-1);
+ lowerInt1ForSelect(T_Lo, Src0, _m1, _0);
}
_mov(DestLo, T_Lo);
Variable *T_Hi = makeReg(DestHi->getType());
@@ -2119,24 +2247,10 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
_sxt(T, Src0R);
_mov(Dest, T);
} else {
+ Constant *_0 = Ctx->getConstantZero(IceType_i32);
+ Operand *_m1 = Ctx->getConstantInt(Dest->getType(), -1);
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.
- // lsl t1, src_reg, 31
- // asr t1, t1, 31
- // dst = t1
- Variable *Src0R = legalizeToReg(Src0);
- Constant *ShiftAmt = Ctx->getConstantInt32(31);
- _lsl(T, Src0R, ShiftAmt);
- _asr(T, T, ShiftAmt);
- }
+ lowerInt1ForSelect(T, Src0, _m1, _0);
_mov(Dest, T);
}
break;
@@ -2149,60 +2263,44 @@ void TargetARM32::lowerCast(const InstCast *Inst) {
UnimplementedError(Func->getContext()->getFlags());
} else if (Dest->getType() == IceType_i64) {
// t1=uxtb src; dst.lo=t1; dst.hi=0
- Constant *_0 = Ctx->getConstantZero(IceType_i32);
- Constant *_1 = Ctx->getConstantInt32(1);
+ Operand *_0 =
+ legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
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;
+ switch (Src0->getType()) {
+ default: {
+ assert(Src0->getType() != IceType_i64);
+ _uxt(T_Lo, legalizeToReg(Src0));
+ } break;
+ case IceType_i32: {
+ _mov(T_Lo, legalize(Src0, Legal_Reg | Legal_Flex));
+ } break;
+ case IceType_i1: {
+ SafeBoolChain Safe = lowerInt1(T_Lo, Src0);
+ if (Safe == SBC_No) {
+ Operand *_1 =
+ legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
+ _and(T_Lo, T_Lo, _1);
+ }
+ } break;
}
- // i32 and i1 can just take up the whole register. i32 doesn't need uxt,
- // while i1 will have an and mask later anyway.
- if (Src0->getType() == IceType_i32 || Src0->getType() == IceType_i1) {
- Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
- _mov(T_Lo, Src0RF);
- } else {
- Variable *Src0R = legalizeToReg(Src0);
- _uxt(T_Lo, Src0R);
- }
- if (Src0->getType() == IceType_i1) {
- Constant *One = Ctx->getConstantInt32(1);
- _and(T_Lo, T_Lo, One);
- }
_mov(DestLo, T_Lo);
+
Variable *T_Hi = makeReg(DestLo->getType());
_mov(T_Hi, _0);
_mov(DestHi, T_Hi);
} 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;
+ SafeBoolChain Safe = lowerInt1(T, Src0);
+ if (Safe == SBC_No) {
+ Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
+ _and(T, T, _1);
}
- // t = Src0; t &= 1; Dest = t
- Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
- // 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
- // from legalize anyway.
- _mov(T, Src0RF);
- _and(T, T, _1);
_mov(Dest, T);
} else {
// t1 = uxt src; dst = t1
@@ -2473,19 +2571,13 @@ struct {
};
} // end of anonymous namespace
-void TargetARM32::lowerFcmpCond(const InstFcmp *Instr,
- CondARM32::Cond *CondIfTrue0,
- CondARM32::Cond *CondIfTrue1,
- CondARM32::Cond *CondIfFalse) {
+TargetARM32::CondWhenTrue TargetARM32::lowerFcmpCond(const InstFcmp *Instr) {
InstFcmp::FCond Condition = Instr->getCondition();
switch (Condition) {
case InstFcmp::False:
- *CondIfFalse = CondARM32::AL;
- *CondIfTrue0 = *CondIfTrue1 = CondARM32::kNone;
- break;
+ return CondWhenTrue(CondARM32::kNone);
case InstFcmp::True:
- *CondIfFalse = *CondIfTrue1 = CondARM32::kNone;
- *CondIfTrue0 = CondARM32::AL;
+ return CondWhenTrue(CondARM32::AL);
break;
default: {
Variable *Src0R = legalizeToReg(Instr->getSrc(0));
@@ -2493,11 +2585,7 @@ void TargetARM32::lowerFcmpCond(const InstFcmp *Instr,
_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);
+ return CondWhenTrue(TableFcmp[Condition].CC0, TableFcmp[Condition].CC1);
}
}
}
@@ -2513,39 +2601,40 @@ void TargetARM32::lowerFcmp(const InstFcmp *Instr) {
}
Variable *T = makeReg(IceType_i1);
- Operand *_1 = Ctx->getConstantInt32(1);
- Operand *_0 = Ctx->getConstantZero(IceType_i32);
+ Operand *_1 = legalize(Ctx->getConstantInt32(1), Legal_Reg | Legal_Flex);
+ Operand *_0 =
+ legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
- CondARM32::Cond CondIfTrue0, CondIfTrue1, CondIfFalse;
- lowerFcmpCond(Instr, &CondIfTrue0, &CondIfTrue1, &CondIfFalse);
+ CondWhenTrue Cond = lowerFcmpCond(Instr);
bool RedefineT = false;
- if (CondIfFalse != CondARM32::kNone) {
- assert(!RedefineT);
- _mov(T, _0, CondIfFalse);
+ if (Cond.WhenTrue0 != CondARM32::AL) {
+ _mov(T, _0);
RedefineT = true;
}
- if (CondIfTrue0 != CondARM32::kNone) {
- if (RedefineT) {
- _mov_redefined(T, _1, CondIfTrue0);
- } else {
- _mov(T, _1, CondIfTrue0);
- }
- RedefineT = true;
+ if (Cond.WhenTrue0 == CondARM32::kNone) {
+ _mov(Dest, T);
+ return;
+ }
+
+ if (RedefineT) {
+ _mov_redefined(T, _1, Cond.WhenTrue0);
+ } else {
+ _mov(T, _1, Cond.WhenTrue0);
}
- if (CondIfTrue1 != CondARM32::kNone) {
- assert(RedefineT);
- _mov_redefined(T, _1, CondIfTrue1);
+ if (Cond.WhenTrue1 != CondARM32::kNone) {
+ _mov_redefined(T, _1, Cond.WhenTrue1);
}
_mov(Dest, T);
}
-void TargetARM32::lowerIcmpCond(const InstIcmp *Inst,
- CondARM32::Cond *CondIfTrue,
- CondARM32::Cond *CondIfFalse) {
+TargetARM32::CondWhenTrue TargetARM32::lowerIcmpCond(const InstIcmp *Inst) {
+ assert(Inst->getSrc(0)->getType() != IceType_i1);
+ assert(Inst->getSrc(1)->getType() != IceType_i1);
+
Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Operand *Src1 = legalizeUndef(Inst->getSrc(1));
@@ -2607,9 +2696,7 @@ void TargetARM32::lowerIcmpCond(const InstIcmp *Inst,
_cmp(Src0Hi, Src1HiRF);
_cmp(Src0Lo, Src1LoRF, CondARM32::EQ);
}
- *CondIfTrue = TableIcmp64[Index].C1;
- *CondIfFalse = TableIcmp64[Index].C2;
- return;
+ return CondWhenTrue(TableIcmp64[Index].C1);
}
// a=icmp cond b, c ==>
@@ -2661,8 +2748,7 @@ void TargetARM32::lowerIcmpCond(const InstIcmp *Inst,
Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
_cmp(Src0R, Src1RF);
}
- *CondIfTrue = getIcmp32Mapping(Inst->getCondition());
- *CondIfFalse = InstARM32::getOppositeCondition(*CondIfTrue);
+ return CondWhenTrue(getIcmp32Mapping(Inst->getCondition()));
}
void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
@@ -2676,17 +2762,18 @@ void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
return;
}
- Constant *_0 = Ctx->getConstantZero(IceType_i32);
- Constant *_1 = Ctx->getConstantInt32(1);
+ Operand *_0 =
+ legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
+ Operand *_1 = legalize(Ctx->getConstantInt32(1), Legal_Reg | Legal_Flex);
Variable *T = makeReg(IceType_i1);
- CondARM32::Cond CondIfTrue, CondIfFalse;
- lowerIcmpCond(Inst, &CondIfTrue, &CondIfFalse);
-
- _mov(T, _0, CondIfFalse);
- _mov_redefined(T, _1, CondIfTrue);
+ _mov(T, _0);
+ CondWhenTrue Cond = lowerIcmpCond(Inst);
+ _mov_redefined(T, _1, Cond.WhenTrue0);
_mov(Dest, T);
+ assert(Cond.WhenTrue1 == CondARM32::kNone);
+
return;
}
@@ -3903,119 +3990,7 @@ void TargetARM32::lowerSelect(const InstSelect *Inst) {
return;
}
- 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
- Variable *CmpOpnd0 = legalizeToReg(Condition);
- Type CmpOpnd0Ty = CmpOpnd0->getType();
- Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32);
- assert(CmpOpnd0Ty == IceType_i1);
- if (CmpOpnd0Ty != IceType_i32)
- _uxt(CmpOpnd0, CmpOpnd0);
- _cmp(CmpOpnd0, CmpOpnd1);
- CondIfTrue0 = CondARM32::NE;
- CondIfTrue1 = CondARM32::kNone;
- CondIfFalse = CondARM32::EQ;
- }
-
- if (DestTy == IceType_i64) {
- SrcT = legalizeUndef(SrcT);
- SrcF = legalizeUndef(SrcF);
- // Set the low portion.
- 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);
- Variable *TLo = makeReg(SrcFLo->getType());
- bool RedefineTLo = false;
- if (CondIfFalse != CondARM32::kNone) {
- _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);
-
- // Set the high portion.
- 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);
- Variable *THi = makeReg(SrcFHi->getType());
- bool RedefineTHi = false;
- if (CondIfFalse != CondARM32::kNone) {
- _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);
- return;
- }
-
- if (isFloatingType(DestTy)) {
- SrcT = legalizeToReg(SrcT);
- SrcF = legalizeToReg(SrcF);
- Variable *T = makeReg(DestTy);
- assert(DestTy == SrcF->getType());
- 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);
- }
- assert(DestTy == SrcT->getType());
- _mov(Dest, T);
- return;
- }
-
- Variable *T = makeReg(SrcF->getType());
- SrcT = legalize(SrcT, Legal_Reg | Legal_Flex);
- 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);
+ lowerInt1ForSelect(Dest, Condition, legalizeUndef(SrcT), legalizeUndef(SrcF));
}
void TargetARM32::lowerStore(const InstStore *Inst) {
@@ -4430,74 +4405,251 @@ void TargetARM32::emit(const ConstantUndef *) const {
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
+void TargetARM32::lowerInt1ForSelect(Variable *Dest, Operand *Boolean,
+ Operand *TrueValue, Operand *FalseValue) {
+ Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
+
+ assert(Boolean->getType() == IceType_i1);
+
+ bool NeedsAnd1 = false;
+ if (TrueValue->getType() == IceType_i1) {
+ assert(FalseValue->getType() == IceType_i1);
+
+ Variable *TrueValueV = Func->makeVariable(IceType_i1);
+ SafeBoolChain Src0Safe = lowerInt1(TrueValueV, TrueValue);
+ TrueValue = TrueValueV;
+
+ Variable *FalseValueV = Func->makeVariable(IceType_i1);
+ SafeBoolChain Src1Safe = lowerInt1(FalseValueV, FalseValue);
+ FalseValue = FalseValueV;
+
+ NeedsAnd1 = Src0Safe == SBC_No || Src1Safe == SBC_No;
+ }
+
+ Variable *DestLo = (Dest->getType() == IceType_i64)
+ ? llvm::cast<Variable>(loOperand(Dest))
+ : Dest;
+ Variable *DestHi = (Dest->getType() == IceType_i64)
+ ? llvm::cast<Variable>(hiOperand(Dest))
+ : nullptr;
+ Operand *FalseValueLo = (FalseValue->getType() == IceType_i64)
+ ? loOperand(FalseValue)
+ : FalseValue;
+ Operand *FalseValueHi =
+ (FalseValue->getType() == IceType_i64) ? hiOperand(FalseValue) : nullptr;
+
+ Operand *TrueValueLo =
+ (TrueValue->getType() == IceType_i64) ? loOperand(TrueValue) : TrueValue;
+ Operand *TrueValueHi =
+ (TrueValue->getType() == IceType_i64) ? hiOperand(TrueValue) : nullptr;
+
+ Variable *T_Lo = makeReg(DestLo->getType());
+ Variable *T_Hi = (DestHi == nullptr) ? nullptr : makeReg(DestHi->getType());
+
+ _mov(T_Lo, legalize(FalseValueLo, Legal_Reg | Legal_Flex));
+ if (DestHi) {
+ _mov(T_Hi, legalize(FalseValueHi, Legal_Reg | Legal_Flex));
+ }
+
+ CondWhenTrue Cond(CondARM32::kNone);
+ // FlagsWereSet is used to determine wether Boolean was fold or not. If not,
Jim Stichnoth 2015/11/11 18:55:04 whether ... folded
John 2015/11/11 22:19:46 Done.
+ // and explicit
Jim Stichnoth 2015/11/11 18:55:04 "and" is probably the wrong word here? Also, refl
John 2015/11/11 22:19:46 Done.
+ // _tst instruction below.
+ bool FlagsWereSet = false;
+ if (const Inst *Producer = BoolComputations.getProducerOf(Boolean)) {
+ switch (Producer->getKind()) {
+ default:
+ llvm_unreachable("Unexpected producer.");
+ case Inst::Icmp: {
+ Cond = lowerIcmpCond(llvm::cast<InstIcmp>(Producer));
+ FlagsWereSet = true;
+ } break;
+ case Inst::Fcmp: {
+ Cond = lowerFcmpCond(llvm::cast<InstFcmp>(Producer));
+ FlagsWereSet = true;
+ } break;
+ case Inst::Cast: {
+ const auto *CastProducer = llvm::cast<InstCast>(Producer);
+ assert(CastProducer->getCastKind() == InstCast::Trunc);
+ Boolean = CastProducer->getSrc(0);
+ // No flags were set, so a _tst(Src, 1) will be emitted below. Don't
+ // bother legalizing Src to a Reg because it will be legalized before
+ // emitting the tst instruction.
+ FlagsWereSet = false;
+ } break;
+ case Inst::Arithmetic: {
+ // This is a special case: we eagerly assumed Producer could be fold, but
Jim Stichnoth 2015/11/11 18:55:04 folded ?
John 2015/11/11 22:19:46 Done.
+ // in reality, it can't. No reason to panic: we just lower it using the
+ // regular lowerArithmetic helper.
+ const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
+ lowerArithmetic(ArithProducer);
+ Boolean = ArithProducer->getDest();
+ // No flags were set, so a _tst(Dest, 1) will be emitted below. Don't
+ // bother legalizing Dest to a Reg because it will be legalized before
+ // emitting the tst instruction.
Jim Stichnoth 2015/11/11 18:55:04 single space char between "emitting the"
John 2015/11/11 22:19:44 Done.
+ FlagsWereSet = false;
+ } break;
+ }
+ }
+
+ if (!FlagsWereSet) {
+ // No flags have been set, so emit a tst Boolean, 1.
+ Variable *Src = legalizeToReg(Boolean);
+ _tst(Src, _1);
+ Cond = CondWhenTrue(CondARM32::NE); // i.e., CondARM32::NotZero.
+ }
+
+ if (Cond.WhenTrue0 == CondARM32::kNone) {
+ assert(Cond.WhenTrue1 == CondARM32::kNone);
+ } else {
+ _mov_redefined(T_Lo, legalize(TrueValueLo, Legal_Reg | Legal_Flex),
+ Cond.WhenTrue0);
+ if (DestHi) {
+ _mov_redefined(T_Hi, legalize(TrueValueHi, Legal_Reg | Legal_Flex),
+ Cond.WhenTrue0);
+ }
+ }
+
+ if (Cond.WhenTrue1 != CondARM32::kNone) {
+ _mov_redefined(T_Lo, legalize(TrueValueLo, Legal_Reg | Legal_Flex),
+ Cond.WhenTrue1);
+ if (DestHi) {
+ _mov_redefined(T_Hi, legalize(TrueValueHi, Legal_Reg | Legal_Flex),
+ Cond.WhenTrue1);
+ }
+ }
+
+ if (NeedsAnd1) {
+ // We lowered something that is unsafe (i.e., can't provably be zero or
+ // one). Truncate the result.
+ _and(T_Lo, T_Lo, _1);
+ }
+
+ _mov(DestLo, T_Lo);
+ if (DestHi) {
+ _mov(DestHi, T_Hi);
+ }
}
-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;
+TargetARM32::SafeBoolChain TargetARM32::lowerInt1(Variable *Dest,
+ Operand *Boolean) {
+ assert(Boolean->getType() == IceType_i1);
+ Variable *T = makeReg(IceType_i1);
+ Operand *_0 =
+ legalize(Ctx->getConstantZero(IceType_i1), Legal_Reg | Legal_Flex);
+ Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
+
+ SafeBoolChain Safe = SBC_Yes;
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)) {
+ switch (Producer->getKind()) {
+ default:
+ llvm_unreachable("Unexpected producer.");
+ case Inst::Icmp: {
+ _mov(T, _0);
+ CondWhenTrue Cond = lowerIcmpCond(llvm::cast<InstIcmp>(Producer));
+ assert(Cond.WhenTrue0 != CondARM32::AL);
+ assert(Cond.WhenTrue0 != CondARM32::kNone);
+ assert(Cond.WhenTrue1 == CondARM32::kNone);
+ _mov_redefined(T, _1, Cond.WhenTrue0);
+ } break;
+ case Inst::Fcmp: {
+ _mov(T, _0);
+ Inst *MovZero = Context.getLastInserted();
+ CondWhenTrue Cond = lowerFcmpCond(llvm::cast<InstFcmp>(Producer));
+ if (Cond.WhenTrue0 == CondARM32::AL) {
+ assert(Cond.WhenTrue1 == CondARM32::kNone);
+ MovZero->setDeleted();
+ _mov(T, _1);
+ } else if (Cond.WhenTrue0 != CondARM32::kNone) {
+ _mov_redefined(T, _1, Cond.WhenTrue0);
+ }
+ if (Cond.WhenTrue1 != CondARM32::kNone) {
+ assert(Cond.WhenTrue0 != CondARM32::kNone);
+ assert(Cond.WhenTrue0 != CondARM32::AL);
+ _mov_redefined(T, _1, Cond.WhenTrue1);
+ }
+ } break;
+ case Inst::Cast: {
+ const auto *CastProducer = llvm::cast<InstCast>(Producer);
assert(CastProducer->getCastKind() == InstCast::Trunc);
- lowerTruncToFlags(CastProducer->getSrc(0), CondIfTrue0, CondIfFalse);
- FoldOK = true;
+ Operand *Src = CastProducer->getSrc(0);
+ if (Src->getType() == IceType_i64)
+ Src = loOperand(Src);
+ _mov(T, legalize(Src, Legal_Reg | Legal_Flex));
+ Safe = SBC_No;
+ } break;
+ case Inst::Arithmetic: {
+ const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
+ Safe = lowerInt1Arithmetic(ArithProducer);
+ _mov(T, ArithProducer->getDest());
+ } break;
}
+ } else {
+ _mov(T, legalize(Boolean, Legal_Reg | Legal_Flex));
}
- return FoldOK;
+
+ _mov(Dest, T);
+ return Safe;
}
namespace {
namespace BoolFolding {
bool shouldTrackProducer(const Inst &Instr) {
- switch (static_cast<uint32_t>(Instr.getKind())) {
+ switch (Instr.getKind()) {
+ default:
+ return false;
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 Inst::Cast: {
+ switch (llvm::cast<InstCast>(&Instr)->getCastKind()) {
+ default:
+ return false;
case InstCast::Trunc:
return true;
}
}
- return false;
+ case Inst::Arithmetic: {
+ switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
+ default:
+ return false;
+ case InstArithmetic::And:
+ case InstArithmetic::Or:
+ return true;
+ }
+ }
+ }
}
bool isValidConsumer(const Inst &Instr) {
- switch (static_cast<uint32_t>(Instr.getKind())) {
+ switch (Instr.getKind()) {
+ default:
+ return false;
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 Inst::Cast: {
+ switch (llvm::cast<InstCast>(&Instr)->getCastKind()) {
+ default:
+ return false;
case InstCast::Sext:
return !isVectorType(Instr.getDest()->getType());
case InstCast::Zext:
return !isVectorType(Instr.getDest()->getType());
}
}
- return false;
+ case Inst::Arithmetic: {
+ switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
+ default:
+ return false;
+ case InstArithmetic::And:
+ return !isVectorType(Instr.getDest()->getType());
+ case InstArithmetic::Or:
+ return !isVectorType(Instr.getDest()->getType());
+ }
+ }
+ }
}
} // end of namespace BoolFolding
} // end of anonymous namespace
@@ -4520,9 +4672,8 @@ void TargetARM32::BoolComputationTracker::recordProducers(CfgNode *Node) {
continue;
}
- if (IndexOfVarOperandInInst(Var) != 0 ||
- !BoolFolding::isValidConsumer(Instr)) {
- // All valid consumers use Var as the first source operand
+ ++ComputationIter->second.NumUses;
+ if (!BoolFolding::isValidConsumer(Instr)) {
KnownComputations.erase(VarNum);
continue;
}
@@ -4536,7 +4687,7 @@ void TargetARM32::BoolComputationTracker::recordProducers(CfgNode *Node) {
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) {
+ if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) {
Iter = KnownComputations.erase(Iter);
continue;
}

Powered by Google App Engine
This is Rietveld 408576698