From fc64d978d758579028918348d14253bab8b97000 Mon Sep 17 00:00:00 2001
From: Clark Coleman <clc@zephyr-software.com>
Date: Mon, 5 Oct 2020 17:08:01 -0400
Subject: [PATCH] SPARK: Add INVERTED_LOOP_BACK type, detect it, follow its
 successor when StaysInLoop is true.

---
 include/base/SMPBasicBlock.h       |  1 +
 include/base/SMPDataFlowAnalysis.h |  3 ++-
 src/base/SMPBasicBlock.cpp         | 23 ++++++++++++++++++++++-
 src/base/SMPDataFlowAnalysis.cpp   |  4 ++--
 src/base/SMPFunction.cpp           | 19 ++++++++++++++++---
 src/base/SMPInstr.cpp              |  2 +-
 6 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/include/base/SMPBasicBlock.h b/include/base/SMPBasicBlock.h
index 5080d4a7..067a4782 100644
--- a/include/base/SMPBasicBlock.h
+++ b/include/base/SMPBasicBlock.h
@@ -351,6 +351,7 @@ public:
 	bool IsBlockPred(int BlockNum) const; // Is BlockNum a predecessor block of this block
 	bool HasLoopHeadAsSuccessor(int &HeadBlockNum) const; // block has HeadBlockNum as successor, which is a loop header
 	bool HasLoopHeadWithInvertedExitAsSuccessor(void) const; // block has loop head successor that ends with INVERTED_LOOP_EXIT
+	bool HasInvertedLoopBack(void) const; // COND_BRANCH falls through to loop header of innermost loop containing this block
 	bool IsLiveIn(const STARSOpndTypePtr &CurrOp);
 	inline bool IsLiveOut(const STARSOpndTypePtr &CurrOp) const {
 		return (LiveOutSet.end() != LiveOutSet.find(CurrOp));
diff --git a/include/base/SMPDataFlowAnalysis.h b/include/base/SMPDataFlowAnalysis.h
index fef5ea87..381c58ef 100644
--- a/include/base/SMPDataFlowAnalysis.h
+++ b/include/base/SMPDataFlowAnalysis.h
@@ -671,7 +671,8 @@ enum ControlFlowType {
 	JUMP_TO_SWITCH_INDIR_JUMP = 9,  // jump around default case or preliminary calculations to INDIR_JUMP block for switch
 	SHORT_CIRCUIT_BRANCH = 10,   // any branch in short-circuit conditional evaluation
 	SHORT_CIRCUIT_LOOP_EXIT = 11,  // short-circuit compound conditional expression that exits loop when true
-	INVERTED_LOOP_EXIT = 12 // COND_BRANCH falls out of loop via headerblock, branch taken stays in loop; code layout puts headerblock at bottom
+	INVERTED_LOOP_EXIT = 12, // COND_BRANCH falls out of loop via headerblock, branch taken stays in loop; code layout puts headerblock at bottom
+	INVERTED_LOOP_BACK = 13 // COND_BRANCH falls through to loop headerblock of its containing innermost loop
 };
 
 // Strings for debug dumps of ControlFlowType.
diff --git a/src/base/SMPBasicBlock.cpp b/src/base/SMPBasicBlock.cpp
index d7471f75..f5329462 100644
--- a/src/base/SMPBasicBlock.cpp
+++ b/src/base/SMPBasicBlock.cpp
@@ -1139,6 +1139,26 @@ bool SMPBasicBlock::HasLoopHeadWithInvertedExitAsSuccessor(void) const {
 	return OddFlowCase;
 } // end of SMPBasicBlock::HasLoopHeadWithInvertedExitAsSuccessor()
 
+// COND_BRANCH falls through to loop header of innermost loop containing this block
+bool SMPBasicBlock::HasInvertedLoopBack(void) const {
+	bool FallsThroughToLoopHead = false;
+	if (this->HasConditionalBranch()) {
+		list<SMPBasicBlock *>::const_iterator SuccIter = this->GetCondNonFallThroughSucc();
+		SMPBasicBlock *SuccBlock = (*SuccIter);
+		assert(nullptr != SuccBlock);
+		int TargetBlockNum = SuccBlock->GetNumber();
+		SuccIter = this->GetCondOtherSucc(TargetBlockNum);
+		SuccBlock = (*SuccIter);
+		assert(nullptr != SuccBlock);
+		int FallThroughBlockNum = SuccBlock->GetNumber();
+		if (SuccBlock->IsLoopHeaderBlock()) {
+			FallsThroughToLoopHead = (SuccBlock->IsLoopHeaderBlock() && this->GetFunc()->AreBlocksInSameLoops(FallThroughBlockNum, this->GetNumber()));
+		}
+	}
+
+	return FallsThroughToLoopHead;
+} // end of SMPBasicBlock::HasInvertedLoopBack()
+
 
 // Determine if CurrOp is LiveIn; if LiveIn set is stale, recompute.
 bool SMPBasicBlock::IsLiveIn(const STARSOpndTypePtr &CurrOp) {
@@ -2683,7 +2703,8 @@ bool SMPBasicBlock::DoesDefControlLoopFlow(const STARSOpndTypePtr &DefOp, int De
 	if (FlowType == COND_BRANCH) {
 		STARS_ea_t LastAddr = LastInst->GetAddr();
 		ControlFlowType LastBranchType = this->GetFunc()->GetControlFlowType(LastAddr);
-		if ((LastBranchType != LOOP_EXIT) && (LastBranchType != LOOP_BACK)) {
+		bool IsLoopBack = ((LastBranchType == LOOP_BACK) || (LastBranchType == INVERTED_LOOP_BACK));
+		if ((LastBranchType != LOOP_EXIT) && (!IsLoopBack)) {
 			return false;
 		}
 	}
diff --git a/src/base/SMPDataFlowAnalysis.cpp b/src/base/SMPDataFlowAnalysis.cpp
index 489777f0..f5e3ed84 100644
--- a/src/base/SMPDataFlowAnalysis.cpp
+++ b/src/base/SMPDataFlowAnalysis.cpp
@@ -163,8 +163,8 @@ const char *SPARKFloatingPointStackRegNames[8] = { "FloatingPointStackDummy", "F
 
 const char *CFTTypeStrings[20] = { "FALL_THROUGH", "BRANCH_IF_THEN", "BRANCH_IF_THEN_ELSE", "JUMP_BEFORE_ELSE",
 "LOOP_BACK", "LOOP_EXIT", "JUMP_INTO_LOOP_TEST", "JUMP_TO_DEFAULT_CASE", "CASE_BREAK_TO_FOLLOW_NODE",
-"JUMP_TO_SWITCH_INDIR_JUMP", "SHORT_CIRCUIT_BRANCH", "SHORT_CIRCUIT_LOOP_EXIT", "INVERTED_LOOP_EXIT",
-"", "", "", "", "", "", ""
+"JUMP_TO_SWITCH_INDIR_JUMP", "SHORT_CIRCUIT_BRANCH", "SHORT_CIRCUIT_LOOP_EXIT", "INVERTED_LOOP_EXIT", 
+"INVERTED_LOOP_BACK", "", "", "", "", "", ""
 };
 
 // Distinguishes subword regs from their parent regs
diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp
index 8642815e..cf8599f5 100644
--- a/src/base/SMPFunction.cpp
+++ b/src/base/SMPFunction.cpp
@@ -12093,7 +12093,8 @@ int SMPFunction::TrackConditionalBranchTerminus(int BranchHeadBlockNum, int Curr
 		list<int> WorkListBlockNums;
 		STARS_ea_t LastAddr = CurrBlock->GetLastAddr();
 		ControlFlowType LastCFType = this->GetControlFlowType(LastAddr);
-		if (LastCFType == LOOP_BACK) {
+		bool IsLoopBack = ((LastCFType == LOOP_BACK) || (LastCFType == INVERTED_LOOP_BACK));
+		if (IsLoopBack) {
 			// Don't follow back edge, but get the other successor, if conditional.
 			vector<SMPInstr *>::const_reverse_iterator LastInstIter = CurrBlock->GetRevInstCBegin();
 			if (COND_BRANCH == (*LastInstIter)->GetDataFlowType()) {
@@ -17014,7 +17015,12 @@ void SMPFunction::MarkSpecialNumericErrorCases(void) {
 				}
 				else if (CurrBlock->IsLoopTailBlock()) {
 					// We must be looping back to the loop header.
-					this->SetControlFlowType(InstAddr, LOOP_BACK);
+					if (CurrBlock->HasInvertedLoopBack()) { // falling through to loop header
+						this->SetControlFlowType(InstAddr, INVERTED_LOOP_BACK);
+					}
+					else { // normal case; branching to loop header
+						this->SetControlFlowType(InstAddr, LOOP_BACK);
+					}
 					if (COND_BRANCH == CurrDataFlowType) {
 						int HeaderBlockNum = CurrBlock->GetLoopHeaderNumber();
 						if (!CurrBlock->IsDoubleLoopTailBlock()) { // normal case
@@ -23031,8 +23037,9 @@ void SMPFunction::EmitSPARKAdaForConditional(int HeaderBlockNum, int FollowBlock
 	//  For the if-then case, we emit the code for the then-block and then "end if;" and return.
 	//  For the if-then-else case, we emit the code for the then-block and then "else" etc.
 	ControlFlowType LastCFType = this->GetControlFlowType(LastAddr);
+	bool IsLoopBack = ((LastCFType == LOOP_BACK) || (LastCFType == INVERTED_LOOP_BACK));
 	bool StaysInLoop = this->IsNonExitingLoopBackBranch(LastAddr);
-	bool IfThenCase = ((LastCFType == BRANCH_IF_THEN) || (StaysInLoop && ((LastCFType == LOOP_BACK) || (LastCFType == LOOP_EXIT))));
+	bool IfThenCase = ((LastCFType == BRANCH_IF_THEN) || (StaysInLoop && (IsLoopBack || (LastCFType == LOOP_EXIT))));
 	bool ShortCircuitCase = (LastCFType == SHORT_CIRCUIT_BRANCH);
 	assert(IfThenCase || ShortCircuitCase || (LastCFType == BRANCH_IF_THEN_ELSE));
 	int FallThroughBlockNum = SMP_BLOCKNUM_UNINIT;
@@ -23056,6 +23063,12 @@ void SMPFunction::EmitSPARKAdaForConditional(int HeaderBlockNum, int FollowBlock
 		assert(2 == HeaderBlock->GetNumSuccessors());
 		SuccIter = HeaderBlock->GetFallThroughSucc();
 		FallThroughBlockNum = (*SuccIter)->GetNumber();
+		if (LastCFType == INVERTED_LOOP_BACK) {
+			// Swap the fall-through and distant blocks.
+			int TempBlockNum = DistantBlockNum;
+			DistantBlockNum = FallThroughBlockNum;
+			FallThroughBlockNum = TempBlockNum;
+		}
 	}
 	SMPBasicBlock *ThenBlock = this->RPOBlocks[(size_t) FallThroughBlockNum];
 	bool CheckFTBlock = false; // check for falling out of loop?
diff --git a/src/base/SMPInstr.cpp b/src/base/SMPInstr.cpp
index 90b69a51..b94aa382 100644
--- a/src/base/SMPInstr.cpp
+++ b/src/base/SMPInstr.cpp
@@ -7014,7 +7014,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) {
 					; // jumps around else clauses are handled in SMPFunction::EmitSPARKAdaForConditional()
 				}
 			}
-			else if (LOOP_BACK == FuncControlFlowType) {
+			else if ((LOOP_BACK == FuncControlFlowType) || (INVERTED_LOOP_BACK == FuncControlFlowType)) {
 				// We must be looping back to the loop header.
 				if (JUMP == CurrDataFlowType) { // simple case
 #if STARS_SPARK_CENTRALIZE_EMIT_LOOP
-- 
GitLab