Subzero: Initial O2 lowering
Includes the following:
1. Liveness analysis.
2. Linear-scan register allocation.
3. Address mode optimization.
4. Compare-branch fusing.
All of these depend on liveness analysis. There are three versions of liveness analysis (in order of increasing cost):
1. Lightweight. This computes last-uses for variables local to a single basic block.
2. Full. This computes last-uses for all variables based on global dataflow analysis.
3. Full live ranges. This computes all last-uses, plus calculates the live range intervals in terms of instruction numbers. (The live ranges are needed for register allocation.)
For testing the full live range computation, Cfg::validateLiveness() checks every Variable of every Inst and verifies that the current Inst is contained within the Variable's live range.
The cross tests are run with O2 in addition to Om1.
Some of the lit tests (for what good they do) are updated with O2 code sequences.
BUG= none
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/300563003
diff --git a/src/IceCfg.h b/src/IceCfg.h
index 5f3bfd3..dbf08c6 100644
--- a/src/IceCfg.h
+++ b/src/IceCfg.h
@@ -58,7 +58,7 @@
const NodeList &getNodes() const { return Nodes; }
// Manage instruction numbering.
- int32_t newInstNumber() { return NextInstNumber++; }
+ InstNumberT newInstNumber() { return NextInstNumber++; }
// Manage Variables.
Variable *makeVariable(Type Ty, const CfgNode *Node,
@@ -72,6 +72,7 @@
// Miscellaneous accessors.
TargetLowering *getTarget() const { return Target.get(); }
+ Liveness *getLiveness() const { return Live.get(); }
bool hasComputedFrame() const;
// Passes over the CFG.
@@ -80,11 +81,16 @@
// compute the predecessor edges, in the form of
// CfgNode::InEdges[].
void computePredecessors();
+ void renumberInstructions();
void placePhiLoads();
void placePhiStores();
void deletePhis();
+ void doAddressOpt();
void genCode();
void genFrame();
+ void livenessLightweight();
+ void liveness(LivenessMode Mode);
+ bool validateLiveness() const;
// Manage the CurrentNode field, which is used for validating the
// Variable::DefNode field during dumping/emitting.
@@ -92,7 +98,7 @@
const CfgNode *getCurrentNode() const { return CurrentNode; }
void emit();
- void dump();
+ void dump(const IceString &Message = "");
// Allocate data of type T using the per-Cfg allocator.
template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
@@ -136,9 +142,10 @@
IceString ErrorMessage;
CfgNode *Entry; // entry basic block
NodeList Nodes; // linearized node list; Entry should be first
- int32_t NextInstNumber;
+ InstNumberT NextInstNumber;
VarList Variables;
VarList Args; // subset of Variables, in argument order
+ llvm::OwningPtr<Liveness> Live;
llvm::OwningPtr<TargetLowering> Target;
// CurrentNode is maintained during dumping/emitting just for