Commit e343e066 by Jim Stichnoth

Subzero: Merge SpillVariable functionality directly into Variable.

Specifically, this is the ability to link variable B to variable A, such that if neither A nor B get a register assignment, they share a stack slot. This CL just refactors and keeps basically the same functionality, in preparation for new work on variable splitting. BUG= none R=jpp@chromium.org Review URL: https://codereview.chromium.org/2107073002 .
parent 45f51a26
...@@ -111,8 +111,8 @@ public: ...@@ -111,8 +111,8 @@ public:
/// Create a new Variable with a particular type and an optional name. The /// Create a new Variable with a particular type and an optional name. The
/// Node argument is the node where the variable is defined. /// Node argument is the node where the variable is defined.
// TODO(jpp): untemplate this with separate methods: makeVariable, // TODO(jpp): untemplate this with separate methods: makeVariable and
// makeSpillVariable, and makeStackVariable. // makeStackVariable.
template <typename T = Variable> T *makeVariable(Type Ty) { template <typename T = Variable> T *makeVariable(Type Ty) {
SizeT Index = Variables.size(); SizeT Index = Variables.size();
auto *Var = T::create(this, Ty, Index); auto *Var = T::create(this, Ty, Index);
......
...@@ -198,11 +198,12 @@ const Variable *Variable::asType(const Cfg *Func, Type Ty, ...@@ -198,11 +198,12 @@ const Variable *Variable::asType(const Cfg *Func, Type Ty,
if (!BuildDefs::dump() || getType() == Ty) if (!BuildDefs::dump() || getType() == Ty)
return this; return this;
static constexpr SizeT One = 1; static constexpr SizeT One = 1;
Variable *V = new (CfgLocalAllocator<Variable>().allocate(One)) auto *V = new (CfgLocalAllocator<Variable>().allocate(One))
Variable(Func, kVariable, Ty, Number); Variable(Func, kVariable, Ty, Number);
V->Name = Name; V->Name = Name;
V->RegNum = NewRegNum.hasValue() ? NewRegNum : RegNum; V->RegNum = NewRegNum.hasValue() ? NewRegNum : RegNum;
V->StackOffset = StackOffset; V->StackOffset = StackOffset;
V->LinkedTo = LinkedTo;
return V; return V;
} }
...@@ -537,8 +538,11 @@ void Variable::dump(const Cfg *Func, Ostream &Str) const { ...@@ -537,8 +538,11 @@ void Variable::dump(const Cfg *Func, Ostream &Str) const {
return; return;
} }
if (Func->isVerbose(IceV_RegOrigins) || if (Func->isVerbose(IceV_RegOrigins) ||
(!hasReg() && !Func->getTarget()->hasComputedFrame())) (!hasReg() && !Func->getTarget()->hasComputedFrame())) {
Str << "%" << getName(); Str << "%" << getName();
if (getLinkedTo() != nullptr)
Str << ":%" << getLinkedTo()->getName();
}
if (hasReg()) { if (hasReg()) {
if (Func->isVerbose(IceV_RegOrigins)) if (Func->isVerbose(IceV_RegOrigins))
Str << ":"; Str << ":";
......
...@@ -656,7 +656,7 @@ Ostream &operator<<(Ostream &Str, const LiveRange &L); ...@@ -656,7 +656,7 @@ Ostream &operator<<(Ostream &Str, const LiveRange &L);
/// Variable represents an operand that is register-allocated or /// Variable represents an operand that is register-allocated or
/// stack-allocated. If it is register-allocated, it will ultimately have a /// stack-allocated. If it is register-allocated, it will ultimately have a
/// non-negative RegNum field. /// valid RegNum field.
class Variable : public Operand { class Variable : public Operand {
Variable() = delete; Variable() = delete;
Variable(const Variable &) = delete; Variable(const Variable &) = delete;
...@@ -773,6 +773,23 @@ public: ...@@ -773,6 +773,23 @@ public:
/// Return reg num of base register, if different from stack/frame register. /// Return reg num of base register, if different from stack/frame register.
virtual RegNumT getBaseRegNum() const { return RegNumT(); } virtual RegNumT getBaseRegNum() const { return RegNumT(); }
void setLinkedTo(const Variable *Var) {
// If B is linked to A, and we now want to link C to B, we instead link C to
// A so that we have one root (A) and all leaves (B, C) link directly to the
// root.
if (Var->getLinkedTo() != nullptr) {
Var = Var->LinkedTo;
assert(Var->LinkedTo == nullptr);
}
LinkedTo = Var;
}
const Variable *getLinkedTo() const {
// Make sure a leaf links directly to the root.
if (LinkedTo != nullptr)
assert(LinkedTo->LinkedTo == nullptr);
return LinkedTo;
}
static bool classof(const Operand *Operand) { static bool classof(const Operand *Operand) {
OperandKind Kind = Operand->getKind(); OperandKind Kind = Operand->getKind();
return Kind >= kVariable && Kind <= kVariable_Max; return Kind >= kVariable && Kind <= kVariable_Max;
...@@ -814,6 +831,9 @@ protected: ...@@ -814,6 +831,9 @@ protected:
LiveRange Live; LiveRange Live;
/// VarsReal (and Operand::Vars) are set up such that Vars[0] == this. /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this.
Variable *VarsReal[1]; Variable *VarsReal[1];
/// This Variable may be "linked" to another Variable, such that if neither
/// Variable gets a register, they are guaranteed to share a stack location.
const Variable *LinkedTo = nullptr;
}; };
// Variable64On32 represents a 64-bit variable on a 32-bit architecture. In // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In
......
...@@ -933,36 +933,6 @@ public: ...@@ -933,36 +933,6 @@ public:
Portion Part; Portion Part;
}; };
/// SpillVariable decorates a Variable by linking it to another Variable. When
/// stack frame offsets are computed, the SpillVariable is given a distinct
/// stack slot only if its linked Variable has a register. If the linked
/// Variable has a stack slot, then the Variable and SpillVariable share that
/// slot.
class SpillVariable : public Variable {
SpillVariable() = delete;
SpillVariable(const SpillVariable &) = delete;
SpillVariable &operator=(const SpillVariable &) = delete;
public:
static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<SpillVariable>())
SpillVariable(Func, Ty, Index);
}
constexpr static auto SpillVariableKind =
static_cast<OperandKind>(kVariable_Target);
static bool classof(const Operand *Operand) {
return Operand->getKind() == SpillVariableKind;
}
void setLinkedTo(Variable *Var) { LinkedTo = Var; }
Variable *getLinkedTo() const { return LinkedTo; }
// Inherit dump() and emit() from Variable.
private:
SpillVariable(const Cfg *Func, Type Ty, SizeT Index)
: Variable(Func, SpillVariableKind, Ty, Index), LinkedTo(nullptr) {}
Variable *LinkedTo;
};
// Note: The following data structures are defined in IceInstX8632.cpp. // Note: The following data structures are defined in IceInstX8632.cpp.
static const struct InstBrAttributesType { static const struct InstBrAttributesType {
......
...@@ -978,36 +978,6 @@ public: ...@@ -978,36 +978,6 @@ public:
Portion Part; Portion Part;
}; };
/// SpillVariable decorates a Variable by linking it to another Variable. When
/// stack frame offsets are computed, the SpillVariable is given a distinct
/// stack slot only if its linked Variable has a register. If the linked
/// Variable has a stack slot, then the Variable and SpillVariable share that
/// slot.
class SpillVariable : public Variable {
SpillVariable() = delete;
SpillVariable(const SpillVariable &) = delete;
SpillVariable &operator=(const SpillVariable &) = delete;
public:
static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<SpillVariable>())
SpillVariable(Func, Ty, Index);
}
constexpr static auto SpillVariableKind =
static_cast<OperandKind>(kVariable_Target);
static bool classof(const Operand *Operand) {
return Operand->getKind() == SpillVariableKind;
}
void setLinkedTo(Variable *Var) { LinkedTo = Var; }
Variable *getLinkedTo() const { return LinkedTo; }
// Inherit dump() and emit() from Variable.
private:
SpillVariable(const Cfg *Func, Type Ty, SizeT Index)
: Variable(Func, SpillVariableKind, Ty, Index), LinkedTo(nullptr) {}
Variable *LinkedTo;
};
// Note: The following data structures are defined in IceInstX8664.cpp. // Note: The following data structures are defined in IceInstX8664.cpp.
static const struct InstBrAttributesType { static const struct InstBrAttributesType {
......
...@@ -70,7 +70,6 @@ public: ...@@ -70,7 +70,6 @@ public:
using X86Operand = typename Traits::X86Operand; using X86Operand = typename Traits::X86Operand;
using X86OperandMem = typename Traits::X86OperandMem; using X86OperandMem = typename Traits::X86OperandMem;
using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters; using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters;
using SpillVariable = typename Traits::SpillVariable;
using InstX86Br = typename Traits::Insts::Br; using InstX86Br = typename Traits::Insts::Br;
using InstX86FakeRMW = typename Traits::Insts::FakeRMW; using InstX86FakeRMW = typename Traits::Insts::FakeRMW;
......
...@@ -1043,10 +1043,11 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) { ...@@ -1043,10 +1043,11 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
// stack slot. // stack slot.
std::function<bool(Variable *)> TargetVarHook = std::function<bool(Variable *)> TargetVarHook =
[&VariablesLinkedToSpillSlots](Variable *Var) { [&VariablesLinkedToSpillSlots](Variable *Var) {
if (auto *SpillVar = if (Var->getLinkedTo() != nullptr) {
llvm::dyn_cast<typename Traits::SpillVariable>(Var)) { // TODO(stichnot): This assert won't necessarily be true in the
// future.
assert(Var->mustNotHaveReg()); assert(Var->mustNotHaveReg());
if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) { if (!Var->getLinkedTo()->hasReg()) {
VariablesLinkedToSpillSlots.push_back(Var); VariablesLinkedToSpillSlots.push_back(Var);
return true; return true;
} }
...@@ -1210,8 +1211,8 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) { ...@@ -1210,8 +1211,8 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
// Assign stack offsets to variables that have been linked to spilled // Assign stack offsets to variables that have been linked to spilled
// variables. // variables.
for (Variable *Var : VariablesLinkedToSpillSlots) { for (Variable *Var : VariablesLinkedToSpillSlots) {
Variable *Linked = const Variable *Linked = Var->getLinkedTo();
(llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo(); assert(Linked != nullptr);
Var->setStackOffset(Linked->getStackOffset()); Var->setStackOffset(Linked->getStackOffset());
} }
this->HasComputedFrame = true; this->HasComputedFrame = true;
...@@ -3086,10 +3087,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) { ...@@ -3086,10 +3087,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) {
// a_hi.i32 = t_hi.i32 // a_hi.i32 = t_hi.i32
Operand *SpillLo, *SpillHi; Operand *SpillLo, *SpillHi;
if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) { if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
SpillVariable *SpillVar = Variable *Spill = Func->makeVariable(IceType_f64);
Func->makeVariable<SpillVariable>(IceType_f64); Spill->setLinkedTo(Src0Var);
SpillVar->setLinkedTo(Src0Var);
Variable *Spill = SpillVar;
Spill->setMustNotHaveReg(); Spill->setMustNotHaveReg();
_movq(Spill, Src0RM); _movq(Spill, Src0RM);
SpillLo = Traits::VariableSplit::create(Func, Spill, SpillLo = Traits::VariableSplit::create(Func, Spill,
...@@ -3134,10 +3133,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) { ...@@ -3134,10 +3133,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) {
// t_hi.i32 = b_hi.i32 // t_hi.i32 = b_hi.i32
// hi(s.f64) = t_hi.i32 // hi(s.f64) = t_hi.i32
// a.f64 = s.f64 // a.f64 = s.f64
SpillVariable *SpillVar = Variable *Spill = Func->makeVariable(IceType_f64);
Func->makeVariable<SpillVariable>(IceType_f64); Spill->setLinkedTo(Dest);
SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar;
Spill->setMustNotHaveReg(); Spill->setMustNotHaveReg();
Variable *T_Lo = nullptr, *T_Hi = nullptr; Variable *T_Lo = nullptr, *T_Hi = nullptr;
......
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