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:
/// Create a new Variable with a particular type and an optional name. The
/// Node argument is the node where the variable is defined.
// TODO(jpp): untemplate this with separate methods: makeVariable,
// makeSpillVariable, and makeStackVariable.
// TODO(jpp): untemplate this with separate methods: makeVariable and
// makeStackVariable.
template <typename T = Variable> T *makeVariable(Type Ty) {
SizeT Index = Variables.size();
auto *Var = T::create(this, Ty, Index);
......
......@@ -198,11 +198,12 @@ const Variable *Variable::asType(const Cfg *Func, Type Ty,
if (!BuildDefs::dump() || getType() == Ty)
return this;
static constexpr SizeT One = 1;
Variable *V = new (CfgLocalAllocator<Variable>().allocate(One))
auto *V = new (CfgLocalAllocator<Variable>().allocate(One))
Variable(Func, kVariable, Ty, Number);
V->Name = Name;
V->RegNum = NewRegNum.hasValue() ? NewRegNum : RegNum;
V->StackOffset = StackOffset;
V->LinkedTo = LinkedTo;
return V;
}
......@@ -537,8 +538,11 @@ void Variable::dump(const Cfg *Func, Ostream &Str) const {
return;
}
if (Func->isVerbose(IceV_RegOrigins) ||
(!hasReg() && !Func->getTarget()->hasComputedFrame()))
(!hasReg() && !Func->getTarget()->hasComputedFrame())) {
Str << "%" << getName();
if (getLinkedTo() != nullptr)
Str << ":%" << getLinkedTo()->getName();
}
if (hasReg()) {
if (Func->isVerbose(IceV_RegOrigins))
Str << ":";
......
......@@ -656,7 +656,7 @@ Ostream &operator<<(Ostream &Str, const LiveRange &L);
/// Variable represents an operand that is register-allocated or
/// stack-allocated. If it is register-allocated, it will ultimately have a
/// non-negative RegNum field.
/// valid RegNum field.
class Variable : public Operand {
Variable() = delete;
Variable(const Variable &) = delete;
......@@ -773,6 +773,23 @@ public:
/// Return reg num of base register, if different from stack/frame register.
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) {
OperandKind Kind = Operand->getKind();
return Kind >= kVariable && Kind <= kVariable_Max;
......@@ -814,6 +831,9 @@ protected:
LiveRange Live;
/// VarsReal (and Operand::Vars) are set up such that Vars[0] == this.
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
......
......@@ -933,36 +933,6 @@ public:
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.
static const struct InstBrAttributesType {
......
......@@ -978,36 +978,6 @@ public:
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.
static const struct InstBrAttributesType {
......
......@@ -70,7 +70,6 @@ public:
using X86Operand = typename Traits::X86Operand;
using X86OperandMem = typename Traits::X86OperandMem;
using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters;
using SpillVariable = typename Traits::SpillVariable;
using InstX86Br = typename Traits::Insts::Br;
using InstX86FakeRMW = typename Traits::Insts::FakeRMW;
......
......@@ -1043,10 +1043,11 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
// stack slot.
std::function<bool(Variable *)> TargetVarHook =
[&VariablesLinkedToSpillSlots](Variable *Var) {
if (auto *SpillVar =
llvm::dyn_cast<typename Traits::SpillVariable>(Var)) {
if (Var->getLinkedTo() != nullptr) {
// TODO(stichnot): This assert won't necessarily be true in the
// future.
assert(Var->mustNotHaveReg());
if (SpillVar->getLinkedTo() && !SpillVar->getLinkedTo()->hasReg()) {
if (!Var->getLinkedTo()->hasReg()) {
VariablesLinkedToSpillSlots.push_back(Var);
return true;
}
......@@ -1210,8 +1211,8 @@ void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
// Assign stack offsets to variables that have been linked to spilled
// variables.
for (Variable *Var : VariablesLinkedToSpillSlots) {
Variable *Linked =
(llvm::cast<typename Traits::SpillVariable>(Var))->getLinkedTo();
const Variable *Linked = Var->getLinkedTo();
assert(Linked != nullptr);
Var->setStackOffset(Linked->getStackOffset());
}
this->HasComputedFrame = true;
......@@ -3086,10 +3087,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) {
// a_hi.i32 = t_hi.i32
Operand *SpillLo, *SpillHi;
if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
SpillVariable *SpillVar =
Func->makeVariable<SpillVariable>(IceType_f64);
SpillVar->setLinkedTo(Src0Var);
Variable *Spill = SpillVar;
Variable *Spill = Func->makeVariable(IceType_f64);
Spill->setLinkedTo(Src0Var);
Spill->setMustNotHaveReg();
_movq(Spill, Src0RM);
SpillLo = Traits::VariableSplit::create(Func, Spill,
......@@ -3134,10 +3133,8 @@ void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) {
// t_hi.i32 = b_hi.i32
// hi(s.f64) = t_hi.i32
// a.f64 = s.f64
SpillVariable *SpillVar =
Func->makeVariable<SpillVariable>(IceType_f64);
SpillVar->setLinkedTo(Dest);
Variable *Spill = SpillVar;
Variable *Spill = Func->makeVariable(IceType_f64);
Spill->setLinkedTo(Dest);
Spill->setMustNotHaveReg();
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