Subzero: Improve the representation and handling of the FakeKill instruction.
The FakeKill instruction is always used for killing scratch registers, and a fair amount of effort is spent building new copies of the same scratch register list each time (i.e., for each lowered call instruction). As such, we can create one master list of scratch registers and share it among all FakeKill instructions.
Also, in all situations where an instruction's Srcs[] were considered for liveness, we had to either explicitly ignore an InstFakeKill instruction, or treat it specially. Now that InstFakeKill lacks any Srcs[] (or Dest), it doesn't need to be specially ignored, and the code is simplified.
In addition, the text asm emitter no longer clutters the output with FakeKill comments (and FakeUse as well).
BUG= none
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/691693003
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index b8b5ce3..ab9d5f7 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -316,8 +316,6 @@
for (Inst *Inst : Node->getInsts()) {
if (Inst->isDeleted())
continue;
- if (llvm::isa<InstFakeKill>(Inst))
- continue;
if (FirstInst == NULL)
FirstInst = Inst;
InstNumberT InstNumber = Inst->getNumber();
diff --git a/src/IceCfgNode.cpp b/src/IceCfgNode.cpp
index b753078..494ab4b 100644
--- a/src/IceCfgNode.cpp
+++ b/src/IceCfgNode.cpp
@@ -667,9 +667,7 @@
if (Mode == Liveness_Intervals) {
if (InstFakeKill *Kill = llvm::dyn_cast<InstFakeKill>(I)) {
if (!Kill->getLinked()->isDeleted()) {
- SizeT NumSrcs = I->getSrcSize();
- for (SizeT Src = 0; Src < NumSrcs; ++Src) {
- Variable *Var = llvm::cast<Variable>(I->getSrc(Src));
+ for (Variable *Var : Kill->getKilledRegs()) {
InstNumberT InstNumber = I->getNumber();
Var->addLiveRange(InstNumber, InstNumber, 1);
}
diff --git a/src/IceInst.cpp b/src/IceInst.cpp
index 70b54b6..090faba 100644
--- a/src/IceInst.cpp
+++ b/src/IceInst.cpp
@@ -454,11 +454,8 @@
InstFakeKill::InstFakeKill(Cfg *Func, const VarList &KilledRegs,
const Inst *Linked)
- : InstHighLevel(Func, Inst::FakeKill, KilledRegs.size(), NULL),
- Linked(Linked) {
- for (Variable *Var : KilledRegs)
- addSource(Var);
-}
+ : InstHighLevel(Func, Inst::FakeKill, 0, NULL), KilledRegs(KilledRegs),
+ Linked(Linked) {}
// ======================== Dump routines ======================== //
@@ -730,6 +727,8 @@
}
void InstFakeDef::emit(const Cfg *Func) const {
+ // Go ahead and "emit" these for now, since they are relatively
+ // rare.
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t# ";
getDest()->emit(Func);
@@ -744,12 +743,7 @@
dumpSources(Func);
}
-void InstFakeUse::emit(const Cfg *Func) const {
- Ostream &Str = Func->getContext()->getStrEmit();
- Str << "\t# ";
- Str << "use.pseudo ";
- emitSources(Func);
-}
+void InstFakeUse::emit(const Cfg *Func) const { (void)Func; }
void InstFakeUse::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump();
@@ -757,21 +751,20 @@
dumpSources(Func);
}
-void InstFakeKill::emit(const Cfg *Func) const {
- Ostream &Str = Func->getContext()->getStrEmit();
- Str << "\t# ";
- if (Linked->isDeleted())
- Str << "// ";
- Str << "kill.pseudo ";
- emitSources(Func);
-}
+void InstFakeKill::emit(const Cfg *Func) const { (void)Func; }
void InstFakeKill::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump();
if (Linked->isDeleted())
Str << "// ";
Str << "kill.pseudo ";
- dumpSources(Func);
+ bool First = true;
+ for (Variable *Var : KilledRegs) {
+ if (!First)
+ Str << ", ";
+ First = false;
+ Var->dump(Func);
+ }
}
void InstTarget::dump(const Cfg *Func) const {
diff --git a/src/IceInst.h b/src/IceInst.h
index e6edb4c..7c96e3f 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -801,6 +801,7 @@
return new (Func->allocateInst<InstFakeKill>())
InstFakeKill(Func, KilledRegs, Linked);
}
+ const VarList &getKilledRegs() const { return KilledRegs; }
const Inst *getLinked() const { return Linked; }
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg * /* Func */) const override {}
@@ -811,6 +812,7 @@
InstFakeKill(Cfg *Func, const VarList &KilledRegs, const Inst *Linked);
~InstFakeKill() override {}
+ const VarList &KilledRegs;
// This instruction is ignored if Linked->isDeleted() is true.
const Inst *Linked;
};
diff --git a/src/IceOperand.cpp b/src/IceOperand.cpp
index e1faf0f..8cf181a 100644
--- a/src/IceOperand.cpp
+++ b/src/IceOperand.cpp
@@ -350,18 +350,8 @@
for (Inst *I : Node->getInsts()) {
if (I->isDeleted())
continue;
- if (InstFakeKill *Kill = llvm::dyn_cast<InstFakeKill>(I)) {
- // A FakeKill instruction indicates certain Variables (usually
- // physical scratch registers) are redefined, so we register
- // them as defs.
- for (SizeT SrcNum = 0; SrcNum < I->getSrcSize(); ++SrcNum) {
- Variable *Var = llvm::cast<Variable>(I->getSrc(SrcNum));
- SizeT VarNum = Var->getIndex();
- assert(VarNum < Metadata.size());
- Metadata[VarNum].markDef(Kind, Kill, Node);
- }
- continue; // no point in executing the rest
- }
+ // Note: The implicit definitions (and uses) from InstFakeKill are
+ // deliberately ignored.
if (Variable *Dest = I->getDest()) {
SizeT DestNum = Dest->getIndex();
assert(DestNum < Metadata.size());
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 17bc8cc..999556e 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -316,6 +316,8 @@
void TargetX8632::translateO2() {
TimerMarker T(TimerStack::TT_O2, Func);
+ initFakeKilledScratchRegisters();
+
if (!Ctx->getFlags().PhiEdgeSplit) {
// Lower Phi instructions.
Func->placePhiLoads();
@@ -411,6 +413,9 @@
void TargetX8632::translateOm1() {
TimerMarker T(TimerStack::TT_Om1, Func);
+
+ initFakeKilledScratchRegisters();
+
Func->placePhiLoads();
if (Func->hasError())
return;
@@ -1869,12 +1874,9 @@
}
// Insert a register-kill pseudo instruction.
- VarList KilledRegs;
- for (SizeT i = 0; i < ScratchRegs.size(); ++i) {
- if (ScratchRegs[i])
- KilledRegs.push_back(Func->getTarget()->getPhysicalRegister(i));
- }
- Context.insert(InstFakeKill::create(Func, KilledRegs, NewCall));
+ assert(!FakeKilledScratchRegisters.empty());
+ Context.insert(
+ InstFakeKill::create(Func, FakeKilledScratchRegisters, NewCall));
// Generate a FakeUse to keep the call live if necessary.
if (Instr->hasSideEffects() && ReturnReg) {
@@ -4540,8 +4542,7 @@
// allocator, for example compute live ranges only for pre-colored
// and infinite-weight variables and run the existing linear-scan
// allocator.
- if (llvm::isa<InstFakeKill>(Inst))
- continue;
+ assert(!llvm::isa<InstFakeKill>(Inst) || Inst->getSrcSize() == 0);
for (SizeT SrcNum = 0; SrcNum < Inst->getSrcSize(); ++SrcNum) {
Operand *Src = Inst->getSrc(SrcNum);
SizeT NumVars = Src->getNumVars();
@@ -4563,9 +4564,6 @@
FreedRegisters.reset();
if (Inst->isDeleted())
continue;
- // Skip FakeKill instructions like above.
- if (llvm::isa<InstFakeKill>(Inst))
- continue;
// Iterate over all variables referenced in the instruction,
// including the Dest variable (if any). If the variable is
// marked as infinite-weight, find it a register. If this
@@ -4579,6 +4577,8 @@
SizeT NumSrcs = Inst->getSrcSize();
if (Dest)
++NumSrcs;
+ if (NumSrcs == 0)
+ continue;
OperandList Srcs(NumSrcs);
for (SizeT i = 0; i < Inst->getSrcSize(); ++i)
Srcs[i] = Inst->getSrc(i);
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 7422f8a..985d3ae 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -484,10 +484,20 @@
SizeT NextLabelNumber;
bool ComputedLiveRanges;
VarList PhysicalRegisters[IceType_NUM];
+ VarList FakeKilledScratchRegisters;
static IceString RegNames[];
private:
~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;
};