Chromium Code Reviews| 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; |
| } |