Chromium Code Reviews| Index: src/IceTargetLoweringX8632.cpp |
| diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp |
| index 506b315079909210d3b1f7c9dc1fbee21e0e53ea..af460cb06767e35512d7c2e7e57f5ed108dc466d 100644 |
| --- a/src/IceTargetLoweringX8632.cpp |
| +++ b/src/IceTargetLoweringX8632.cpp |
| @@ -246,6 +246,25 @@ ICETYPE_TABLE |
| #undef X |
| } // end of namespace dummy3 |
| +// A helper class to ease the settings of RandomizationPoolingPause |
| +// to disable constant blinding or pooling for some translation phases. |
| +class BoolFlagSaver { |
| + BoolFlagSaver() = delete; |
| + BoolFlagSaver(const BoolFlagSaver &) = delete; |
| + BoolFlagSaver &operator=(const BoolFlagSaver &) = delete; |
| + |
| +public: |
| + BoolFlagSaver(bool &F, bool NewValue) : Flag(F) { |
| + OldValue = F; |
| + F = NewValue; |
| + } |
| + ~BoolFlagSaver() { Flag = OldValue; } |
| + |
| +private: |
| + bool &Flag; |
|
Jim Stichnoth
2015/06/19 16:51:03
Can you do this?
bool &const Flag;
const bool
qining
2015/06/19 20:22:25
I can initialize OldValue in the initialization li
Jim Stichnoth
2015/06/19 23:12:15
I think I was wrong about const and Flag, sorry.
|
| + bool OldValue; |
| +}; |
| + |
| } // end of anonymous namespace |
| BoolFoldingEntry::BoolFoldingEntry(Inst *I) |
| @@ -399,8 +418,8 @@ TargetX8632::TargetX8632(Cfg *Func) |
| InstructionSet(static_cast<X86InstructionSet>( |
| Func->getContext()->getFlags().getTargetInstructionSet() - |
| TargetInstructionSet::X86InstructionSet_Begin)), |
| - IsEbpBasedFrame(false), NeedsStackAlignment(false), |
| - SpillAreaSizeBytes(0) { |
| + IsEbpBasedFrame(false), NeedsStackAlignment(false), SpillAreaSizeBytes(0), |
| + RandomizationPoolingPaused(false) { |
| static_assert((X86InstructionSet::End - X86InstructionSet::Begin) == |
| (TargetInstructionSet::X86InstructionSet_End - |
| TargetInstructionSet::X86InstructionSet_Begin), |
| @@ -482,7 +501,11 @@ void TargetX8632::translateO2() { |
| return; |
| Func->dump("After x86 address mode opt"); |
| - doLoadOpt(); |
| + // qining: disable constant blinding or pooling for load optimization |
| + { |
| + BoolFlagSaver B(RandomizationPoolingPaused, true); |
| + doLoadOpt(); |
| + } |
| Func->genCode(); |
| if (Func->hasError()) |
| return; |
| @@ -509,7 +532,13 @@ void TargetX8632::translateO2() { |
| Func->dump("After linear scan regalloc"); |
| if (Ctx->getFlags().getPhiEdgeSplit()) { |
| - Func->advancedPhiLowering(); |
| + // qining: In general we need to pause constant blinding or pooling |
|
Jim Stichnoth
2015/06/19 16:51:03
Don't tag comments with your name. Use TODO(qinin
qining
2015/06/19 20:22:26
Done.
|
| + // during advanced phi lowering, unless the lowering assignment has a |
| + // physical register for the Dest Variable |
| + { |
| + BoolFlagSaver B(RandomizationPoolingPaused, true); |
| + Func->advancedPhiLowering(); |
| + } |
| Func->dump("After advanced Phi lowering"); |
| } |
| @@ -762,8 +791,9 @@ void TargetX8632::emitVariable(const Variable *Var) const { |
| Str << "%" << getRegName(Var->getRegNum(), Var->getType()); |
| return; |
| } |
| - if (Var->getWeight().isInf()) |
| + if (Var->getWeight().isInf()) { |
| llvm_unreachable("Infinite-weight Variable has no register assigned"); |
| + } |
| int32_t Offset = Var->getStackOffset(); |
| if (!hasFramePointer()) |
| Offset += getStackAdjustment(); |
| @@ -776,8 +806,9 @@ void TargetX8632::emitVariable(const Variable *Var) const { |
| X8632::Address TargetX8632::stackVarToAsmOperand(const Variable *Var) const { |
| if (Var->hasReg()) |
| llvm_unreachable("Stack Variable has a register assigned"); |
| - if (Var->getWeight().isInf()) |
| + if (Var->getWeight().isInf()) { |
| llvm_unreachable("Infinite-weight Variable has no register assigned"); |
| + } |
| int32_t Offset = Var->getStackOffset(); |
| if (!hasFramePointer()) |
| Offset += getStackAdjustment(); |
| @@ -1168,12 +1199,18 @@ Operand *TargetX8632::loOperand(Operand *Operand) { |
| return Var->getLo(); |
| } |
| if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { |
| - return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue())); |
| - } |
| - if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) { |
| - return OperandX8632Mem::create(Func, IceType_i32, Mem->getBase(), |
| - Mem->getOffset(), Mem->getIndex(), |
| - Mem->getShift(), Mem->getSegmentRegister()); |
| + ConstantInteger32 *ConstInt = llvm::dyn_cast<ConstantInteger32>( |
| + Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue()))); |
| + return legalize(ConstInt); |
| + } |
| + if (OperandX8632Mem *Mem = llvm::cast<OperandX8632Mem>(Operand)) { |
|
Jim Stichnoth
2015/06/19 16:51:03
llvm::dyn_cast
qining
2015/06/19 20:22:25
Done.
|
| + OperandX8632Mem *MemOperand = OperandX8632Mem::create( |
| + Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(), |
| + Mem->getShift(), Mem->getSegmentRegister()); |
| + // Test if we should randomize or pool the offset, if so randomize it or |
| + // pool it then create mem operand with the blinded/pooled constant. |
| + // Otherwise, return the mem operand as ordinary mem operand. |
| + return legalize(MemOperand); |
| } |
| llvm_unreachable("Unsupported operand type"); |
| return nullptr; |
| @@ -1189,8 +1226,10 @@ Operand *TargetX8632::hiOperand(Operand *Operand) { |
| return Var->getHi(); |
| } |
| if (ConstantInteger64 *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { |
| - return Ctx->getConstantInt32( |
| - static_cast<uint32_t>(Const->getValue() >> 32)); |
| + ConstantInteger32 *ConstInt = llvm::dyn_cast<ConstantInteger32>( |
| + Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue() >> 32))); |
| + // check if we need to blind/pool the constant |
| + return legalize(ConstInt); |
| } |
| if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) { |
| Constant *Offset = Mem->getOffset(); |
| @@ -1206,9 +1245,13 @@ Operand *TargetX8632::hiOperand(Operand *Operand) { |
| Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName(), |
| SymOffset->getSuppressMangling()); |
| } |
| - return OperandX8632Mem::create(Func, IceType_i32, Mem->getBase(), Offset, |
| - Mem->getIndex(), Mem->getShift(), |
| - Mem->getSegmentRegister()); |
| + OperandX8632Mem *MemOperand = OperandX8632Mem::create( |
| + Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(), |
| + Mem->getShift(), Mem->getSegmentRegister()); |
| + // Test if the Offset is an eligible i32 constants for randomization and |
| + // pooling. Blind/pool it if it is. Otherwise return as oridinary mem |
| + // operand. |
| + return legalize(MemOperand); |
| } |
| llvm_unreachable("Unsupported operand type"); |
| return nullptr; |
| @@ -1287,6 +1330,102 @@ void TargetX8632::lowerAlloca(const InstAlloca *Inst) { |
| _mov(Dest, esp); |
| } |
| +// Strength-reduce scalar integer multiplication by a constant (for |
| +// i32 or narrower) for certain constants. The lea instruction can be |
| +// used to multiply by 3, 5, or 9, and the lsh instruction can be used |
| +// to multiply by powers of 2. These can be combined such that |
| +// e.g. multiplying by 100 can be done as 2 lea-based multiplies by 5, |
| +// combined with left-shifting by 2. |
| +bool TargetX8632::optimizeScalarMul(Variable *Dest, Operand *Src0, |
| + int32_t Src1) { |
| + // Disable this optimization for Om1 and O0, just to keep things |
| + // simple there. |
| + if (Ctx->getFlags().getOptLevel() < Opt_1) |
| + return false; |
| + Type Ty = Dest->getType(); |
| + Variable *T = nullptr; |
| + if (Src1 == -1) { |
| + _mov(T, Src0); |
| + _neg(T); |
| + _mov(Dest, T); |
| + return true; |
| + } |
| + if (Src1 == 0) { |
| + _mov(Dest, Ctx->getConstantZero(Ty)); |
| + return true; |
| + } |
| + if (Src1 == 1) { |
| + _mov(T, Src0); |
| + _mov(Dest, T); |
| + return true; |
| + } |
| + // Don't bother with the edge case where Src1 == MININT. |
| + if (Src1 == -Src1) |
| + return false; |
| + const bool Src1IsNegative = Src1 < 0; |
| + if (Src1IsNegative) |
| + Src1 = -Src1; |
| + uint32_t Count9 = 0; |
| + uint32_t Count5 = 0; |
| + uint32_t Count3 = 0; |
| + uint32_t Count2 = 0; |
| + uint32_t CountOps = 0; |
| + while (Src1 > 1) { |
| + if (Src1 % 9 == 0) { |
| + ++CountOps; |
| + ++Count9; |
| + Src1 /= 9; |
| + } else if (Src1 % 5 == 0) { |
| + ++CountOps; |
| + ++Count5; |
| + Src1 /= 5; |
| + } else if (Src1 % 3 == 0) { |
| + ++CountOps; |
| + ++Count3; |
| + Src1 /= 3; |
| + } else if (Src1 % 2 == 0) { |
| + if (Count2 == 0) |
| + ++CountOps; |
| + ++Count2; |
| + Src1 /= 2; |
| + } else { |
| + return false; |
| + } |
| + } |
| + // Lea optimization only works for i16 and i32 types, not i8. |
| + if (Ty != IceType_i16 && Ty != IceType_i32 && (Count3 || Count5 || Count9)) |
| + return false; |
| + // Limit the number of lea/shl operations for a single multiply, to |
| + // a somewhat arbitrary choice of 3. |
| + const uint32_t MaxOpsForOptimizedMul = 3; |
| + if (CountOps > MaxOpsForOptimizedMul) |
| + return false; |
| + _mov(T, Src0); |
| + Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| + for (uint32_t i = 0; i < Count9; ++i) { |
| + const uint16_t Shift = 3; // log2(9-1) |
| + _lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); |
| + _set_dest_nonkillable(); |
| + } |
| + for (uint32_t i = 0; i < Count5; ++i) { |
| + const uint16_t Shift = 2; // log2(5-1) |
| + _lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); |
| + _set_dest_nonkillable(); |
| + } |
| + for (uint32_t i = 0; i < Count3; ++i) { |
| + const uint16_t Shift = 1; // log2(3-1) |
| + _lea(T, OperandX8632Mem::create(Func, IceType_void, T, Zero, T, Shift)); |
| + _set_dest_nonkillable(); |
| + } |
| + if (Count2) { |
| + _shl(T, Ctx->getConstantInt(Ty, Count2)); |
| + } |
| + if (Src1IsNegative) |
| + _neg(T); |
| + _mov(Dest, T); |
| + return true; |
| +} |
| + |
| void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) { |
| Variable *Dest = Inst->getDest(); |
| Operand *Src0 = legalize(Inst->getSrc(0)); |
| @@ -1294,8 +1433,47 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) { |
| if (Inst->isCommutative()) { |
| if (!llvm::isa<Variable>(Src0) && llvm::isa<Variable>(Src1)) |
| std::swap(Src0, Src1); |
| + if (llvm::isa<Constant>(Src0) && !llvm::isa<Constant>(Src1)) |
| + std::swap(Src0, Src1); |
| } |
| if (Dest->getType() == IceType_i64) { |
| + switch (Inst->getOp()) { |
|
Jim Stichnoth
2015/06/19 16:51:03
Add a comment explaining why these instructions ar
qining
2015/06/19 20:22:26
Done.
|
| + case InstArithmetic::Udiv: { |
| + const SizeT MaxSrcs = 2; |
| + InstCall *Call = makeHelperCall(H_udiv_i64, Dest, MaxSrcs); |
| + Call->addArg(Inst->getSrc(0)); |
| + Call->addArg(Inst->getSrc(1)); |
| + lowerCall(Call); |
| + return; |
| + } |
| + case InstArithmetic::Sdiv: { |
| + const SizeT MaxSrcs = 2; |
| + InstCall *Call = makeHelperCall(H_sdiv_i64, Dest, MaxSrcs); |
| + Call->addArg(Inst->getSrc(0)); |
| + Call->addArg(Inst->getSrc(1)); |
| + lowerCall(Call); |
| + return; |
| + } |
| + case InstArithmetic::Urem: { |
| + const SizeT MaxSrcs = 2; |
| + InstCall *Call = makeHelperCall(H_urem_i64, Dest, MaxSrcs); |
| + Call->addArg(Inst->getSrc(0)); |
| + Call->addArg(Inst->getSrc(1)); |
| + lowerCall(Call); |
| + return; |
| + } |
| + case InstArithmetic::Srem: { |
| + const SizeT MaxSrcs = 2; |
| + InstCall *Call = makeHelperCall(H_srem_i64, Dest, MaxSrcs); |
| + Call->addArg(Inst->getSrc(0)); |
| + Call->addArg(Inst->getSrc(1)); |
| + lowerCall(Call); |
| + return; |
| + } |
| + default: |
| + break; |
| + } |
| + |
| Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
| Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
| Operand *Src0Lo = loOperand(Src0); |
| @@ -1485,34 +1663,6 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) { |
| _mov(DestLo, T_2); |
| _mov(DestHi, T_3); |
| } break; |
| - case InstArithmetic::Udiv: { |
| - const SizeT MaxSrcs = 2; |
| - InstCall *Call = makeHelperCall(H_udiv_i64, Dest, MaxSrcs); |
| - Call->addArg(Inst->getSrc(0)); |
| - Call->addArg(Inst->getSrc(1)); |
| - lowerCall(Call); |
| - } break; |
| - case InstArithmetic::Sdiv: { |
| - const SizeT MaxSrcs = 2; |
| - InstCall *Call = makeHelperCall(H_sdiv_i64, Dest, MaxSrcs); |
| - Call->addArg(Inst->getSrc(0)); |
| - Call->addArg(Inst->getSrc(1)); |
| - lowerCall(Call); |
| - } break; |
| - case InstArithmetic::Urem: { |
| - const SizeT MaxSrcs = 2; |
| - InstCall *Call = makeHelperCall(H_urem_i64, Dest, MaxSrcs); |
| - Call->addArg(Inst->getSrc(0)); |
| - Call->addArg(Inst->getSrc(1)); |
| - lowerCall(Call); |
| - } break; |
| - case InstArithmetic::Srem: { |
| - const SizeT MaxSrcs = 2; |
| - InstCall *Call = makeHelperCall(H_srem_i64, Dest, MaxSrcs); |
| - Call->addArg(Inst->getSrc(0)); |
| - Call->addArg(Inst->getSrc(1)); |
| - lowerCall(Call); |
| - } break; |
| case InstArithmetic::Fadd: |
| case InstArithmetic::Fsub: |
| case InstArithmetic::Fmul: |
| @@ -1520,8 +1670,13 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) { |
| case InstArithmetic::Frem: |
| llvm_unreachable("FP instruction with i64 type"); |
| break; |
| + default: |
|
Jim Stichnoth
2015/06/19 16:51:03
Don't use default, instead just explicitly list Ud
qining
2015/06/19 20:22:25
Done.
|
| + llvm_unreachable("Unknown instruction with i64 type"); |
| + break; |
| } |
| - } else if (isVectorType(Dest->getType())) { |
| + return; |
| + } |
| + if (isVectorType(Dest->getType())) { |
| // TODO: Trap on integer divide and integer modulo by zero. |
| // See: https://code.google.com/p/nativeclient/issues/detail?id=3899 |
| if (llvm::isa<OperandX8632Mem>(Src1)) |
| @@ -1650,175 +1805,248 @@ void TargetX8632::lowerArithmetic(const InstArithmetic *Inst) { |
| scalarizeArithmetic(Inst->getOp(), Dest, Src0, Src1); |
| break; |
| } |
| - } else { // Dest->getType() is non-i64 scalar |
| - Variable *T_edx = nullptr; |
| - Variable *T = nullptr; |
| - switch (Inst->getOp()) { |
| - case InstArithmetic::_num: |
| - llvm_unreachable("Unknown arithmetic operator"); |
| - break; |
| - case InstArithmetic::Add: |
| - _mov(T, Src0); |
| - _add(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::And: |
| - _mov(T, Src0); |
| - _and(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Or: |
| - _mov(T, Src0); |
| - _or(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Xor: |
| + return; |
| + } |
| + Variable *T_edx = nullptr; |
| + Variable *T = nullptr; |
| + switch (Inst->getOp()) { |
| + case InstArithmetic::_num: |
| + llvm_unreachable("Unknown arithmetic operator"); |
| + break; |
| + case InstArithmetic::Add: |
| + _mov(T, Src0); |
| + _add(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::And: |
| + _mov(T, Src0); |
| + _and(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Or: |
| + _mov(T, Src0); |
| + _or(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Xor: |
| + _mov(T, Src0); |
| + _xor(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Sub: |
| + _mov(T, Src0); |
| + _sub(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Mul: |
| + if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) { |
| + if (optimizeScalarMul(Dest, Src0, C->getValue())) |
| + return; |
| + } |
| + // The 8-bit version of imul only allows the form "imul r/m8" |
| + // where T must be in eax. |
| + if (isByteSizedArithType(Dest->getType())) { |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| + } else { |
| _mov(T, Src0); |
| - _xor(T, Src1); |
| + } |
| + _imul(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Shl: |
| + _mov(T, Src0); |
| + if (!llvm::isa<Constant>(Src1)) |
| + Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| + _shl(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Lshr: |
| + _mov(T, Src0); |
| + if (!llvm::isa<Constant>(Src1)) |
| + Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| + _shr(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Ashr: |
| + _mov(T, Src0); |
| + if (!llvm::isa<Constant>(Src1)) |
| + Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| + _sar(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Udiv: |
| + // div and idiv are the few arithmetic operators that do not allow |
| + // immediates as the operand. |
| + Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| + if (isByteSizedArithType(Dest->getType())) { |
| + Variable *T_ah = nullptr; |
| + Constant *Zero = Ctx->getConstantZero(IceType_i8); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _mov(T_ah, Zero, RegX8632::Reg_ah); |
| + _div(T, Src1, T_ah); |
| _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Sub: |
| - _mov(T, Src0); |
| - _sub(T, Src1); |
| + } else { |
| + Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _mov(T_edx, Zero, RegX8632::Reg_edx); |
| + _div(T, Src1, T_edx); |
| _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Mul: |
| - // TODO: Optimize for llvm::isa<Constant>(Src1) |
| - // TODO: Strength-reduce multiplications by a constant, |
| - // particularly -1 and powers of 2. Advanced: use lea to |
| - // multiply by 3, 5, 9. |
| - // |
| - // The 8-bit version of imul only allows the form "imul r/m8" |
| - // where T must be in eax. |
| - if (isByteSizedArithType(Dest->getType())) { |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| - } else { |
| - _mov(T, Src0); |
| + } |
| + break; |
| + case InstArithmetic::Sdiv: |
| + // TODO(stichnot): Enable this after doing better performance |
| + // and cross testing. |
| + if (false && Ctx->getFlags().getOptLevel() >= Opt_1) { |
| + // Optimize division by constant power of 2, but not for Om1 |
| + // or O0, just to keep things simple there. |
| + if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) { |
| + int32_t Divisor = C->getValue(); |
| + uint32_t UDivisor = static_cast<uint32_t>(Divisor); |
| + if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) { |
| + uint32_t LogDiv = llvm::Log2_32(UDivisor); |
| + Type Ty = Dest->getType(); |
| + // LLVM does the following for dest=src/(1<<log): |
| + // t=src |
| + // sar t,typewidth-1 // -1 if src is negative, 0 if not |
| + // shr t,typewidth-log |
| + // add t,src |
| + // sar t,log |
| + // dest=t |
| + uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty); |
| + _mov(T, Src0); |
| + // If for some reason we are dividing by 1, just treat it |
| + // like an assignment. |
| + if (LogDiv > 0) { |
| + // The initial sar is unnecessary when dividing by 2. |
| + if (LogDiv > 1) |
| + _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1)); |
| + _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv)); |
| + _add(T, Src0); |
| + _sar(T, Ctx->getConstantInt(Ty, LogDiv)); |
| + } |
| + _mov(Dest, T); |
| + return; |
| + } |
| } |
| - _imul(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Shl: |
| - _mov(T, Src0); |
| - if (!llvm::isa<Constant>(Src1)) |
| - Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| - _shl(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Lshr: |
| - _mov(T, Src0); |
| - if (!llvm::isa<Constant>(Src1)) |
| - Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| - _shr(T, Src1); |
| + } |
| + Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| + if (isByteSizedArithType(Dest->getType())) { |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _cbwdq(T, T); |
| + _idiv(T, Src1, T); |
| _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Ashr: |
| - _mov(T, Src0); |
| - if (!llvm::isa<Constant>(Src1)) |
| - Src1 = legalizeToVar(Src1, RegX8632::Reg_ecx); |
| - _sar(T, Src1); |
| + } else { |
| + T_edx = makeReg(IceType_i32, RegX8632::Reg_edx); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _cbwdq(T_edx, T); |
| + _idiv(T, Src1, T_edx); |
| _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Udiv: |
| - // div and idiv are the few arithmetic operators that do not allow |
| - // immediates as the operand. |
| - Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| - if (isByteSizedArithType(Dest->getType())) { |
| - Variable *T_ah = nullptr; |
| - Constant *Zero = Ctx->getConstantZero(IceType_i8); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _mov(T_ah, Zero, RegX8632::Reg_ah); |
| - _div(T, Src1, T_ah); |
| - _mov(Dest, T); |
| - } else { |
| - Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _mov(T_edx, Zero, RegX8632::Reg_edx); |
| - _div(T, Src1, T_edx); |
| - _mov(Dest, T); |
| - } |
| - break; |
| - case InstArithmetic::Sdiv: |
| - Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| - if (isByteSizedArithType(Dest->getType())) { |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _cbwdq(T, T); |
| - _idiv(T, Src1, T); |
| - _mov(Dest, T); |
| - } else { |
| - T_edx = makeReg(IceType_i32, RegX8632::Reg_edx); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _cbwdq(T_edx, T); |
| - _idiv(T, Src1, T_edx); |
| - _mov(Dest, T); |
| - } |
| - break; |
| - case InstArithmetic::Urem: |
| - Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| - if (isByteSizedArithType(Dest->getType())) { |
| - Variable *T_ah = nullptr; |
| - Constant *Zero = Ctx->getConstantZero(IceType_i8); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _mov(T_ah, Zero, RegX8632::Reg_ah); |
| - _div(T_ah, Src1, T); |
| - _mov(Dest, T_ah); |
| - } else { |
| - Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| - _mov(T_edx, Zero, RegX8632::Reg_edx); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _div(T_edx, Src1, T); |
| - _mov(Dest, T_edx); |
| - } |
| - break; |
| - case InstArithmetic::Srem: |
| - Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| - if (isByteSizedArithType(Dest->getType())) { |
| - Variable *T_ah = makeReg(IceType_i8, RegX8632::Reg_ah); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _cbwdq(T, T); |
| - Context.insert(InstFakeDef::create(Func, T_ah)); |
| - _idiv(T_ah, Src1, T); |
| - _mov(Dest, T_ah); |
| - } else { |
| - T_edx = makeReg(IceType_i32, RegX8632::Reg_edx); |
| - _mov(T, Src0, RegX8632::Reg_eax); |
| - _cbwdq(T_edx, T); |
| - _idiv(T_edx, Src1, T); |
| - _mov(Dest, T_edx); |
| + } |
| + break; |
| + case InstArithmetic::Urem: |
| + Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| + if (isByteSizedArithType(Dest->getType())) { |
| + Variable *T_ah = nullptr; |
| + Constant *Zero = Ctx->getConstantZero(IceType_i8); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _mov(T_ah, Zero, RegX8632::Reg_ah); |
| + _div(T_ah, Src1, T); |
| + _mov(Dest, T_ah); |
| + } else { |
| + Constant *Zero = Ctx->getConstantZero(IceType_i32); |
| + _mov(T_edx, Zero, RegX8632::Reg_edx); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _div(T_edx, Src1, T); |
| + _mov(Dest, T_edx); |
| + } |
| + break; |
| + case InstArithmetic::Srem: |
| + // TODO(stichnot): Enable this after doing better performance |
| + // and cross testing. |
| + if (false && Ctx->getFlags().getOptLevel() >= Opt_1) { |
| + // Optimize mod by constant power of 2, but not for Om1 or O0, |
| + // just to keep things simple there. |
| + if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) { |
| + int32_t Divisor = C->getValue(); |
| + uint32_t UDivisor = static_cast<uint32_t>(Divisor); |
| + if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) { |
| + uint32_t LogDiv = llvm::Log2_32(UDivisor); |
| + Type Ty = Dest->getType(); |
| + // LLVM does the following for dest=src%(1<<log): |
| + // t=src |
| + // sar t,typewidth-1 // -1 if src is negative, 0 if not |
| + // shr t,typewidth-log |
| + // add t,src |
| + // and t, -(1<<log) |
| + // sub t,src |
| + // neg t |
| + // dest=t |
| + uint32_t TypeWidth = X86_CHAR_BIT * typeWidthInBytes(Ty); |
| + // If for some reason we are dividing by 1, just assign 0. |
| + if (LogDiv == 0) { |
| + _mov(Dest, Ctx->getConstantZero(Ty)); |
| + return; |
| + } |
| + _mov(T, Src0); |
| + // The initial sar is unnecessary when dividing by 2. |
| + if (LogDiv > 1) |
| + _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1)); |
| + _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv)); |
| + _add(T, Src0); |
| + _and(T, Ctx->getConstantInt(Ty, -(1 << LogDiv))); |
| + _sub(T, Src0); |
| + _neg(T); |
| + _mov(Dest, T); |
| + return; |
| + } |
| } |
| - break; |
| - case InstArithmetic::Fadd: |
| - _mov(T, Src0); |
| - _addss(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Fsub: |
| - _mov(T, Src0); |
| - _subss(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Fmul: |
| - _mov(T, Src0); |
| - _mulss(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Fdiv: |
| - _mov(T, Src0); |
| - _divss(T, Src1); |
| - _mov(Dest, T); |
| - break; |
| - case InstArithmetic::Frem: { |
| - const SizeT MaxSrcs = 2; |
| - Type Ty = Dest->getType(); |
| - InstCall *Call = |
| - makeHelperCall(isFloat32Asserting32Or64(Ty) ? H_frem_f32 : H_frem_f64, |
| - Dest, MaxSrcs); |
| - Call->addArg(Src0); |
| - Call->addArg(Src1); |
| - return lowerCall(Call); |
| - } break; |
| } |
| + Src1 = legalize(Src1, Legal_Reg | Legal_Mem); |
| + if (isByteSizedArithType(Dest->getType())) { |
| + Variable *T_ah = makeReg(IceType_i8, RegX8632::Reg_ah); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _cbwdq(T, T); |
| + Context.insert(InstFakeDef::create(Func, T_ah)); |
| + _idiv(T_ah, Src1, T); |
| + _mov(Dest, T_ah); |
| + } else { |
| + T_edx = makeReg(IceType_i32, RegX8632::Reg_edx); |
| + _mov(T, Src0, RegX8632::Reg_eax); |
| + _cbwdq(T_edx, T); |
| + _idiv(T_edx, Src1, T); |
| + _mov(Dest, T_edx); |
| + } |
| + break; |
| + case InstArithmetic::Fadd: |
| + _mov(T, Src0); |
| + _addss(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Fsub: |
| + _mov(T, Src0); |
| + _subss(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Fmul: |
| + _mov(T, Src0); |
| + _mulss(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Fdiv: |
| + _mov(T, Src0); |
| + _divss(T, Src1); |
| + _mov(Dest, T); |
| + break; |
| + case InstArithmetic::Frem: { |
| + const SizeT MaxSrcs = 2; |
| + Type Ty = Dest->getType(); |
| + InstCall *Call = makeHelperCall( |
| + isFloat32Asserting32Or64(Ty) ? H_frem_f32 : H_frem_f64, Dest, MaxSrcs); |
| + Call->addArg(Src0); |
| + Call->addArg(Src1); |
| + return lowerCall(Call); |
| + } |
| } |
| } |
| @@ -1839,18 +2067,27 @@ void TargetX8632::lowerAssign(const InstAssign *Inst) { |
| _mov(DestHi, T_Hi); |
| } else { |
| Operand *RI; |
| - if (Dest->hasReg()) |
| + if (Dest->hasReg()) { |
| // If Dest already has a physical register, then legalize the |
| // Src operand into a Variable with the same register |
| // assignment. This is mostly a workaround for advanced phi |
| // lowering's ad-hoc register allocation which assumes no |
| // register allocation is needed when at least one of the |
| // operands is non-memory. |
| - RI = legalize(Src0, Legal_Reg, Dest->getRegNum()); |
| - else |
| + |
| + // qining: if we have a physical register for the dest variable, |
| + // we can enable our constant blinding or pooling again. Note |
| + // this is only for advancedPhiLowering(), the flag flip should |
| + // leave no other side effect. |
| + { |
| + BoolFlagSaver B(RandomizationPoolingPaused, false); |
| + RI = legalize(Src0, Legal_Reg, Dest->getRegNum()); |
| + } |
| + } else { |
| // If Dest could be a stack operand, then RI must be a physical |
| // register or a scalar integer immediate. |
| RI = legalize(Src0, Legal_Reg | Legal_Imm); |
| + } |
| if (isVectorType(Dest->getType())) |
| _movp(Dest, RI); |
| else |
| @@ -3119,10 +3356,11 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
| Func->setError("Unexpected memory ordering for AtomicRMW"); |
| return; |
| } |
| - lowerAtomicRMW(Instr->getDest(), |
| - static_cast<uint32_t>(llvm::cast<ConstantInteger32>( |
| - Instr->getArg(0))->getValue()), |
| - Instr->getArg(1), Instr->getArg(2)); |
| + lowerAtomicRMW( |
| + Instr->getDest(), |
| + static_cast<uint32_t>( |
| + llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()), |
| + Instr->getArg(1), Instr->getArg(2)); |
| return; |
| case Intrinsics::AtomicStore: { |
| if (!Intrinsics::isMemoryOrderValid( |
| @@ -4325,6 +4563,10 @@ void TargetX8632::lowerUnreachable(const InstUnreachable * /*Inst*/) { _ud2(); } |
| // turned into zeroes, since loOperand() and hiOperand() don't expect |
| // Undef input. |
| void TargetX8632::prelowerPhis() { |
| + // Pause constant blinding or pooling, blinding or pooling will be done later |
| + // during phi lowering assignments |
| + BoolFlagSaver B(RandomizationPoolingPaused, true); |
| + |
| CfgNode *Node = Context.getNode(); |
| for (Inst &I : Node->getPhis()) { |
| auto Phi = llvm::dyn_cast<InstPhi>(&I); |
| @@ -4424,7 +4666,28 @@ void TargetX8632::lowerPhiAssignments(CfgNode *Node, |
| Context.rewind(); |
| auto Assign = llvm::dyn_cast<InstAssign>(&I); |
| Variable *Dest = Assign->getDest(); |
| + |
| + // qining: Here is an ugly hack for phi.ll test. |
| + // In function test_split_undef_int_vec, the advanced phi |
| + // lowering process will find an assignment of undefined |
| + // vector. This vector, as the Src here, will crash if it |
| + // go through legalize(). legalize() will create new variable |
| + // with makeVectorOfZeros(), but this new variable will be |
| + // assigned a stack slot. This will fail the assertion in |
| + // IceInstX8632.cpp:789, as XmmEmitterRegOp() complain: |
| + // Var->hasReg() fails. Note this failure is irrelevant to |
| + // randomization or pooling of constants. |
| + // So, we do not call legalize() to add pool label for the |
| + // src operands of phi assignment instructions. |
| + // Instead, we manually add pool label for constant float and |
| + // constant double values here. |
| + // Note going through legalize() does not affect the testing |
| + // results of SPEC2K and xtests. |
| Operand *Src = Assign->getSrc(0); |
| + if (!llvm::isa<ConstantUndef>(Assign->getSrc(0))) { |
| + Src = legalize(Src); |
| + } |
| + |
| Variable *SrcVar = llvm::dyn_cast<Variable>(Src); |
| // Use normal assignment lowering, except lower mem=mem specially |
| // so we can register-allocate at the same time. |
| @@ -4600,6 +4863,7 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
| // work, e.g. allow the shl shift amount to be either an immediate |
| // or in ecx.) |
| assert(RegNum == Variable::NoRegister || Allowed == Legal_Reg); |
| + |
| if (auto Mem = llvm::dyn_cast<OperandX8632Mem>(From)) { |
| // Before doing anything with a Mem operand, we need to ensure |
| // that the Base and Index components are in physical registers. |
| @@ -4614,11 +4878,14 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
| RegIndex = legalizeToVar(Index); |
| } |
| if (Base != RegBase || Index != RegIndex) { |
| - From = |
| + Mem = |
| OperandX8632Mem::create(Func, Ty, RegBase, Mem->getOffset(), RegIndex, |
| Mem->getShift(), Mem->getSegmentRegister()); |
| } |
| + // qining: For all Memory Operands, we do randomization/pooling here |
| + From = randomizeOrPoolImmediate(Mem); |
| + |
| if (!(Allowed & Legal_Mem)) { |
| From = copyToReg(From, RegNum); |
| } |
| @@ -4643,6 +4910,16 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
| } |
| // There should be no constants of vector type (other than undef). |
| assert(!isVectorType(Ty)); |
| + |
| + // If the operand is an 32 bit constant integer, we should check |
| + // whether we need to randomize it or pool it. |
| + if (ConstantInteger32 *C = llvm::dyn_cast<ConstantInteger32>(From)) { |
| + Operand *NewFrom = randomizeOrPoolImmediate(C, RegNum); |
| + if (NewFrom != From) { |
| + return NewFrom; |
| + } |
| + } |
| + |
| // Convert a scalar floating point constant into an explicit |
| // memory operand. |
| if (isScalarFloatingType(Ty)) { |
| @@ -4650,6 +4927,7 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
| std::string Buffer; |
| llvm::raw_string_ostream StrBuf(Buffer); |
| llvm::cast<Constant>(From)->emitPoolLabel(StrBuf); |
| + llvm::cast<Constant>(From)->shouldBePooled = true; |
| Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); |
| From = OperandX8632Mem::create(Func, Ty, Base, Offset); |
| } |
| @@ -4706,25 +4984,38 @@ Operand *TargetX8632::legalizeSrc0ForCmp(Operand *Src0, Operand *Src1) { |
| return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg); |
| } |
| -OperandX8632Mem *TargetX8632::formMemoryOperand(Operand *Operand, Type Ty, |
| +OperandX8632Mem *TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty, |
| bool DoLegalize) { |
| - OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand); |
| + OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Opnd); |
| // It may be the case that address mode optimization already creates |
| // an OperandX8632Mem, so in that case it wouldn't need another level |
| // of transformation. |
| if (!Mem) { |
| - Variable *Base = llvm::dyn_cast<Variable>(Operand); |
| - Constant *Offset = llvm::dyn_cast<Constant>(Operand); |
| + Variable *Base = llvm::dyn_cast<Variable>(Opnd); |
| + Constant *Offset = llvm::dyn_cast<Constant>(Opnd); |
| assert(Base || Offset); |
| if (Offset) { |
| - // Make sure Offset is not undef. |
| - Offset = llvm::cast<Constant>(legalize(Offset)); |
| + // qining: during memory operand building, we do not |
| + // blind or pool the constant offset, we will work on |
| + // the whole memory operand later as one entity later, |
| + // this save one instruction. By turning blinding and |
| + // pooling off, we guarantee legalize(Offset) will return |
| + // a constant* |
| + { |
| + BoolFlagSaver B(RandomizationPoolingPaused, true); |
| + |
| + Offset = llvm::cast<Constant>(legalize(Offset)); |
| + } |
| + |
| assert(llvm::isa<ConstantInteger32>(Offset) || |
| llvm::isa<ConstantRelocatable>(Offset)); |
| } |
| Mem = OperandX8632Mem::create(Func, Ty, Base, Offset); |
| } |
| - return llvm::cast<OperandX8632Mem>(DoLegalize ? legalize(Mem) : Mem); |
| + // qining: do legalization, which contains randomization/pooling |
| + // or do randomization/pooling. |
| + return llvm::cast<OperandX8632Mem>( |
| + DoLegalize ? legalize(Mem) : randomizeOrPoolImmediate(Mem)); |
| } |
| Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) { |
| @@ -4965,6 +5256,45 @@ const char *PoolTypeConverter<double>::TypeName = "double"; |
| const char *PoolTypeConverter<double>::AsmTag = ".quad"; |
| const char *PoolTypeConverter<double>::PrintfString = "0x%llx"; |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<int> { |
|
Jim Stichnoth
2015/06/19 16:51:03
Please use uint32_t/uint16_t/uint8_t instead of in
qining
2015/06/19 20:22:26
Done. I think both signed and unsigned should be f
|
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i32; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<int>::TypeName = "i32"; |
| +const char *PoolTypeConverter<int>::AsmTag = ".long"; |
| +const char *PoolTypeConverter<int>::PrintfString = "0x%x"; |
| + |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<short> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i16; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<short>::TypeName = "i16"; |
| +const char *PoolTypeConverter<short>::AsmTag = ".short"; |
| +const char *PoolTypeConverter<short>::PrintfString = "0x%x"; |
| + |
| +// Add converter for int type constant pooling |
| +template <> struct PoolTypeConverter<char> { |
| + typedef uint32_t PrimitiveIntType; |
| + typedef ConstantInteger32 IceType; |
| + static const Type Ty = IceType_i8; |
| + static const char *TypeName; |
| + static const char *AsmTag; |
| + static const char *PrintfString; |
| +}; |
| +const char *PoolTypeConverter<char>::TypeName = "i8"; |
| +const char *PoolTypeConverter<char>::AsmTag = ".byte"; |
| +const char *PoolTypeConverter<char>::PrintfString = "0x%x"; |
| + |
| template <typename T> |
| void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) { |
| if (!ALLOW_DUMP) |
| @@ -4978,6 +5308,8 @@ void TargetDataX8632::emitConstantPool(GlobalContext *Ctx) { |
| << "\n"; |
| Str << "\t.align\t" << Align << "\n"; |
| for (Constant *C : Pool) { |
| + if (!C->shouldBePooled) |
| + continue; |
| typename T::IceType *Const = llvm::cast<typename T::IceType>(C); |
| typename T::IceType::PrimType Value = Const->getValue(); |
| // Use memcpy() to copy bits from Value into RawValue in a way |
| @@ -5004,12 +5336,22 @@ void TargetDataX8632::lowerConstants() const { |
| switch (Ctx->getFlags().getOutFileType()) { |
| case FT_Elf: { |
| ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
| + |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i8); |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i16); |
| + Writer->writeConstantPool<ConstantInteger32>(IceType_i32); |
| + |
| Writer->writeConstantPool<ConstantFloat>(IceType_f32); |
| Writer->writeConstantPool<ConstantDouble>(IceType_f64); |
| } break; |
| case FT_Asm: |
| case FT_Iasm: { |
| OstreamLocker L(Ctx); |
| + |
| + emitConstantPool<PoolTypeConverter<char>>(Ctx); |
| + emitConstantPool<PoolTypeConverter<short>>(Ctx); |
| + emitConstantPool<PoolTypeConverter<int>>(Ctx); |
| + |
| emitConstantPool<PoolTypeConverter<float>>(Ctx); |
| emitConstantPool<PoolTypeConverter<double>>(Ctx); |
| } break; |
| @@ -5019,4 +5361,197 @@ void TargetDataX8632::lowerConstants() const { |
| TargetHeaderX8632::TargetHeaderX8632(GlobalContext *Ctx) |
| : TargetHeaderLowering(Ctx) {} |
| +// Blind/pool an Immediate |
| +Operand *TargetX8632::randomizeOrPoolImmediate(Constant *Immediate, |
| + int32_t RegNum) { |
| + assert(llvm::isa<ConstantInteger32>(Immediate) || |
| + llvm::isa<ConstantRelocatable>(Immediate)); |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None || |
| + RandomizationPoolingPaused == true) { |
| + // immediates randomization/pool turned off |
| + return Immediate; |
| + } |
| + if (Constant *C = llvm::dyn_cast_or_null<Constant>(Immediate)) { |
| + if (C->shouldBeRandomizedOrPooled(Ctx)) { |
| + Ctx->statsUpdateRPImms(); |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == |
| + RPI_Randomize) { |
| + // blind the constant |
| + // FROM: |
| + // imm |
| + // TO: |
| + // insert: mov imm+cookie, Reg |
| + // insert: lea -cookie[Reg], Reg |
|
Jim Stichnoth
2015/06/19 16:51:03
Explain in a comment that lea is used (as opposed
qining
2015/06/19 20:22:26
Done.
|
| + // => Reg |
| + // If we have already assigned a phy register, we must come from |
| + // andvancedPhiLowering()=>lowerAssign(). In this case we should reuse |
| + // the assigned register as this assignment is that start of its use-def |
| + // chain. So we add RegNum argument here. |
| + Variable *Reg = makeReg(IceType_i32, RegNum); |
| + ConstantInteger32 *Integer = llvm::cast<ConstantInteger32>(Immediate); |
| + uint32_t Value = Integer->getValue(); |
| + uint32_t Cookie = Ctx->getRandomizationCookie(); |
| + _mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value)); |
| + Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie); |
| + _lea(Reg, |
| + OperandX8632Mem::create(Func, IceType_i32, Reg, Offset, NULL, 0)); |
|
Jim Stichnoth
2015/06/19 16:51:03
nullptr
qining
2015/06/19 20:22:26
Done.
|
| + // make sure liveness analysis won't kill this variable, otherwise a |
| + // liveness |
| + // assertion will be triggered. |
| + _set_dest_nonkillable(); |
| + if (Immediate->getType() != IceType_i32) { |
| + Variable *TruncReg = makeReg(Immediate->getType(), RegNum); |
| + _mov(TruncReg, Reg); |
| + return TruncReg; |
| + } |
| + return Reg; |
| + } |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool) { |
| + // pool the constant |
| + // FROM: |
| + // imm |
| + // TO: |
| + // insert: mov $label, Reg |
| + // => Reg |
| + assert(Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == |
| + RPI_Pool); |
| + Immediate->shouldBePooled = true; |
| + // if we have already assigned a phy register, we must come from |
| + // andvancedPhiLowering()=>lowerAssign(). In this case we should reuse |
| + // the assigned register as this assignment is that start of its use-def |
| + // chain. So we add RegNum argument here. |
| + Variable *Reg = makeReg(Immediate->getType(), RegNum); |
| + IceString Label; |
| + llvm::raw_string_ostream Label_stream(Label); |
| + Immediate->emitPoolLabel(Label_stream); |
| + const RelocOffsetT Offset = 0; |
| + const bool SuppressMangling = true; |
| + Constant *Symbol = |
| + Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); |
| + OperandX8632Mem *MemOperand = |
| + OperandX8632Mem::create(Func, Immediate->getType(), NULL, Symbol); |
| + _mov(Reg, MemOperand); |
| + return Reg; |
| + } |
| + assert("Unsupported -randomize-pool-immediates option" && false); |
| + } |
| + } |
| + // the constant Immediate is not eligible for blinding/pooling |
| + return Immediate; |
| +} |
| + |
| +OperandX8632Mem * |
| +TargetX8632::randomizeOrPoolImmediate(OperandX8632Mem *MemOperand, |
| + int32_t RegNum) { |
| + assert(MemOperand); |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None || |
| + RandomizationPoolingPaused == true) { |
| + // immediates randomization/pooling is turned off |
| + return MemOperand; |
| + } |
| + |
| + if (Constant *C = llvm::dyn_cast_or_null<Constant>(MemOperand->getOffset())) { |
| + if (C->shouldBeRandomizedOrPooled(Ctx)) { |
| + // The offset of this mem operand should be blinded or pooled |
| + Ctx->statsUpdateRPImms(); |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == |
| + RPI_Randomize) { |
| + // blind the constant offset |
| + // FROM: |
| + // offset[base, index, shift] |
| + // TO: |
| + // insert: lea offset+cookie[base], RegTemp |
| + // => -cookie[RegTemp, index, shift] |
| + uint32_t Value = |
| + llvm::dyn_cast<ConstantInteger32>(MemOperand->getOffset()) |
| + ->getValue(); |
| + uint32_t Cookie = Ctx->getRandomizationCookie(); |
| + Constant *Mask1 = Ctx->getConstantInt( |
| + MemOperand->getOffset()->getType(), Cookie + Value); |
| + Constant *Mask2 = |
| + Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie); |
| + |
| + // qining: if the offset value is -cookie, this memory operand should |
| + // have already been randomized, we just return it. |
| + if(Value == -Cookie) return MemOperand; |
|
Jim Stichnoth
2015/06/19 16:51:03
make format
Also, there's an interesting one-in-f
qining
2015/06/19 20:22:25
I think Cookie==MIN_INT should still be fine.
Ass
|
| + |
| + // qining: We need to make sure the MemOperand->getBase() has a physical |
| + // register, if it is a variable! |
| + if (MemOperand->getBase() != NULL) |
| + MemOperand->getBase()->setWeightInfinite(); |
| + OperandX8632Mem *TempMemOperand = OperandX8632Mem::create( |
| + Func, MemOperand->getType(), MemOperand->getBase(), Mask1); |
| + // If we have already assigned a physical register, we must come from |
| + // advancedPhiLowering()=>lowerAssign(). In this case we should reuse |
| + // the assigned register as this assignment is that start of its use-def |
| + // chain. So we add RegNum argument here. |
| + Variable *RegTemp = makeReg(MemOperand->getOffset()->getType(), RegNum); |
| + _lea(RegTemp, TempMemOperand); |
| + // As source operand doesn't use the dstreg, we don't need to add |
| + // _set_dest_nonkillable(). |
| + // qining: but if we use the same Dest Reg, that is, with RegNum |
| + // assigned, we should add this _set_dest_nonkillable() |
| + if (RegNum != Variable::NoRegister) |
| + _set_dest_nonkillable(); |
| + |
| + OperandX8632Mem *NewMemOperand = OperandX8632Mem::create( |
| + Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(), |
| + MemOperand->getShift(), MemOperand->getSegmentRegister()); |
| + |
| + return NewMemOperand; |
| + } |
| + if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool) { |
| + // pool the constant offset |
| + // FROM: |
| + // offset[base, index, shift] |
| + // TO: |
| + // insert: mov $label, RegTemp |
| + // insert: lea [base, RegTemp], RegTemp |
| + // =>[RegTemp, index, shift] |
| + assert(Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == |
| + RPI_Pool); |
| + // qining: Mem operand should never exist as source operands in phi |
| + // lowering |
| + // assignments, so there is no need to reuse any registers here. |
| + // However, for phi lowering, we should not ask for new physical |
| + // registers in general. |
| + // However, if we do meet MemOperand during phi lowering, we should not |
| + // blind or pool the immediates for now |
| + if (RegNum != Variable::NoRegister) |
| + return MemOperand; |
| + Variable *RegTemp = makeReg(IceType_i32); |
| + IceString Label; |
| + llvm::raw_string_ostream Label_stream(Label); |
| + MemOperand->getOffset()->emitPoolLabel(Label_stream); |
| + MemOperand->getOffset()->shouldBePooled = true; |
| + const RelocOffsetT SymOffset = 0; |
| + bool SuppressMangling = true; |
| + Constant *Symbol = Ctx->getConstantSym(SymOffset, Label_stream.str(), |
| + SuppressMangling); |
| + OperandX8632Mem *SymbolOperand = OperandX8632Mem::create( |
| + Func, MemOperand->getOffset()->getType(), NULL, Symbol); |
| + _mov(RegTemp, SymbolOperand); |
| + // qining: We need to make sure the MemOperand->getBase() has a physical |
| + // register! If we do not have base register here, we won't need an |
| + // extra lea instruction anymore. |
| + if (MemOperand->getBase()) { |
| + OperandX8632Mem *CalculateOperand = OperandX8632Mem::create( |
| + Func, MemOperand->getType(), MemOperand->getBase(), NULL, RegTemp, |
| + 0, MemOperand->getSegmentRegister()); |
| + _lea(RegTemp, CalculateOperand); |
| + _set_dest_nonkillable(); |
| + } |
| + OperandX8632Mem *NewMemOperand = OperandX8632Mem::create( |
| + Func, MemOperand->getType(), RegTemp, NULL, MemOperand->getIndex(), |
| + MemOperand->getShift(), MemOperand->getSegmentRegister()); |
| + return NewMemOperand; |
| + } |
| + assert("Unsupported -randomize-pool-immediates option" && false); |
| + } |
| + } |
| + // the offset is not eligible for blinding or pooling, return the original |
| + // mem operand |
| + return MemOperand; |
| +} |
| + |
| } // end of namespace Ice |