Commit 87ff3a18 by Jim Stichnoth

Subzero: Simplify the FakeKill instruction.

Even after earlier simplifications, FakeKill was still handled somewhat inefficiently for the register allocator. For x86-32, any function containing call instructions would result in about 11 pre-colored Variables, each with an identical and relatively complex live range consisting of points. They would start out on the UnhandledPrecolored list, then all move to the Inactive list, where they would be repeatedly compared against each register allocation candidate via overlapsRange(). We improve this by keeping around a single copy of that live range and directly masking out the Free[] register set when that live range overlaps the current candidate's live range. This saves ~10 overlaps() calculations per candidate while FakeKills are still pending. Also, slightly rearrange the initialization of the Unhandled etc. sets into a separate init routine, which will make it easier to reuse the register allocator in other situations such as Om1 post-lowering. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/720343003
parent 51596d43
...@@ -661,18 +661,6 @@ void CfgNode::livenessPostprocess(LivenessMode Mode, Liveness *Liveness) { ...@@ -661,18 +661,6 @@ void CfgNode::livenessPostprocess(LivenessMode Mode, Liveness *Liveness) {
FirstInstNum = I->getNumber(); FirstInstNum = I->getNumber();
assert(I->getNumber() > LastInstNum); assert(I->getNumber() > LastInstNum);
LastInstNum = I->getNumber(); LastInstNum = I->getNumber();
// Create fake live ranges for a Kill instruction, but only if the
// linked instruction is still alive.
if (Mode == Liveness_Intervals) {
if (InstFakeKill *Kill = llvm::dyn_cast<InstFakeKill>(I)) {
if (!Kill->getLinked()->isDeleted()) {
for (Variable *Var : Kill->getKilledRegs()) {
InstNumberT InstNumber = I->getNumber();
Var->addLiveRange(InstNumber, InstNumber, 1);
}
}
}
}
} }
if (Mode != Liveness_Intervals) if (Mode != Liveness_Intervals)
return; return;
......
...@@ -114,8 +114,6 @@ bool Inst::isLastUse(const Operand *TestSrc) const { ...@@ -114,8 +114,6 @@ bool Inst::isLastUse(const Operand *TestSrc) const {
void Inst::livenessLightweight(Cfg *Func, LivenessBV &Live) { void Inst::livenessLightweight(Cfg *Func, LivenessBV &Live) {
assert(!isDeleted()); assert(!isDeleted());
if (llvm::isa<InstFakeKill>(this))
return;
resetLastUses(); resetLastUses();
VariablesMetadata *VMetadata = Func->getVMetadata(); VariablesMetadata *VMetadata = Func->getVMetadata();
SizeT VarIndex = 0; SizeT VarIndex = 0;
...@@ -139,8 +137,6 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, ...@@ -139,8 +137,6 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live,
Liveness *Liveness, LiveBeginEndMap *LiveBegin, Liveness *Liveness, LiveBeginEndMap *LiveBegin,
LiveBeginEndMap *LiveEnd) { LiveBeginEndMap *LiveEnd) {
assert(!isDeleted()); assert(!isDeleted());
if (llvm::isa<InstFakeKill>(this))
return true;
Dead = false; Dead = false;
if (Dest) { if (Dest) {
...@@ -181,15 +177,13 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, ...@@ -181,15 +177,13 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live,
// twice. ICE only allows a variable to have a single // twice. ICE only allows a variable to have a single
// liveness interval in a basic block (except for blocks // liveness interval in a basic block (except for blocks
// where a variable is live-in and live-out but there is a // where a variable is live-in and live-out but there is a
// gap in the middle, and except for the special // gap in the middle). Therefore, this lowered sequence
// InstFakeKill instruction that can appear multiple // needs to represent a single conservative live range for
// times in the same block). Therefore, this lowered // t. Since the instructions are being traversed backwards,
// sequence needs to represent a single conservative live // we make sure LiveEnd is only set once by setting it only
// range for t. Since the instructions are being traversed // when LiveEnd[VarNum]==0 (sentinel value). Note that it's
// backwards, we make sure LiveEnd is only set once by // OK to set LiveBegin multiple times because of the
// setting it only when LiveEnd[VarNum]==0 (sentinel value). // backwards traversal.
// Note that it's OK to set LiveBegin multiple times because
// of the backwards traversal.
if (LiveEnd) { if (LiveEnd) {
// Ideally, we would verify that VarNum wasn't already // Ideally, we would verify that VarNum wasn't already
// added in this block, but this can't be done very // added in this block, but this can't be done very
...@@ -452,10 +446,8 @@ InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src) ...@@ -452,10 +446,8 @@ InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src)
addSource(Src); addSource(Src);
} }
InstFakeKill::InstFakeKill(Cfg *Func, const VarList &KilledRegs, InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked)
const Inst *Linked) : InstHighLevel(Func, Inst::FakeKill, 0, NULL), Linked(Linked) {}
: InstHighLevel(Func, Inst::FakeKill, 0, NULL), KilledRegs(KilledRegs),
Linked(Linked) {}
// ======================== Dump routines ======================== // // ======================== Dump routines ======================== //
...@@ -757,14 +749,7 @@ void InstFakeKill::dump(const Cfg *Func) const { ...@@ -757,14 +749,7 @@ void InstFakeKill::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
if (Linked->isDeleted()) if (Linked->isDeleted())
Str << "// "; Str << "// ";
Str << "kill.pseudo "; Str << "kill.pseudo scratch_regs";
bool First = true;
for (Variable *Var : KilledRegs) {
if (!First)
Str << ", ";
First = false;
Var->dump(Func);
}
} }
void InstTarget::dump(const Cfg *Func) const { void InstTarget::dump(const Cfg *Func) const {
......
...@@ -782,11 +782,12 @@ private: ...@@ -782,11 +782,12 @@ private:
~InstFakeUse() override {} ~InstFakeUse() override {}
}; };
// FakeKill instruction. This "kills" a set of variables by adding a // FakeKill instruction. This "kills" a set of variables by modeling
// trivial live range at this instruction to each variable. The // a trivial live range at this instruction for each (implicit)
// primary use is to indicate that scratch registers are killed after // variable. The primary use is to indicate that scratch registers
// a call, so that the register allocator won't assign a scratch // are killed after a call, so that the register allocator won't
// register to a variable whose live range spans a call. // assign a scratch register to a variable whose live range spans a
// call.
// //
// The FakeKill instruction also holds a pointer to the instruction // The FakeKill instruction also holds a pointer to the instruction
// that kills the set of variables, so that if that linked instruction // that kills the set of variables, so that if that linked instruction
...@@ -796,12 +797,9 @@ class InstFakeKill : public InstHighLevel { ...@@ -796,12 +797,9 @@ class InstFakeKill : public InstHighLevel {
InstFakeKill &operator=(const InstFakeKill &) = delete; InstFakeKill &operator=(const InstFakeKill &) = delete;
public: public:
static InstFakeKill *create(Cfg *Func, const VarList &KilledRegs, static InstFakeKill *create(Cfg *Func, const Inst *Linked) {
const Inst *Linked) { return new (Func->allocateInst<InstFakeKill>()) InstFakeKill(Func, Linked);
return new (Func->allocateInst<InstFakeKill>())
InstFakeKill(Func, KilledRegs, Linked);
} }
const VarList &getKilledRegs() const { return KilledRegs; }
const Inst *getLinked() const { return Linked; } const Inst *getLinked() const { return Linked; }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg * /* Func */) const override {} void emitIAS(const Cfg * /* Func */) const override {}
...@@ -809,10 +807,9 @@ public: ...@@ -809,10 +807,9 @@ public:
static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; } static bool classof(const Inst *Inst) { return Inst->getKind() == FakeKill; }
private: private:
InstFakeKill(Cfg *Func, const VarList &KilledRegs, const Inst *Linked); InstFakeKill(Cfg *Func, const Inst *Linked);
~InstFakeKill() override {} ~InstFakeKill() override {}
const VarList &KilledRegs;
// This instruction is ignored if Linked->isDeleted() is true. // This instruction is ignored if Linked->isDeleted() is true.
const Inst *Linked; const Inst *Linked;
}; };
......
...@@ -37,8 +37,6 @@ bool operator==(const RegWeight &A, const RegWeight &B) { ...@@ -37,8 +37,6 @@ bool operator==(const RegWeight &A, const RegWeight &B) {
} }
void LiveRange::addSegment(InstNumberT Start, InstNumberT End) { void LiveRange::addSegment(InstNumberT Start, InstNumberT End) {
if (End > Start)
IsNonpoints = true;
#ifdef USE_SET #ifdef USE_SET
RangeElementType Element(Start, End); RangeElementType Element(Start, End);
RangeType::iterator Next = Range.lower_bound(Element); RangeType::iterator Next = Range.lower_bound(Element);
...@@ -125,8 +123,6 @@ bool LiveRange::overlaps(const LiveRange &Other, bool UseTrimmed) const { ...@@ -125,8 +123,6 @@ bool LiveRange::overlaps(const LiveRange &Other, bool UseTrimmed) const {
} }
bool LiveRange::overlapsInst(InstNumberT OtherBegin, bool UseTrimmed) const { bool LiveRange::overlapsInst(InstNumberT OtherBegin, bool UseTrimmed) const {
if (!IsNonpoints)
return false;
bool Result = false; bool Result = false;
for (auto I = (UseTrimmed ? TrimmedBegin : Range.begin()), E = Range.end(); for (auto I = (UseTrimmed ? TrimmedBegin : Range.begin()), E = Range.end();
I != E; ++I) { I != E; ++I) {
......
...@@ -309,17 +309,15 @@ bool operator==(const RegWeight &A, const RegWeight &B); ...@@ -309,17 +309,15 @@ bool operator==(const RegWeight &A, const RegWeight &B);
// weight, in case e.g. we want a live range to have higher weight // weight, in case e.g. we want a live range to have higher weight
// inside a loop. // inside a loop.
class LiveRange { class LiveRange {
// LiveRange(const LiveRange &) = delete;
// LiveRange &operator=(const LiveRange &) = delete;
public: public:
LiveRange() : Weight(0), IsNonpoints(false) {} LiveRange() : Weight(0) {}
LiveRange(const LiveRange &) = default;
LiveRange &operator=(const LiveRange &) = default;
void reset() { void reset() {
Range.clear(); Range.clear();
Weight.setWeight(0); Weight.setWeight(0);
untrim(); untrim();
IsNonpoints = false;
} }
void addSegment(InstNumberT Start, InstNumberT End); void addSegment(InstNumberT Start, InstNumberT End);
...@@ -328,7 +326,6 @@ public: ...@@ -328,7 +326,6 @@ public:
bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const; bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const;
bool containsValue(InstNumberT Value, bool IsDest) const; bool containsValue(InstNumberT Value, bool IsDest) const;
bool isEmpty() const { return Range.empty(); } bool isEmpty() const { return Range.empty(); }
bool isNonpoints() const { return IsNonpoints; }
InstNumberT getStart() const { InstNumberT getStart() const {
return Range.empty() ? -1 : Range.begin()->first; return Range.empty() ? -1 : Range.begin()->first;
} }
...@@ -365,11 +362,6 @@ private: ...@@ -365,11 +362,6 @@ private:
// that linear-scan also has to initialize TrimmedBegin at the // that linear-scan also has to initialize TrimmedBegin at the
// beginning by calling untrim(). // beginning by calling untrim().
RangeType::const_iterator TrimmedBegin; RangeType::const_iterator TrimmedBegin;
// IsNonpoints keeps track of whether the live range contains at
// least one interval where Start!=End. If it is empty or has the
// form [x,x),[y,y),...,[z,z), then overlaps(InstNumberT) is
// trivially false.
bool IsNonpoints;
}; };
Ostream &operator<<(Ostream &Str, const LiveRange &L); Ostream &operator<<(Ostream &Str, const LiveRange &L);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "IceCfg.h" #include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceRegAlloc.h" #include "IceRegAlloc.h"
...@@ -72,6 +73,63 @@ void dumpLiveRange(const Variable *Var, const Cfg *Func) { ...@@ -72,6 +73,63 @@ void dumpLiveRange(const Variable *Var, const Cfg *Func) {
} // end of anonymous namespace } // end of anonymous namespace
void LinearScan::initForGlobalAlloc() {
TimerMarker T(TimerStack::TT_initUnhandled, Func);
Unhandled.clear();
UnhandledPrecolored.clear();
Handled.clear();
Inactive.clear();
Active.clear();
// Gather the live ranges of all variables and add them to the
// Unhandled set.
const VarList &Vars = Func->getVariables();
Unhandled.reserve(Vars.size());
for (Variable *Var : Vars) {
// Explicitly don't consider zero-weight variables, which are
// meant to be spill slots.
if (Var->getWeight() == RegWeight::Zero)
continue;
// Don't bother if the variable has a null live range, which means
// it was never referenced.
if (Var->getLiveRange().isEmpty())
continue;
Var->untrimLiveRange();
Unhandled.push_back(Var);
if (Var->hasReg()) {
Var->setRegNumTmp(Var->getRegNum());
Var->setLiveRangeInfiniteWeight();
UnhandledPrecolored.push_back(Var);
}
}
struct CompareRanges {
bool operator()(const Variable *L, const Variable *R) {
InstNumberT Lstart = L->getLiveRange().getStart();
InstNumberT Rstart = R->getLiveRange().getStart();
if (Lstart == Rstart)
return L->getIndex() < R->getIndex();
return Lstart < Rstart;
}
};
// Do a reverse sort so that erasing elements (from the end) is fast.
std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges());
std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(),
CompareRanges());
// Build the (ordered) list of FakeKill instruction numbers.
Kills.clear();
for (CfgNode *Node : Func->getNodes()) {
for (auto I = Node->getInsts().begin(), E = Node->getInsts().end(); I != E;
++I) {
if (I->isDeleted())
continue;
if (auto Kill = llvm::dyn_cast<InstFakeKill>(I)) {
if (!Kill->getLinked()->isDeleted())
Kills.push_back(I->getNumber());
}
}
}
}
// Implements the linear-scan algorithm. Based on "Linear Scan // Implements the linear-scan algorithm. Based on "Linear Scan
// Register Allocation in the Context of SSA Form and Register // Register Allocation in the Context of SSA Form and Register
// Constraints" by Hanspeter Mössenböck and Michael Pfeiffer, // Constraints" by Hanspeter Mössenböck and Michael Pfeiffer,
...@@ -86,53 +144,16 @@ void dumpLiveRange(const Variable *Var, const Cfg *Func) { ...@@ -86,53 +144,16 @@ void dumpLiveRange(const Variable *Var, const Cfg *Func) {
void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
TimerMarker T(TimerStack::TT_linearScan, Func); TimerMarker T(TimerStack::TT_linearScan, Func);
assert(RegMaskFull.any()); // Sanity check assert(RegMaskFull.any()); // Sanity check
Unhandled.clear();
UnhandledPrecolored.clear();
Handled.clear();
Inactive.clear();
Active.clear();
Ostream &Str = Func->getContext()->getStrDump(); Ostream &Str = Func->getContext()->getStrDump();
bool Verbose = Func->getContext()->isVerbose(IceV_LinearScan); bool Verbose = Func->getContext()->isVerbose(IceV_LinearScan);
Func->resetCurrentNode(); Func->resetCurrentNode();
VariablesMetadata *VMetadata = Func->getVMetadata(); VariablesMetadata *VMetadata = Func->getVMetadata();
// Gather the live ranges of all variables and add them to the // Build a LiveRange representing the Kills list.
// Unhandled set. LiveRange KillsRange;
const VarList &Vars = Func->getVariables(); for (InstNumberT I : Kills)
{ KillsRange.addSegment(I, I);
TimerMarker T(TimerStack::TT_initUnhandled, Func); KillsRange.untrim();
Unhandled.reserve(Vars.size());
for (Variable *Var : Vars) {
// Explicitly don't consider zero-weight variables, which are
// meant to be spill slots.
if (Var->getWeight() == RegWeight::Zero)
continue;
// Don't bother if the variable has a null live range, which means
// it was never referenced.
if (Var->getLiveRange().isEmpty())
continue;
Var->untrimLiveRange();
Unhandled.push_back(Var);
if (Var->hasReg()) {
Var->setRegNumTmp(Var->getRegNum());
Var->setLiveRangeInfiniteWeight();
UnhandledPrecolored.push_back(Var);
}
}
struct CompareRanges {
bool operator()(const Variable *L, const Variable *R) {
InstNumberT Lstart = L->getLiveRange().getStart();
InstNumberT Rstart = R->getLiveRange().getStart();
if (Lstart == Rstart)
return L->getIndex() < R->getIndex();
return Lstart < Rstart;
}
};
// Do a reverse sort so that erasing elements (from the end) is fast.
std::sort(Unhandled.rbegin(), Unhandled.rend(), CompareRanges());
std::sort(UnhandledPrecolored.rbegin(), UnhandledPrecolored.rend(),
CompareRanges());
}
// RegUses[I] is the number of live ranges (variables) that register // RegUses[I] is the number of live ranges (variables) that register
// I is currently assigned to. It can be greater than 1 as a result // I is currently assigned to. It can be greater than 1 as a result
...@@ -144,6 +165,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -144,6 +165,11 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
assert(Inactive.empty()); assert(Inactive.empty());
assert(Handled.empty()); assert(Handled.empty());
UnorderedRanges::iterator Next; UnorderedRanges::iterator Next;
const TargetLowering::RegSetMask RegsInclude =
TargetLowering::RegSet_CallerSave;
const TargetLowering::RegSetMask RegsExclude = TargetLowering::RegSet_None;
const llvm::SmallBitVector KillsMask =
Func->getTarget()->getRegisterSet(RegsInclude, RegsExclude);
while (!Unhandled.empty()) { while (!Unhandled.empty()) {
Variable *Cur = Unhandled.back(); Variable *Cur = Unhandled.back();
...@@ -155,6 +181,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -155,6 +181,7 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
} }
const llvm::SmallBitVector RegMask = const llvm::SmallBitVector RegMask =
RegMaskFull & Func->getTarget()->getRegisterSetForType(Cur->getType()); RegMaskFull & Func->getTarget()->getRegisterSetForType(Cur->getType());
KillsRange.trim(Cur->getLiveRange().getStart());
// Check for precolored ranges. If Cur is precolored, it // Check for precolored ranges. If Cur is precolored, it
// definitely gets that register. Previously processed live // definitely gets that register. Previously processed live
...@@ -220,15 +247,6 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -220,15 +247,6 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
++Next; ++Next;
Variable *Item = *I; Variable *Item = *I;
Item->trimLiveRange(Cur->getLiveRange().getStart()); Item->trimLiveRange(Cur->getLiveRange().getStart());
// As an optimization, don't bother checking pure point-valued
// Inactive ranges, because the overlapsStart() test will never
// succeed, and the rangeEndsBefore() test will generally only
// succeed after the last call instruction, which statistically
// happens near the end. TODO(stichnot): Consider suppressing
// this check every N iterations in case calls are only at the
// beginning of the function.
if (!Item->getLiveRange().isNonpoints())
continue;
if (Item->rangeEndsBefore(Cur)) { if (Item->rangeEndsBefore(Cur)) {
// Move Item from Inactive to Handled list. // Move Item from Inactive to Handled list.
if (Verbose) { if (Verbose) {
...@@ -374,6 +392,19 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) { ...@@ -374,6 +392,19 @@ void LinearScan::scan(const llvm::SmallBitVector &RegMaskFull) {
} }
} }
// Remove scratch registers from the Free[] list, and mark their
// Weights[] as infinite, if KillsRange overlaps Cur's live range.
const bool UseTrimmed = true;
if (Cur->getLiveRange().overlaps(KillsRange, UseTrimmed)) {
Free.reset(KillsMask);
for (int i = KillsMask.find_first(); i != -1;
i = KillsMask.find_next(i)) {
Weights[i].setWeight(RegWeight::Inf);
if (PreferReg == i)
AllowOverlap = false;
}
}
// Print info about physical register availability. // Print info about physical register availability.
if (Verbose) { if (Verbose) {
for (SizeT i = 0; i < RegMask.size(); ++i) { for (SizeT i = 0; i < RegMask.size(); ++i) {
......
...@@ -27,6 +27,7 @@ class LinearScan { ...@@ -27,6 +27,7 @@ class LinearScan {
public: public:
LinearScan(Cfg *Func) : Func(Func) {} LinearScan(Cfg *Func) : Func(Func) {}
void initForGlobalAlloc();
void scan(const llvm::SmallBitVector &RegMask); void scan(const llvm::SmallBitVector &RegMask);
void dump(Cfg *Func) const; void dump(Cfg *Func) const;
...@@ -39,6 +40,7 @@ private: ...@@ -39,6 +40,7 @@ private:
// for faster processing. // for faster processing.
OrderedRanges UnhandledPrecolored; OrderedRanges UnhandledPrecolored;
UnorderedRanges Active, Inactive, Handled; UnorderedRanges Active, Inactive, Handled;
std::vector<InstNumberT> Kills;
}; };
} // end of namespace Ice } // end of namespace Ice
......
...@@ -234,6 +234,7 @@ void TargetLowering::regAlloc() { ...@@ -234,6 +234,7 @@ void TargetLowering::regAlloc() {
RegInclude |= RegSet_CalleeSave; RegInclude |= RegSet_CalleeSave;
if (hasFramePointer()) if (hasFramePointer())
RegExclude |= RegSet_FramePointer; RegExclude |= RegSet_FramePointer;
LinearScan.initForGlobalAlloc();
llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude); llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude);
LinearScan.scan(RegMask); LinearScan.scan(RegMask);
} }
......
...@@ -316,8 +316,6 @@ TargetX8632::TargetX8632(Cfg *Func) ...@@ -316,8 +316,6 @@ TargetX8632::TargetX8632(Cfg *Func)
void TargetX8632::translateO2() { void TargetX8632::translateO2() {
TimerMarker T(TimerStack::TT_O2, Func); TimerMarker T(TimerStack::TT_O2, Func);
initFakeKilledScratchRegisters();
if (!Ctx->getFlags().PhiEdgeSplit) { if (!Ctx->getFlags().PhiEdgeSplit) {
// Lower Phi instructions. // Lower Phi instructions.
Func->placePhiLoads(); Func->placePhiLoads();
...@@ -413,8 +411,6 @@ void TargetX8632::translateO2() { ...@@ -413,8 +411,6 @@ void TargetX8632::translateO2() {
void TargetX8632::translateOm1() { void TargetX8632::translateOm1() {
TimerMarker T(TimerStack::TT_Om1, Func); TimerMarker T(TimerStack::TT_Om1, Func);
initFakeKilledScratchRegisters();
Func->placePhiLoads(); Func->placePhiLoads();
if (Func->hasError()) if (Func->hasError())
return; return;
...@@ -1894,9 +1890,7 @@ void TargetX8632::lowerCall(const InstCall *Instr) { ...@@ -1894,9 +1890,7 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
} }
// Insert a register-kill pseudo instruction. // Insert a register-kill pseudo instruction.
assert(!FakeKilledScratchRegisters.empty()); Context.insert(InstFakeKill::create(Func, NewCall));
Context.insert(
InstFakeKill::create(Func, FakeKilledScratchRegisters, NewCall));
// Generate a FakeUse to keep the call live if necessary. // Generate a FakeUse to keep the call live if necessary.
if (Instr->hasSideEffects() && ReturnReg) { if (Instr->hasSideEffects() && ReturnReg) {
......
...@@ -483,20 +483,10 @@ protected: ...@@ -483,20 +483,10 @@ protected:
llvm::SmallBitVector RegsUsed; llvm::SmallBitVector RegsUsed;
SizeT NextLabelNumber; SizeT NextLabelNumber;
VarList PhysicalRegisters[IceType_NUM]; VarList PhysicalRegisters[IceType_NUM];
VarList FakeKilledScratchRegisters;
static IceString RegNames[]; static IceString RegNames[];
private: private:
~TargetX8632() override {} ~TargetX8632() override {}
// Ideally, this initialization would be done in the constructor,
// but we need to defer it until after the initial CFG is built,
// because some of the bitcode reader tests rely on the order that
// Variables are created and their default printable names.
void initFakeKilledScratchRegisters() {
for (SizeT I = 0; I < ScratchRegs.size(); ++I)
if (ScratchRegs[I])
FakeKilledScratchRegisters.push_back(getPhysicalRegister(I));
}
template <typename T> void emitConstantPool() const; template <typename T> void emitConstantPool() const;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment