Chromium Code Reviews| Index: src/IceTargetLoweringX86BaseImpl.h |
| diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h |
| index 8739c77ac8e99351c19df3736faed4789cbc5be1..4e9449ae0a124fa9d3504625ef89ad2c1f37dd0a 100644 |
| --- a/src/IceTargetLoweringX86BaseImpl.h |
| +++ b/src/IceTargetLoweringX86BaseImpl.h |
| @@ -797,8 +797,9 @@ TargetX86Base<Machine>::stackVarToAsmOperand(const Variable *Var) const { |
| if (!hasFramePointer()) |
| Offset += getStackAdjustment(); |
| } |
| + static constexpr AssemblerFixup *Fixup = nullptr; |
| return typename Traits::Address( |
| - Traits::RegisterSet::getEncodedGPR(BaseRegNum), Offset); |
| + Traits::RegisterSet::getEncodedGPR(BaseRegNum), Offset, Fixup); |
| } |
| /// Helper function for addProlog(). |
| @@ -2851,15 +2852,19 @@ TargetX86Base<Machine>::lowerIcmp64(const InstIcmp *Icmp, const InstBr *Br) { |
| break; |
| case InstIcmp::Eq: |
| case InstIcmp::Ule: |
| - _mov(Temp, Src0LoRM); |
| - _or(Temp, Src0HiRM); |
| + // Mov Src0HiRM first, because it was legalized most recently, and will |
| + // sometimes avoid a move before the OR. |
| + _mov(Temp, Src0HiRM); |
| + _or(Temp, Src0LoRM); |
| Context.insert(InstFakeUse::create(Func, Temp)); |
| setccOrBr(Traits::Cond::Br_e, Dest, Br); |
| return; |
| case InstIcmp::Ne: |
| case InstIcmp::Ugt: |
| - _mov(Temp, Src0LoRM); |
| - _or(Temp, Src0HiRM); |
| + // Mov Src0HiRM first, because it was legalized most recently, and will |
| + // sometimes avoid a move before the OR. |
| + _mov(Temp, Src0HiRM); |
| + _or(Temp, Src0LoRM); |
| Context.insert(InstFakeUse::create(Func, Temp)); |
| setccOrBr(Traits::Cond::Br_ne, Dest, Br); |
| return; |
| @@ -4094,16 +4099,17 @@ void TargetX86Base<Machine>::lowerIndirectJump(Variable *Target) { |
| } |
| inline bool isAdd(const Inst *Inst) { |
| - if (const InstArithmetic *Arith = |
| - llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { |
| + if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { |
| return (Arith->getOp() == InstArithmetic::Add); |
| } |
| return false; |
| } |
| -inline void dumpAddressOpt(const Cfg *Func, const Variable *Base, |
| +inline void dumpAddressOpt(const Cfg *Func, |
| + const ConstantRelocatable *Relocatable, |
| + int32_t Offset, const Variable *Base, |
| const Variable *Index, uint16_t Shift, |
| - int32_t Offset, const Inst *Reason) { |
| + const Inst *Reason) { |
| if (!BuildDefs::dump()) |
| return; |
| if (!Func->isVerbose(IceV_AddrOpt)) |
| @@ -4122,11 +4128,13 @@ inline void dumpAddressOpt(const Cfg *Func, const Variable *Base, |
| Index->dump(Func); |
| else |
| Str << "<null>"; |
| - Str << ", Shift=" << Shift << ", Offset=" << Offset << "\n"; |
| + Str << ", Shift=" << Shift << ", Offset=" << Offset |
| + << ", Relocatable=" << Relocatable << "\n"; |
| } |
| -inline bool matchTransitiveAssign(const VariablesMetadata *VMetadata, |
| - Variable *&Var, const Inst *&Reason) { |
| +inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *&Var, |
| + ConstantRelocatable *&Relocatable, int32_t &Offset, |
| + const Inst *&Reason) { |
| // Var originates from Var=SrcVar ==> set Var:=SrcVar |
| if (Var == nullptr) |
| return false; |
| @@ -4135,7 +4143,7 @@ inline bool matchTransitiveAssign(const VariablesMetadata *VMetadata, |
| if (llvm::isa<InstAssign>(VarAssign)) { |
| Operand *SrcOp = VarAssign->getSrc(0); |
| assert(SrcOp); |
| - if (Variable *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { |
| + if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { |
| if (!VMetadata->isMultiDef(SrcVar) && |
| // TODO: ensure SrcVar stays single-BB |
| true) { |
| @@ -4143,6 +4151,21 @@ inline bool matchTransitiveAssign(const VariablesMetadata *VMetadata, |
| Reason = VarAssign; |
| return true; |
| } |
| + } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { |
| + int32_t MoreOffset = Const->getValue(); |
| + if (Utils::WouldOverflowAdd(Offset, MoreOffset)) |
| + return false; |
| + Var = nullptr; |
| + Offset += MoreOffset; |
| + Reason = VarAssign; |
| + return true; |
| + } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) { |
| + if (Relocatable == nullptr) { |
| + Var = nullptr; |
| + Relocatable = AddReloc; |
| + Reason = VarAssign; |
| + return true; |
| + } |
| } |
| } |
| } |
| @@ -4158,16 +4181,16 @@ inline bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, |
| return false; |
| if (Index != nullptr) |
| return false; |
| - const Inst *BaseInst = VMetadata->getSingleDefinition(Base); |
| + auto *BaseInst = VMetadata->getSingleDefinition(Base); |
| if (BaseInst == nullptr) |
| return false; |
| assert(!VMetadata->isMultiDef(Base)); |
| if (BaseInst->getSrcSize() < 2) |
| return false; |
| - if (Variable *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { |
| + if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { |
| if (VMetadata->isMultiDef(Var1)) |
| return false; |
| - if (Variable *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { |
| + if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { |
| if (VMetadata->isMultiDef(Var2)) |
| return false; |
| if (isAdd(BaseInst) && |
| @@ -4191,20 +4214,23 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
| // Index=Var, Shift+=log2(Const) |
| if (Index == nullptr) |
| return false; |
| - const Inst *IndexInst = VMetadata->getSingleDefinition(Index); |
| + auto *IndexInst = VMetadata->getSingleDefinition(Index); |
| if (IndexInst == nullptr) |
| return false; |
| assert(!VMetadata->isMultiDef(Index)); |
| if (IndexInst->getSrcSize() < 2) |
| return false; |
| - if (const InstArithmetic *ArithInst = |
| - llvm::dyn_cast<InstArithmetic>(IndexInst)) { |
| - if (Variable *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { |
| - if (ConstantInteger32 *Const = |
| + if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) { |
| + if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { |
| + if (auto *Const = |
| llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) { |
| - if (ArithInst->getOp() == InstArithmetic::Mul && |
| - !VMetadata->isMultiDef(Var) && Const->getType() == IceType_i32) { |
| - uint64_t Mult = Const->getValue(); |
| + if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) |
| + return false; |
| + switch (ArithInst->getOp()) { |
| + default: |
| + return false; |
| + case InstArithmetic::Mul: { |
| + uint32_t Mult = Const->getValue(); |
| uint32_t LogMult; |
| switch (Mult) { |
| case 1: |
| @@ -4229,6 +4255,25 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
| return true; |
| } |
| } |
| + case InstArithmetic::Shl: { |
| + uint32_t ShiftAmount = Const->getValue(); |
| + switch (ShiftAmount) { |
| + case 0: |
| + case 1: |
| + case 2: |
| + case 3: |
| + break; |
| + default: |
| + return false; |
| + } |
| + if (Shift + ShiftAmount <= 3) { |
| + Index = Var; |
| + Shift += ShiftAmount; |
| + Reason = IndexInst; |
| + return true; |
| + } |
| + } |
| + } |
| } |
| } |
| } |
| @@ -4236,49 +4281,93 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
| } |
| inline bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable *&Base, |
| - int32_t &Offset, const Inst *&Reason) { |
| + ConstantRelocatable *&Relocatable, int32_t &Offset, |
| + const Inst *&Reason) { |
| // Base is Base=Var+Const || Base is Base=Const+Var ==> |
| // set Base=Var, Offset+=Const |
| // Base is Base=Var-Const ==> |
| // set Base=Var, Offset-=Const |
| - if (Base == nullptr) |
| + if (Base == nullptr) { |
| return false; |
| + } |
| const Inst *BaseInst = VMetadata->getSingleDefinition(Base); |
| - if (BaseInst == nullptr) |
| + if (BaseInst == nullptr) { |
| return false; |
| + } |
| assert(!VMetadata->isMultiDef(Base)); |
| - if (const InstArithmetic *ArithInst = |
| - llvm::dyn_cast<const InstArithmetic>(BaseInst)) { |
| + if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst)) { |
| if (ArithInst->getOp() != InstArithmetic::Add && |
| ArithInst->getOp() != InstArithmetic::Sub) |
| return false; |
| bool IsAdd = ArithInst->getOp() == InstArithmetic::Add; |
| - Variable *Var = nullptr; |
| - ConstantInteger32 *Const = nullptr; |
| - if (Variable *VariableOperand = |
| - llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { |
| - Var = VariableOperand; |
| - Const = llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1)); |
| - } else if (IsAdd) { |
| - Const = llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(0)); |
| - Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(1)); |
| - } |
| - if (Var == nullptr || Const == nullptr || VMetadata->isMultiDef(Var)) |
| + Operand *Src0 = ArithInst->getSrc(0); |
| + Operand *Src1 = ArithInst->getSrc(1); |
| + auto *Var0 = llvm::dyn_cast<Variable>(Src0); |
| + auto *Var1 = llvm::dyn_cast<Variable>(Src1); |
| + auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0); |
| + auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1); |
| + auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0); |
| + auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1); |
| + Variable *NewBase = nullptr; |
| + int32_t NewOffset = Offset; |
| + ConstantRelocatable *NewRelocatable = Relocatable; |
| + if (Var0 && Var1) |
| + // TODO(sehr): merge base/index splitting into here. |
| return false; |
| - int32_t MoreOffset = IsAdd ? Const->getValue() : -Const->getValue(); |
| - if (Utils::WouldOverflowAdd(Offset, MoreOffset)) |
| + else if (!IsAdd && Var1) |
|
Jim Stichnoth
2015/10/27 22:19:52
Don't use "else" after "if (...) return;".
(here a
sehr
2015/10/27 23:24:05
Done.
|
| return false; |
| - Base = Var; |
| - Offset += MoreOffset; |
| + else if (Var0) |
| + NewBase = Var0; |
| + else if (Var1) |
| + NewBase = Var1; |
| + // Don't know how to add/subtract two relocatables. |
| + if ((Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) |
| + return false; |
| + // Don't know how to subtract a relocatable. |
| + if (!IsAdd && Reloc1) |
| + return false; |
| + // Incorporate ConstantRelocatables. |
| + if (Reloc0) |
| + NewRelocatable = Reloc0; |
| + else if (Reloc1) |
| + NewRelocatable = Reloc1; |
| + // Compute the updated constant offset. |
| + if (Const0) { |
| + int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue(); |
| + if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| + return false; |
| + NewOffset += MoreOffset; |
| + } |
| + if (Const1) { |
| + int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue(); |
| + if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| + return false; |
| + NewOffset += MoreOffset; |
| + } |
| + // Update the computed address parameters once we are sure optimization |
| + // is valid. |
| + Base = NewBase; |
| + Offset = NewOffset; |
| + Relocatable = NewRelocatable; |
| Reason = BaseInst; |
| return true; |
| } |
| return false; |
| } |
| -inline void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base, |
| - Variable *&Index, uint16_t &Shift, |
| - int32_t &Offset) { |
| +// Builds information for a canonical address expresion: |
| +// <Relocatable + Offset>(Base, Index, Shift) |
| +// On entry: |
| +// Relocatable == null, |
| +// Offset == 0, |
| +// Base is a Variable, |
| +// Index == nullptr, |
| +// Shift == 0 |
| +inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, |
| + ConstantRelocatable *&Relocatable, |
| + int32_t &Offset, Variable *&Base, |
| + Variable *&Index, uint16_t &Shift) { |
| + bool AddressWasOptimized = false; |
| Func->resetCurrentNode(); |
| if (Func->isVerbose(IceV_AddrOpt)) { |
| OstreamLocker L(Func->getContext()); |
| @@ -4286,54 +4375,75 @@ inline void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base, |
| Str << "\nStarting computeAddressOpt for instruction:\n "; |
| Instr->dumpDecorated(Func); |
| } |
| - (void)Offset; // TODO: pattern-match for non-zero offsets. |
| if (Base == nullptr) |
| - return; |
| + return AddressWasOptimized; |
| // If the Base has more than one use or is live across multiple blocks, then |
| // don't go further. Alternatively (?), never consider a transformation that |
| // would change a variable that is currently *not* live across basic block |
| // boundaries into one that *is*. |
| if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/) |
| - return; |
| + return AddressWasOptimized; |
| const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck(); |
| const VariablesMetadata *VMetadata = Func->getVMetadata(); |
| - bool Continue = true; |
| - while (Continue) { |
| - const Inst *Reason = nullptr; |
| - if (matchTransitiveAssign(VMetadata, Base, Reason) || |
| - matchTransitiveAssign(VMetadata, Index, Reason) || |
| - (!MockBounds && |
| - matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) || |
| - (!MockBounds && matchShiftedIndex(VMetadata, Index, Shift, Reason)) || |
| - matchOffsetBase(VMetadata, Base, Offset, Reason)) { |
| - dumpAddressOpt(Func, Base, Index, Shift, Offset, Reason); |
| - } else { |
| - Continue = false; |
| + const Inst *Reason = nullptr; |
| + do { |
| + if (Reason) { |
| + dumpAddressOpt(Func, Relocatable, Offset, Base, Index, Shift, Reason); |
| + AddressWasOptimized = true; |
| + Reason = nullptr; |
| } |
| + // Update Base and Index to follow through assignments to definitions. |
| + if (matchAssign(VMetadata, Base, Relocatable, Offset, Reason)) { |
| + // Assignments of Base from a Relocatable or ConstantInt32 can result |
| + // in Base becoming nullptr. To avoid code duplication in this loop we |
| + // prefer that Base be non-nullptr if possible. |
| + if ((Base == nullptr) && (Index != nullptr) && (Shift == 0)) |
| + std::swap(Base, Index); |
| + continue; |
| + } |
| + if (matchAssign(VMetadata, Index, Relocatable, Offset, Reason)) |
| + continue; |
| - // Index is Index=Var<<Const && Const+Shift<=3 ==> |
| - // Index=Var, Shift+=Const |
| - |
| - // Index is Index=Const*Var && log2(Const)+Shift<=3 ==> |
| - // Index=Var, Shift+=log2(Const) |
| - |
| - // Index && Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> |
| - // swap(Index,Base) |
| - // Similar for Base=Const*Var and Base=Var<<Const |
| - |
| + if (!MockBounds) { |
| + // Transition from: |
| + // <Relocatable + Offset>(Base) to |
| + // <Relocatable + Offset>(Base, Index) |
| + if (matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) |
| + continue; |
| + // Recognize multiply/shift and update Shift amount. |
| + // Index becomes Index=Var<<Const && Const+Shift<=3 ==> |
| + // Index=Var, Shift+=Const |
| + // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==> |
| + // Index=Var, Shift+=log2(Const) |
| + if (matchShiftedIndex(VMetadata, Index, Shift, Reason)) |
| + continue; |
| + // If Shift is zero, the choice of Base and Index was purely arbitrary. |
| + // Recognize multiply/shift and set Shift amount. |
| + // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> |
| + // swap(Index,Base) |
| + // Similar for Base=Const*Var and Base=Var<<Const |
| + if ((Shift == 0) && matchShiftedIndex(VMetadata, Base, Shift, Reason)) { |
| + std::swap(Base, Index); |
| + continue; |
| + } |
| + } |
| + // Update Offset to reflect additions/subtractions with constants and |
| + // relocatables. |
| + // TODO: consider overflow issues with respect to Offset. |
| + // TODO: handle symbolic constants. |
| + if (matchOffsetBase(VMetadata, Base, Relocatable, Offset, Reason)) |
| + continue; |
| + // TODO(sehr, stichnot): Handle updates of Index with Shift != 0. |
| // Index is Index=Var+Const ==> |
| // set Index=Var, Offset+=(Const<<Shift) |
| - |
| // Index is Index=Const+Var ==> |
| // set Index=Var, Offset+=(Const<<Shift) |
| - |
| // Index is Index=Var-Const ==> |
| // set Index=Var, Offset-=(Const<<Shift) |
| - |
| - // TODO: consider overflow issues with respect to Offset. |
| - // TODO: handle symbolic constants. |
| - } |
| + break; |
| + } while (Reason); |
| + return AddressWasOptimized; |
| } |
| /// Add a mock bounds check on the memory address before using it as a load or |
| @@ -4415,19 +4525,26 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() { |
| Variable *Dest = Inst->getDest(); |
| Operand *Addr = Inst->getSrc(0); |
| Variable *Index = nullptr; |
| + ConstantRelocatable *Relocatable = nullptr; |
| uint16_t Shift = 0; |
| - int32_t Offset = 0; // TODO: make Constant |
| + int32_t Offset = 0; |
| // Vanilla ICE load instructions should not use the segment registers, and |
| // computeAddressOpt only works at the level of Variables and Constants, not |
| // other Traits::X86OperandMem, so there should be no mention of segment |
| // registers there either. |
| const typename Traits::X86OperandMem::SegmentRegisters SegmentReg = |
| Traits::X86OperandMem::DefaultSegment; |
| - Variable *Base = llvm::dyn_cast<Variable>(Addr); |
| - computeAddressOpt(Func, Inst, Base, Index, Shift, Offset); |
| - if (Base && Addr != Base) { |
| + auto *Base = llvm::dyn_cast<Variable>(Addr); |
| + if (computeAddressOpt(Func, Inst, Relocatable, Offset, Base, Index, Shift)) { |
| Inst->setDeleted(); |
| - Constant *OffsetOp = Ctx->getConstantInt32(Offset); |
| + Constant *OffsetOp = nullptr; |
| + if (Relocatable == nullptr) { |
| + OffsetOp = Ctx->getConstantInt32(Offset); |
| + } else { |
| + OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, |
| + Relocatable->getName(), |
| + Relocatable->getSuppressMangling()); |
| + } |
| Addr = Traits::X86OperandMem::create(Func, Dest->getType(), Base, OffsetOp, |
| Index, Shift, SegmentReg); |
| Context.insert(InstLoad::create(Func, Dest, Addr)); |
| @@ -4623,19 +4740,26 @@ template <class Machine> void TargetX86Base<Machine>::doAddressOptStore() { |
| Operand *Data = Inst->getData(); |
| Operand *Addr = Inst->getAddr(); |
| Variable *Index = nullptr; |
| + ConstantRelocatable *Relocatable = nullptr; |
| uint16_t Shift = 0; |
| - int32_t Offset = 0; // TODO: make Constant |
| - Variable *Base = llvm::dyn_cast<Variable>(Addr); |
| + int32_t Offset = 0; |
| + auto *Base = llvm::dyn_cast<Variable>(Addr); |
| // Vanilla ICE store instructions should not use the segment registers, and |
| // computeAddressOpt only works at the level of Variables and Constants, not |
| // other Traits::X86OperandMem, so there should be no mention of segment |
| // registers there either. |
| const typename Traits::X86OperandMem::SegmentRegisters SegmentReg = |
| Traits::X86OperandMem::DefaultSegment; |
| - computeAddressOpt(Func, Inst, Base, Index, Shift, Offset); |
| - if (Base && Addr != Base) { |
| + if (computeAddressOpt(Func, Inst, Relocatable, Offset, Base, Index, Shift)) { |
| Inst->setDeleted(); |
| - Constant *OffsetOp = Ctx->getConstantInt32(Offset); |
| + Constant *OffsetOp = nullptr; |
| + if (Relocatable == nullptr) { |
| + OffsetOp = Ctx->getConstantInt32(Offset); |
| + } else { |
| + OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, |
| + Relocatable->getName(), |
| + Relocatable->getSuppressMangling()); |
| + } |
| Addr = Traits::X86OperandMem::create(Func, Data->getType(), Base, OffsetOp, |
| Index, Shift, SegmentReg); |
| InstStore *NewStore = InstStore::create(Func, Data, Addr); |