From 27f3de54874ab86bd53a50fc3f1b390273722ec9 Mon Sep 17 00:00:00 2001
From: Clark Coleman <clc@zephyr-software.com>
Date: Tue, 25 Aug 2020 17:40:15 -0400
Subject: [PATCH] SPARK crash fixes.

---
 src/base/SMPFunction.cpp | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp
index 15ff7959..05576858 100644
--- a/src/base/SMPFunction.cpp
+++ b/src/base/SMPFunction.cpp
@@ -12074,6 +12074,14 @@ void SMPFunction::FindGuardedLoops(void) {
 							SMPBasicBlock *NextBlock = (*NextBlockIter);
 							if (NextBlock->IsLoopHeaderBlock()) {
 								// The less simple case: some [straight-line code] between COND_BRANCH and loop header.
+
+								// To prevent being deceived by the case in which we fall through 
+								//  to the tail block, which the compiler has placed so that the tail block falls through
+								//  to the loop header block, we require that the FallThroughBlock must dominate the loop
+								//  header block. Simple, fast screening before concluding.
+								bool CorrectDomTreeStructure = this->DoesBlockDominateBlock((int) BlockIndex, NextBlock->GetNumber());
+								if (!CorrectDomTreeStructure)
+									continue; // move on to next block
 								FoundGuardedLoop = true;
 								LoopAddr = NextBlock->GetFirstNonMarkerAddr();
 							}
@@ -18125,7 +18133,7 @@ void SMPFunction::Dump(void) {
 	if (this->LoopCount > 0) {
 		SMP_msg("Block numbers by loop number:\n");
 		for (size_t LoopNum = 0; LoopNum < this->LoopCount; ++LoopNum) {
-			SMP_msg("Loop %d : ", LoopNum);
+			SMP_msg("Loop %d : Loop Type: %d :", LoopNum, this->LoopTypesByLoopNum[LoopNum]);
 			for (size_t BlockNum = 0; BlockNum < (size_t)this->BlockCount; ++BlockNum) {
 				if (this->FuncBlocksByLoop[LoopNum].GetBit(BlockNum)) {
 					SMP_msg(" %zu", BlockNum);
@@ -18796,6 +18804,13 @@ void SMPFunction::PreProcessForSPARKAdaTranslation(void) {
 			}
 		}
 		size_t BlockNum = (size_t) CurrBlock->GetNumber();
+		vector<SMPInstr *>::const_reverse_iterator LastInstIter = CurrBlock->GetRevInstCBegin();
+		SMPInstr *LastInst = (*LastInstIter);
+		if (LastInst->IsBranchToOtherFunc()) {
+			SMP_msg("SPARK: WARNING: Bad CFG (branch outside function at %llx) \n", (uint64_t)LastInst->GetAddr());
+			this->HasStructuredCFG = false;
+		}
+
 		if (HasLoops && CurrBlock->HasMemoryWrite() && this->IsBlockInAnyLoop((int) BlockNum)) {
 			for (vector<SMPInstr *>::iterator InstIter = CurrBlock->GetFirstInst(); InstIter != CurrBlock->GetLastInst(); ++InstIter) {
 				SMPInstr *CurrInst = (*InstIter);
@@ -20217,7 +20232,7 @@ void SMPFunction::EmitFuncSPARKAda(void) {
 #else
 	int FollowBlockNum = SMP_BLOCKNUM_UNINIT;
 #endif
-	this->EmitSPARKAdaForBlock(0, FollowBlockNum, BodyFile, false);
+	this->EmitSPARKAdaForBlock(0, FollowBlockNum, BodyFile, false, false);
 
 	SMP_fprintf(BodyFile, "\nend %s;\n\n", AdaFuncName.c_str());
 	STARS_SPARK_IndentCount = 1;
@@ -21636,8 +21651,10 @@ void SMPFunction::EmitSPARKAdaForBlock(int CurrBlockNum, int FollowBlockNum, FIL
 			bool TranslatingGuardedLoop = (this->LoopToGuardMap.find(LoopAddr) != this->LoopToGuardMap.cend());
 			int NextFollowBlockNum = this->LoopFollowNodes[LoopNum];
 			// Could end with a loop if we call abort, etc., in which case no follow block.
-			//  Otherwise, we should have a follow block.
-			assert((SMP_BLOCKNUM_UNINIT != NextFollowBlockNum) || (!this->FuncReturnsToCaller()));
+			//  Could be an infinite loop. Otherwise, we should have a follow block.
+			bool FuncMightNotReturn = ((!this->FuncReturnsToCaller()) || this->HasCallToNonReturningFunc());
+			bool LoopMightBeInfinite = (STARS_INFINITE_OR_MIDDLE_TESTING_LOOP == this->LoopTypesByLoopNum[LoopNum]);
+			assert((SMP_BLOCKNUM_UNINIT != NextFollowBlockNum) || FuncMightNotReturn || LoopMightBeInfinite);
 
 			if (LoopToProc) {
 				assert(TranslatingGuardedLoop || (ResumeBlockNum == NextFollowBlockNum)); // should be passed in as loop follow block number
@@ -21761,7 +21778,7 @@ void SMPFunction::EmitSPARKAdaForBlock(int CurrBlockNum, int FollowBlockNum, FIL
 				}
 				else if (FlowType == JUMP) {
 					// Get control flow type of the jump
-					assert(1 == CurrBlock->GetNumSuccessors());
+					assert((1 == CurrBlock->GetNumSuccessors()) || LastInst->IsBranchToOtherFunc());
 					if (JUMP_INTO_LOOP_TEST == LastCFType) {
 						// Optimized top-testing loop becomes a bottom-testing loop with a jump to the loop header/loop-test
 						//  block for the first iteration. We translate as a top-testing loop in Ada by starting with the 
@@ -21834,7 +21851,10 @@ void SMPFunction::EmitSPARKAdaForBlock(int CurrBlockNum, int FollowBlockNum, FIL
 					ResumeBlockNum = FallThroughSucc->GetNumber();
 				}
 				else {
-					assert(((FlowType == CALL) || (FlowType == HALT) || CurrBlock->IsUnreachableBlock()) && (0 == NumSuccessors));
+					// Nop at end of block could be for alignment, masking the control flow type of CALL
+					//  or HALT before it.
+					assert(((FlowType == CALL) || (FlowType == HALT) || CurrBlock->IsUnreachableBlock() || LastInst->IsNop())
+						&& (0 == NumSuccessors));
 				}
 			}
 		} // end if header block ... elsif tail block ... else ...
-- 
GitLab