Commit 263ac526 by David Sehr

Replace constant conditional branches by unconditional branches

BUG= R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1847423003 .
parent 318c01bc
...@@ -283,7 +283,7 @@ void Cfg::computeInOutEdges() { ...@@ -283,7 +283,7 @@ void Cfg::computeInOutEdges() {
TimerMarker T(TimerStack::TT_phiValidation, this); TimerMarker T(TimerStack::TT_phiValidation, this);
for (CfgNode *Node : Nodes) for (CfgNode *Node : Nodes)
Node->validatePhis(); Node->enforcePhiConsistency();
} }
void Cfg::renumberInstructions() { void Cfg::renumberInstructions() {
......
...@@ -84,11 +84,15 @@ void CfgNode::computeSuccessors() { ...@@ -84,11 +84,15 @@ void CfgNode::computeSuccessors() {
OutEdges = Insts.rbegin()->getTerminatorEdges(); OutEdges = Insts.rbegin()->getTerminatorEdges();
} }
// Validate each Phi instruction in the node with respect to control flow. For // Ensure each Phi instruction in the node is consistent with respect to control
// every phi argument, its label must appear in the predecessor list. For each // flow. For each predecessor, there must be a phi argument with that label.
// predecessor, there must be a phi argument with that label. We don't check // If a phi argument's label doesn't appear in the predecessor list (which can
// that phi arguments with the same label have the same value. // happen as a result of e.g. unreachable node elimination), its value is
void CfgNode::validatePhis() { // modified to be zero, to maintain consistency in liveness analysis. This
// allows us to remove some dead control flow without a major rework of the phi
// instructions. We don't check that phi arguments with the same label have the
// same value.
void CfgNode::enforcePhiConsistency() {
for (Inst &Instr : Phis) { for (Inst &Instr : Phis) {
auto *Phi = llvm::cast<InstPhi>(&Instr); auto *Phi = llvm::cast<InstPhi>(&Instr);
// We do a simple O(N^2) algorithm to check for consistency. Even so, it // We do a simple O(N^2) algorithm to check for consistency. Even so, it
...@@ -106,8 +110,11 @@ void CfgNode::validatePhis() { ...@@ -106,8 +110,11 @@ void CfgNode::validatePhis() {
break; break;
} }
} }
if (!Found) if (!Found) {
llvm::report_fatal_error("Phi error: label for bad incoming edge"); // Predecessor was unreachable, so if (impossibly) the control flow
// enters from that predecessor, the value should be zero.
Phi->clearOperandForTarget(Label);
}
} }
for (CfgNode *InNode : getInEdges()) { for (CfgNode *InNode : getInEdges()) {
bool Found = false; bool Found = false;
......
...@@ -90,7 +90,7 @@ public: ...@@ -90,7 +90,7 @@ public:
CfgNode *splitIncomingEdge(CfgNode *Pred, SizeT InEdgeIndex); CfgNode *splitIncomingEdge(CfgNode *Pred, SizeT InEdgeIndex);
/// @} /// @}
void validatePhis(); void enforcePhiConsistency();
void placePhiLoads(); void placePhiLoads();
void placePhiStores(); void placePhiStores();
void deletePhis(); void deletePhis();
......
...@@ -304,7 +304,13 @@ InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue_, ...@@ -304,7 +304,13 @@ InstBr::InstBr(Cfg *Func, Operand *Source, CfgNode *TargetTrue_,
CfgNode *TargetFalse_) CfgNode *TargetFalse_)
: InstHighLevel(Func, Inst::Br, 1, nullptr), TargetFalse(TargetFalse_), : InstHighLevel(Func, Inst::Br, 1, nullptr), TargetFalse(TargetFalse_),
TargetTrue(TargetTrue_) { TargetTrue(TargetTrue_) {
if (TargetTrue == TargetFalse) { if (auto *Constant = llvm::dyn_cast<ConstantInteger32>(Source)) {
int32_t C32 = Constant->getValue();
if (C32 != 0) {
TargetFalse = TargetTrue;
}
TargetTrue = nullptr; // turn into unconditional version
} else if (TargetTrue == TargetFalse) {
TargetTrue = nullptr; // turn into unconditional version TargetTrue = nullptr; // turn into unconditional version
} else { } else {
addSource(Source); addSource(Source);
...@@ -392,8 +398,7 @@ void InstPhi::addArgument(Operand *Source, CfgNode *Label) { ...@@ -392,8 +398,7 @@ void InstPhi::addArgument(Operand *Source, CfgNode *Label) {
} }
// Find the source operand corresponding to the incoming edge for the given // Find the source operand corresponding to the incoming edge for the given
// node. TODO: This uses a linear-time search, which could be improved if it // node.
// becomes a problem.
Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { Operand *InstPhi::getOperandForTarget(CfgNode *Target) const {
for (SizeT I = 0; I < getSrcSize(); ++I) { for (SizeT I = 0; I < getSrcSize(); ++I) {
if (Labels[I] == Target) if (Labels[I] == Target)
...@@ -403,6 +408,19 @@ Operand *InstPhi::getOperandForTarget(CfgNode *Target) const { ...@@ -403,6 +408,19 @@ Operand *InstPhi::getOperandForTarget(CfgNode *Target) const {
return nullptr; return nullptr;
} }
// Replace the source operand corresponding to the incoming edge for the given
// node by a zero of the appropriate type.
void InstPhi::clearOperandForTarget(CfgNode *Target) {
for (SizeT I = 0; I < getSrcSize(); ++I) {
if (getLabel(I) == Target) {
Type Ty = Dest->getType();
Srcs[I] = Target->getCfg()->getContext()->getConstantZero(Ty);
return;
}
}
llvm_unreachable("Phi target not found");
}
// Updates liveness for a particular operand based on the given predecessor // Updates liveness for a particular operand based on the given predecessor
// edge. Doesn't mark the operand as live if the Phi instruction is dead or // edge. Doesn't mark the operand as live if the Phi instruction is dead or
// deleted. // deleted.
......
...@@ -622,6 +622,7 @@ public: ...@@ -622,6 +622,7 @@ public:
} }
void addArgument(Operand *Source, CfgNode *Label); void addArgument(Operand *Source, CfgNode *Label);
Operand *getOperandForTarget(CfgNode *Target) const; Operand *getOperandForTarget(CfgNode *Target) const;
void clearOperandForTarget(CfgNode *Target);
CfgNode *getLabel(SizeT Index) const { return Labels[Index]; } CfgNode *getLabel(SizeT Index) const { return Labels[Index]; }
void livenessPhiOperand(LivenessBV &Live, CfgNode *Target, void livenessPhiOperand(LivenessBV &Live, CfgNode *Target,
Liveness *Liveness); Liveness *Liveness);
......
...@@ -72,18 +72,9 @@ b6: ...@@ -72,18 +72,9 @@ b6:
; CHECK-NEXT: b1: ; CHECK-NEXT: b1:
; CHECK-NEXT: %v0 = add i32 %p0, %v3 ; CHECK-NEXT: %v0 = add i32 %p0, %v3
; CHECK-NEXT: br label %b6 ; CHECK-NEXT: br label %b6
; CHECK-NEXT: b2:
; CHECK-NEXT: %v1 = add i32 %p0, %v4
; CHECK-NEXT: br label %b6
; CHECK-NEXT: b3:
; CHECK-NEXT: %v2 = add i32 %p0, %v3
; CHECK-NEXT: br label %b6
; CHECK-NEXT: b4: ; CHECK-NEXT: b4:
; CHECK-NEXT: %v3 = add i32 %p0, %p0 ; CHECK-NEXT: %v3 = add i32 %p0, %p0
; CHECK-NEXT: br i1 true, label %b1, label %b5 ; CHECK-NEXT: br label %b1
; CHECK-NEXT: b5:
; CHECK-NEXT: %v4 = add i32 %v3, %p0
; CHECK-NEXT: br i1 true, label %b2, label %b3
; CHECK-NEXT: b6: ; CHECK-NEXT: b6:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; CHECK-NEXT: } ; CHECK-NEXT: }
......
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