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

Unified Diff: src/IceTargetLoweringX8632.cpp

Issue 1185703004: Add constant blinding/pooling option for X8632 code translation (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Avoid calling randomizationOrPoolImmediate() multiple times on a same operand" Created 5 years, 6 months 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/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

Powered by Google App Engine
This is Rietveld 408576698