diff --git a/include/base/SMPDataFlowAnalysis.h b/include/base/SMPDataFlowAnalysis.h
index 8cddee777eeb8e4a23355e8963591839f99e49c5..2132304e905feaf81441743ecca776213c8bb9fd 100644
--- a/include/base/SMPDataFlowAnalysis.h
+++ b/include/base/SMPDataFlowAnalysis.h
@@ -174,7 +174,7 @@ STARSOpndTypePtr CloneIfNecessary(const STARSOpndTypePtr &CurrOp, bool UseFP);
 void PrintDefUse(unsigned long feature, int OpNum);
 void PrintSIB(const STARSOpndTypePtr &Opnd);
 void AnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, char OutString[STARS_MAXSTR], bool Has64BitOperands);
-void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands);
+void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands, bool UseSavedStackPtr);
 void SPARKAnnotSIBToString(const STARSOpndTypePtr &Opnd, bool HasOffset, std::string &OutString, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands);
 void PrintOneOperand(const STARSOpndTypePtr &Opnd, uint32_t features, int OpNum);
 void PrintListOperand(const STARSOpndTypePtr &Opnd, int SSANum = SMP_SSA_UNINIT); 
diff --git a/include/base/SMPFunction.h b/include/base/SMPFunction.h
index cd4683a26a93d040e430686f397418029bcd0419..9976d56514d5ad11e20c07fcc1447f59b823105e 100644
--- a/include/base/SMPFunction.h
+++ b/include/base/SMPFunction.h
@@ -851,6 +851,7 @@ private:
 	void EmitSPARKArgs(FILE *BodyFile, FILE *HeaderFile, bool Signature, std::size_t LoopIndex) const; // Emit loop function args, as Signature to HeaderFile or proc call to BodyFile.
 	void EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *HeaderFile, bool PreconditionSection); // Emit mem writing ranges for pre- and post-conditions
 	bool NeedsSPARKPreconditions(bool &HasLoopMemWrites, bool &HasNonLoopInArgMemWrites, bool &HasCalleeMemWrites); // Determine if any mem writes (or callee mem writes) are not just to the stack frame locals.
+	bool LoopRequiresNonStackPreconditions(size_t LoopIndex) const; // Loop indirect writes require pre-conditions
 	std::string EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlockNum, int FollowBlockNum, FILE *BodyFile, FILE *HeaderFile); // Create SPARK procedure for loop starting at HeaderBlockNum
 	void AnalyzeLoopGlobals(int HeaderBlockNum, int FollowBlockNum, bool &MemoryInput, bool &MemoryOutput, std::bitset<1 + MD_LAST_REG_NO> &InputRegs, std::bitset<1 + MD_LAST_REG_NO> &OutputRegs); // Analyze reg and mem accesses in loop
 	void EmitSPARKLoopProcGlobals(FILE *BodyFile, FILE *HeaderFile, bool MemoryInput, bool MemoryOutput, const std::bitset<1 + MD_LAST_REG_NO> &InputRegs, const std::bitset<1 + MD_LAST_REG_NO> &OutputRegs); // emit Input, Output, In_Out flow annotations
diff --git a/include/base/SMPInstr.h b/include/base/SMPInstr.h
index 562e3f0478d3334b36d5de37dc7b4f0a09a08d0e..634c7a34220f013819f9cd86a5da19201cd9ef2e 100644
--- a/include/base/SMPInstr.h
+++ b/include/base/SMPInstr.h
@@ -175,6 +175,10 @@ inline bool IsRelationalOperator(SMPoperator Oper) {
 	return ((Oper >= SMP_LESS_THAN) && (Oper <= SMP_ABOVE_EQUAL));
 };
 
+inline bool IsIntegerAddOrSubOperator(SMPoperator Oper) {
+	return ((Oper >= SMP_DECREMENT) && (Oper <= SMP_SUBTRACT_BORROW));
+};
+
 // Take RelationalOperator from a comparison instruction, as determined by its matching jump,
 //  and convert it to the operator needed if the comparison operands are swapped.
 //  E.g.: cmp rax,rbx followed by ja label1 produces SMP_GREATER_THAN operator.
@@ -401,10 +405,11 @@ public:
 	inline bool HasRightSubTree(void) const { return (booleans1 & EXPR_SET_RIGHT_SUBTREE); };
 	inline bool HasLeftSubTree(void) const { return (booleans1 & EXPR_SET_LEFT_SUBTREE); };
 	bool IsEqualExpr(const STARSExpression *OtherExpr) const; // are exprs identical in operands and operators?
+	bool IsStackPtrPlusOffset(void) const; // Is Expr just the stack pointer plus optional offset constant?
 
 	// Printing methods
 	void Dump(const std::size_t TabCount = 0) const;
-	void EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs = false) const;  // Emit SPARK Ada translation of expression to OutputFile, perhaps with Reg'Old suffix.
+	void EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr = false) const;  // Emit SPARK Ada translation of expression to OutputFile, perhaps with Reg'Old suffix.
 	void EmitSPARKAdaString(std::string &OutString, bool ProcessingLoop, bool OldSuffix, bool OffByOne) const;  // Emit SPARK Ada translation of expression to OutString, perhaps with Reg'Old suffix.
 	void EmitSPARKInSafeRegion64(FILE *OutputFile, size_t MemWidth) const; // Emit X86.InSafeRegion64(..., X86.RSP) for each byte in memory expr
 	void PrintSPARKArgLocationStrings(FILE *OutputFile, bool LoopInvariant); // create vector of strings matching loop-function parameters to their incoming locations
@@ -815,9 +820,9 @@ public:
 	void PrintDeadRegs(FILE *OutputFile); // print the registers that are dead right before this instruction.
 	void Dump(void); // Complete debug print, with DEF/USE list, SSA #s, RTL
 	// Print an operand in SPARK-Ada form.
-	void PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace);
+	void PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr = false);
 	void SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string &OutString, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace);
-	void PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP);  // e.g. for [RBP-8] print RBP-8 only
+	void PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP, bool UseSavedStackPtr);  // e.g. for [RBP-8] print RBP-8 only
 	void MDEmitSPARKAdaStringOperation(FILE *OutFile); // emit SPARK Ada for string operation, perhaps with repeat prefix that makes it a loop.
 	void MDEmitSPARKAdaCompareOrTest(FILE *OutFile); // emit SPARK Ada for setting flags only (compare or test opcodes)
 	void MDEmitSPARKAdaArithmeticSetsCondCodes(FILE *OutFile); // emit SPARK Ada for ops that set flags (add, sub, etc.)
diff --git a/src/base/SMPDataFlowAnalysis.cpp b/src/base/SMPDataFlowAnalysis.cpp
index 0c504fd83837c9e57fcd8b30cbf5de7b23cc8b9e..5c9bb80884f4af5ceccd9102209676ac7bf1944f 100644
--- a/src/base/SMPDataFlowAnalysis.cpp
+++ b/src/base/SMPDataFlowAnalysis.cpp
@@ -840,7 +840,7 @@ void AnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile,
 } // end AnnotPrintSIB()
 
 // Annotations: concisely print SIB info for an operand.
-void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands) {
+void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutFile, STARS_regnum_t SegReg, bool UseFP, bool Has64BitOperands, bool UseSavedStackPtr) {
 	int BaseReg;
 	int IndexReg;
 	uint16_t ScaleFactor;
@@ -880,15 +880,25 @@ void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutF
 			(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
 		}
 #endif
-		(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
-		(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) BaseReg, ByteWidth), STARS_MAXSTR - 1);
+		if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
+			(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR - 1);
+			(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t)BaseReg, ByteWidth), STARS_MAXSTR - 1);
+		}
+		else {
+			(void) SMP_strncat(OutString, "SaveStackPtr", STARS_MAXSTR - 1);
+		}
 		if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
 			++SubwordAddressRegCount;
 		}
 		if (IndexReg != STARS_x86_R_none) {
-			(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
-			(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
-			(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) IndexReg, ByteWidth), STARS_MAXSTR - 1);
+			(void) SMP_strncat(OutString, " + ", STARS_MAXSTR - 1);
+			if (!(UseSavedStackPtr && (IndexReg == MD_STACK_POINTER_REG))) {
+				(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR - 1);
+				(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) IndexReg, ByteWidth), STARS_MAXSTR - 1);
+			}
+			else {
+				(void) SMP_strncat(OutString, "SaveStackPtr", STARS_MAXSTR - 1);
+			}
 			if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
 				++SubwordAddressRegCount;
 			}
@@ -904,8 +914,13 @@ void SPARKAnnotPrintSIB(const STARSOpndTypePtr &Opnd, bool HasOffset, FILE *OutF
 			(void) SMP_strncat(OutString, " + ", STARS_MAXSTR-1);
 		}
 #endif
-		(void) SMP_strncat(OutString, "X86.", STARS_MAXSTR-1);
-		(void) SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t) IndexReg, ByteWidth), STARS_MAXSTR - 1);
+		if (!(UseSavedStackPtr && (IndexReg == MD_STACK_POINTER_REG))) {
+			(void)SMP_strncat(OutString, "X86.", STARS_MAXSTR - 1);
+			(void)SMP_strncat(OutString, MDGetRegNumName((STARS_regnum_t)IndexReg, ByteWidth), STARS_MAXSTR - 1);
+		}
+		else {
+			(void)SMP_strncat(OutString, "SaveStackPtr", STARS_MAXSTR - 1);
+		}
 		if (global_STARS_program->GetSTARS_ISA_Bytewidth() > ByteWidth) {
 			++SubwordAddressRegCount;
 		}
diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp
index 1fb0d67adabab670c098e1b21edbc18d1fe4f140..232dd83f2b8c56ab615b81d83c0deff21a0a69a5 100644
--- a/src/base/SMPFunction.cpp
+++ b/src/base/SMPFunction.cpp
@@ -6796,11 +6796,11 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 	// For now, we will limit ourselves to BIVars with a loop update of BIV += 1 or BIV -= 1.
 	bool SimpleBIV = (IVFamily.BasicInductionVar.Multiplier.GetOp()->IsImmedOp()
 		&& (IVFamily.BasicInductionVar.Multiplier.GetOp()->GetImmedValue() == 1)
-		&& IVFamily.BasicInductionVar.Addend.GetOp()->IsImmedOp()
-		&& (1 == IVFamily.BasicInductionVar.Addend.GetOp()->GetImmedValue()));
+		&& IVFamily.BasicInductionVar.Addend.GetOp()->IsImmedOp());
 	if (!SimpleBIV)
 		return nullptr;
 
+	STARS_uval_t IncDecValue = IVFamily.BasicInductionVar.Addend.GetOp()->GetImmedValue();
 	bool PositiveIncrement = (!IVFamily.BasicInductionVar.SubtractAddend);
 	bool BottomTestingLoop = (this->LoopTypesByLoopNum[LoopIndex] == STARS_BOTTOM_TESTING_LOOP);
 
@@ -6812,24 +6812,40 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 	//     Y               Y                   >=             (Limit - Init) / 1
 	//     Y               Y                   <              undefined
 	//     Y               Y                   <=             undefined
+	//     Y               Y                   ==             (Limit - Init) / 1
+	//     Y               Y                   !=             undefined
 	//     Y               N                   >              undefined
 	//     Y               N                   >=             undefined
 	//     Y               N                   <              (Limit - Init) / 1
 	//     Y               N                   <=             (Limit + 1 - Init) / 1
-	//     N               Y                   >              (Limit + 2 - Init) / 1
-	//     N               Y                   >=             (Limit + 1 - Init) / 1
+	//     Y               N                   ==             undefined
+	//     Y               N                   !=             (Limit - Init) / 1
+	//     N               Y                   >              (Limit + 1 - Init) / 1
+	//     N               Y                   >=             (Limit - Init) / 1
 	//     N               Y                   <              undefined
 	//     N               Y                   <=             undefined
+	//     N               Y                   ==             (Limit - Init) / 1
+	//     N               Y                   !=             undefined
 	//     N               N                   >              undefined
 	//     N               N                   >=             undefined
-	//     N               N                   <              (Limit + 1 - Init) / 1
-	//     N               N                   <=             (Limit + 2 - Init) / 1
+	//     N               N                   <              (Limit - Init) / 1
+	//     N               N                   <=             (Limit + 1 - Init) / 1
+	//     N               N                   ==             undefined
+	//     N               N                   !=             (Limit - Init) / 1
 	//
-	// We see that certain COND_BRANCH relational operators add 1 to the iteration count, and
-	// bottom-testing loops execute once more than top-testing loops with the same COND_BRANCH.
+	// We see that certain COND_BRANCH relational operators add 1 to the iteration count.
 	// Certain combinations make no sense, e.g. counting up by 1 from Init to Limit while exiting
 	// the loop when BIV < Limit. Some of these cases could be zero-trip loops that we will analyze
 	// in greater depth later.
+	// NOTE: There is no difference between top-testing and bottom-testing loops in the table.
+	//  That is because the only difference in practice is the possibility that a top-testing loop
+	//  executes zero iterations, while the bottom-testing version of the loop would execute one
+	//  iteration in that case. If we have security properties that depend on identifying zero-trip
+	//  loops, we will need a separate analysis later.
+	// NOTE: In these tables, we assume that == and != are used properly. There is the possibility
+	//  that someone could write code such as: for (i = 0; i != limit; i += 8) and have a limit
+	//  that is not a multiple of 8. Again, we will need a special-case analysis if we want to detect
+	//  the possibility of such an infinite loop.
 
 	// For loops with a BIV that counts downward by 1:
 	//
@@ -6848,6 +6864,10 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 	//     N               N                   ==             undefined
 	//     N               N                   !=             (Init - Limit) / 1
 
+	// We can generalize the formulae above to allow increment or decrement by values other than 1.
+	//  Whenever we add 1 in the numerator, just add the increment or decrement value.
+	//  Whenever we divide by 1 in the denominator, divide by the increment or decrement value.
+
 	// Weed out undefined cases.
 	bool Undefined = false;
 	assert(LoopIndex < this->LoopComparisonExprs.size());
@@ -6855,11 +6875,11 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 	if (PositiveIncrement) {
 		if (this->LoopComparisonExprs[LoopIndex].ExitsLoop) {
 			Undefined = ((BranchOperator != SMP_GREATER_THAN) && (BranchOperator != SMP_GREATER_EQUAL)
-				&& (BranchOperator != SMP_ABOVE) && (BranchOperator != SMP_ABOVE_EQUAL));
+				&& (BranchOperator != SMP_ABOVE) && (BranchOperator != SMP_ABOVE_EQUAL) && (BranchOperator != SMP_EQUAL));
 		}
 		else {
 			Undefined = ((BranchOperator != SMP_LESS_THAN) && (BranchOperator != SMP_LESS_EQUAL)
-				&& (BranchOperator != SMP_BELOW) && (BranchOperator != SMP_BELOW_EQUAL));
+				&& (BranchOperator != SMP_BELOW) && (BranchOperator != SMP_BELOW_EQUAL) && (BranchOperator != SMP_NOT_EQUAL));
 		}
 	}
 	else { // Decrement by one on each iteration
@@ -6875,39 +6895,39 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 	if (Undefined)
 		return nullptr;
 
+	STARSOpndTypePtr IncDecOp = InitExpr->GetParentInst()->MakeImmediateOpnd(IncDecValue);
 	STARS_sval_t LimitIncrease = 0;
 	if (PositiveIncrement) {
-		if (BottomTestingLoop) {
-			LimitIncrease += 1;
-		}
 		if ((BranchOperator == SMP_LESS_EQUAL) || (BranchOperator == SMP_GREATER_THAN)
 			|| (BranchOperator == SMP_BELOW_EQUAL) || (BranchOperator == SMP_ABOVE)) {
-			LimitIncrease += 1; // only because we weeded out some undefined cases; change if we redefine those cases.
+			LimitIncrease += IncDecValue; // only because we weeded out some undefined cases; change if we redefine those cases.
 		}
 	}
 	else { // Decrement
 		if ((BranchOperator == SMP_LESS_THAN) || (BranchOperator == SMP_GREATER_EQUAL)
 			|| (BranchOperator == SMP_BELOW) || (BranchOperator == SMP_ABOVE_EQUAL)) {
-			LimitIncrease += 1;
+			LimitIncrease += IncDecValue;
 		}
 	}
 
 	bool NeedLimitIncrease = (0 != LimitIncrease);
 
-	// At this point, the iteration count is (Limit + LimitIncrease - Init) / 1 for the SimpleBIV cases
-	//  with PositiveIncrement, and (Init + LimitIncrease - Limit) / 1 for the Decrement case.
-	//  We will omit the division by 1, of course, although SimplifyExpr() should remove it.
+	// At this point, the iteration count is (Limit + LimitIncrease - Init) / IncDecValue for the SimpleBIV cases
+	//  with PositiveIncrement, and (Init + LimitIncrease - Limit) / IncDecValue for the Decrement case.
+	//  We will omit the division by 1 case, of course, although SimplifyExpr() should remove it.
 	// If Init is a constant, then we can fold (LimitIncrease - Init) or (Init + LimitIncrease) into a constant operand.
 	STARSExpression *IterationsExpr = new STARSExpression();
 	IterationsExpr->SetParentInst(LimitExpr->GetParentInst());
 	IterationsExpr->SetParentFunc(this);
+	bool LimitIncreaseFolded = false;
 	if (PositiveIncrement) {
 		if ((InitExpr->GetOperator() == SMP_ASSIGN) && InitExpr->GetLeftOperand()->IsImmedOp()) {
 			// Only LeftOperand is valid, and it is a constant.
-			STARS_sval_t InitValue = (STARS_sval_t)InitExpr->GetLeftOperand()->GetImmedValue();
+			STARS_sval_t InitValue = (STARS_sval_t) InitExpr->GetLeftOperand()->GetImmedValue();
 			LimitIncrease -= InitValue;
-			STARSOpndTypePtr RightOp = InitExpr->GetParentInst()->MakeImmediateOpnd((STARS_uval_t)LimitIncrease);
+			STARSOpndTypePtr RightOp = InitExpr->GetParentInst()->MakeImmediateOpnd((STARS_uval_t) LimitIncrease);
 			IterationsExpr->SetRightOperand(RightOp);
+			LimitIncreaseFolded = true;
 			NeedLimitIncrease = false; // already in IterationsExpr
 		}
 		else { // non-constant InitExpr
@@ -6939,7 +6959,7 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 			}
 			IterationsExpr->SetLeftTree(LeftExpr);
 		}
-		else { // just need LimitExpr right hand side as left tree or operand.
+		else if (LimitIncreaseFolded) { // just need LimitExpr right hand side as left tree or operand.
 			IterationsExpr->SetOperator(SMP_ADD);  // LimitExpr RHS + (folded LimitIncrease - InitExpr)
 			// If LimitExpr RHS is just an operand, make it the LeftOperand, else make it the LeftTree.
 			if (!LimitExpr->HasRightSubTree()) { // just RightOperand
@@ -6951,6 +6971,10 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 				IterationsExpr->SetLeftTree(LimitExpr->GetRightTree());
 			}
 		}
+		else { // never folded, no LimitIncrease, just LimitExpr - InitExpr
+			IterationsExpr->SetOperator(SMP_SUBTRACT);
+			IterationsExpr->SetLeftTree(LimitExpr);
+		}
 	} // end if PositiveIncrement
 	else { // decrement case
 		if ((InitExpr->GetOperator() == SMP_ASSIGN) && InitExpr->GetLeftOperand()->IsImmedOp()) {
@@ -6959,6 +6983,7 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 			LimitIncrease += InitValue;
 			STARSOpndTypePtr LeftOp = InitExpr->GetParentInst()->MakeImmediateOpnd((STARS_uval_t) LimitIncrease);
 			IterationsExpr->SetLeftOperand(LeftOp);
+			LimitIncreaseFolded = true;
 			NeedLimitIncrease = false; // already in IterationsExpr
 		}
 		else { // non-constant InitExpr
@@ -7003,7 +7028,26 @@ STARSExpression* SMPFunction::CreateIterationsExpr(std::size_t LoopIndex, const
 		}
 	} // end .. else decrement case
 
-	return IterationsExpr;
+	// We want to simplify the resulting expression before we divide by IncDecValue.
+	//  The division otherwise might have to have complex simplifications. E.g. if we
+	//  have InitExpr of RSP-200 and LimitExpr of RSP-100 and IncDecValue of 4, we prefer
+	//  to simplify ((RSP - 100) - (RSP - 200)) to 100 and then return 100 / 4. Our 
+	//  caller will call SimplifyExpr() on the expr we return.
+	assert(nullptr != IterationsExpr);
+	bool Simplified = IterationsExpr->SimplifyExpr(nullptr);
+	if (IncDecValue != 1) {
+		// Divide by IncDecOp.
+		STARSExpression *NewIterExpr = new STARSExpression();
+		NewIterExpr->SetParentInst(LimitExpr->GetParentInst());
+		NewIterExpr->SetParentFunc(this);
+		NewIterExpr->SetOperator(SMP_U_DIVIDE);
+		NewIterExpr->SetRightOperand(IncDecOp);
+		NewIterExpr->SetLeftTree(IterationsExpr);
+		return NewIterExpr;
+	}
+	else {
+		return IterationsExpr;
+	}
 } // end of SMPFunction::CreateIterationsExpr()
 
 // Create a Memory range expression for indirect or indexed memory writes in the loop
@@ -14223,174 +14267,10 @@ void SMPFunction::EmitFuncSPARKAda(void) {
 	}
 	SMP_fprintf(HeaderFile, "),\n"); // close Globals section parenthesis
 
-	// Emit memory writing range pre-conditions.
+	// Emit memory writing range pre-conditions and post-conditions.
 	bool HasLoopMemWrites = ((this->LoopCount > 0) && this->MemRangeRegsBitmap.any());
-#if 1
 	this->EmitSPARKProcPrePostMemConditions(BodyFile, HeaderFile, true);
-#else
-	bool HasLoopMemWrites = ((this->LoopCount > 0) && this->MemRangeRegsBitmap.any());
-	bool HasNonLoopInArgMemWrites = (!this->InArgsUsedInMemWrites.empty());
-	bool HasCalleeMemWrites = (!this->MemAddrExprsFromCallees.empty());
-	if (!HasNonLoopInArgMemWrites) {
-		size_t OutputCount = 0;
-		if (HasLoopMemWrites) {
-			SMP_fprintf(HeaderFile, "\tPre => (for all i in Unsigned64 => (if X86.InMemoryRange(i, ");
-			for (size_t LoopIndex = 0; LoopIndex < this->LoopCount; ++LoopIndex) {
-				if (0 < OutputCount) {
-					SMP_fprintf(HeaderFile, "\n\t\t or X86.InMemoryRange(i, ");
-				}
-				this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ", ");
-				this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ") ");
-				++OutputCount;
-			}
-		}
-		if (HasCalleeMemWrites) {
-			if (0 == OutputCount) {
-				SMP_fprintf(HeaderFile, "\tPre => (for all i in Unsigned64 => (");
-			}
-			for (size_t i = 0; i < this->MemAddrExprWidthsFromCallees.size(); ++i) {
-				// Easier in this loop to use X86.InRange64(i, X86.RAX, 8) than to use X86.InMemoryRange(i, X86.RAX, X86.RAX+8)
-				//  which would require printing the same operand twice.
-				if (0 < OutputCount) {
-					SMP_fprintf(HeaderFile, "\n\t\t or X86.InRange64(i, ");
-				}
-				else {
-					SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
-				}
-				(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
-				++OutputCount;
-			}
-		}
-		if (0 < OutputCount) {
-			SMP_fprintf(HeaderFile, " then\n\t\tX86.InSafeRegion64(i, X86.RSP))),\n");
-		}
-	}
-	else {
-		SMP_fprintf(HeaderFile, "\tPre => (for all i in Unsigned64 => (");
-		size_t OutputCount = 0;
-		if (HasLoopMemWrites) {
-			for (size_t LoopIndex = 0; LoopIndex < this->LoopCount; ++LoopIndex) {
-				if (0 < OutputCount) {
-					SMP_fprintf(HeaderFile, "\n\t\t or X86.InMemoryRange(i, ");
-				}
-				else {
-					SMP_fprintf(HeaderFile, "if X86.InMemoryRange(i, ");
-				}
-				this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ", ");
-				this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ") ");
-				++OutputCount;
-			}
-		}
-
-		STARSExpression *PreviousExpr = nullptr;
-		for (size_t i = 0; i < this->InArgsUsedInMemWrites.size(); ++i) {
-			STARSExpression *InArgExpr = this->InArgsUsedInMemWrites[i];
-			// Avoid duplicate output.
-			if (nullptr == PreviousExpr) {
-				PreviousExpr = InArgExpr;
-			}
-			else if (PreviousExpr->IsEqualExpr(InArgExpr)) {
-				continue;
-			}
-			else {
-				PreviousExpr = InArgExpr;
-			}
-
-			// Easier in this loop to use X86.InRange64(i, X86.RAX, 8) than to use X86.InMemoryRange(i, X86.RAX, X86.RAX+8)
-			//  which would require printing the same operand twice.
-			if (0 < OutputCount) {
-				SMP_fprintf(HeaderFile, "\n\t\t or X86.InRange64(i, ");
-			}
-			else {
-				SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
-			}
-			InArgExpr->EmitSPARKAda(HeaderFile, false, false, false);
-			SMP_fprintf(HeaderFile, ", %u)", this->InArgsUsedInMemWriteByteWidths[i]);
-			++OutputCount;
-		}
-
-		if (HasCalleeMemWrites) {
-			if (0 == OutputCount) {
-				SMP_fprintf(HeaderFile, "\tPre => (for all i in Unsigned64 => (");
-			}
-			for (size_t i = 0; i < this->MemAddrExprWidthsFromCallees.size(); ++i) {
-				// Easier in this loop to use X86.InRange64(i, X86.RAX, 8) than to use X86.InMemoryRange(i, X86.RAX, X86.RAX+8)
-				//  which would require printing the same operand twice.
-				if (0 < OutputCount) {
-					SMP_fprintf(HeaderFile, "\n\t\t or X86.InRange64(i, ");
-				}
-				else {
-					SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
-				}
-				(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
-				SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
-				++OutputCount;
-			}
-		}
-
-		SMP_fprintf(HeaderFile, " then\n\t\tX86.InSafeRegion64(i, X86.RSP))),\n");
-	}
-#endif
-
-#if 1
 	this->EmitSPARKProcPrePostMemConditions(BodyFile, HeaderFile, false);
-#else
-	if (this->AltersSPARKMemory()) {
-		SMP_fprintf(HeaderFile, "\tPost => (X86.RSP = (X86.RSP'Old + 8)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old) = X86.Memory'Old(X86.RSP'Old)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 1) = X86.Memory'Old(X86.RSP'Old + 1)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 2) = X86.Memory'Old(X86.RSP'Old + 2)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 3) = X86.Memory'Old(X86.RSP'Old + 3)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 4) = X86.Memory'Old(X86.RSP'Old + 4)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 5) = X86.Memory'Old(X86.RSP'Old + 5)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 6) = X86.Memory'Old(X86.RSP'Old + 6)) and\n");
-		SMP_fprintf(HeaderFile, "\t\t(X86.Memory(X86.RSP'Old + 7) = X86.Memory'Old(X86.RSP'Old + 7))");
-	}
-	else {
-		SMP_fprintf(HeaderFile, "\tPost => (X86.RSP = (X86.RSP'Old + 8))");
-	}
-	if (this->PreservedRegsBitmap.any()) {
-		size_t RegLimit = this->PreservedRegsBitmap.size();
-		if (RegLimit > STARS_x86_R_r15) {
-			RegLimit = STARS_x86_R_r15; // last full-width general purpose reg
-		}
-		for (size_t RegIndex = 0; RegIndex <= RegLimit; ++RegIndex) {
-			if (this->IsRegPreserved(RegIndex)) {
-				const char *RegName = MDGetSPARKRegNumName((STARS_regnum_t) RegIndex, ByteWidth);
-				SMP_fprintf(HeaderFile, " and\n\t\t(X86.%s = X86.%s'Old)", RegName, RegName);
-			}
-		}
-	}
-
-	// Emit memory writing range post-conditions.
-	if (HasLoopMemWrites) {
-		size_t OutputCount = 0;
-		SMP_fprintf(HeaderFile, "\tand \n\t(for all i in Unsigned64 => (if not X86.InMemoryRange(i, ");
-		for (size_t LoopIndex = 0; LoopIndex < this->LoopCount; ++LoopIndex) {
-			if (0 < OutputCount) {
-				SMP_fprintf(HeaderFile, "\n\t\t and not X86.InMemoryRange(i, ");
-			}
-			this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, true, false);
-			SMP_fprintf(HeaderFile, ", ");
-			this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, true, false);
-			SMP_fprintf(HeaderFile, ") ");
-			++OutputCount;
-		}
-		SMP_fprintf(HeaderFile, "\n\t\tand X86.InSafeRegion64(i, X86.RSP'Old)");
-		SMP_fprintf(HeaderFile, " then\n\t\t(X86.Memory(i) = X86.Memory'Old(i))))");
-	}
-	else if (this->AltersSPARKMemory()) {
-		SMP_fprintf(HeaderFile, "\tand \n\t(for all i in Unsigned64 => (if X86.InSafeRegion64(i, X86.RSP'Old)");
-		SMP_fprintf(HeaderFile, " then\n\t\t(X86.Memory(i) = X86.Memory'Old(i))))");
-	}
-
-	SMP_fprintf(HeaderFile, ";\n\n"); // terminate the postcondition section
-#endif
 
 	// Begin recursive descent translation with entry block.
 	SMPBasicBlock *CurrBlock = this->RPOBlocks[0];
@@ -14523,9 +14403,9 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						else
 							SMP_fprintf(HeaderFile, "\n\t\t and not X86.InMemoryRange(i, ");
 					}
-					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ", ");
-					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ") ");
 					++OutputCount;
 				}
@@ -14546,7 +14426,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						assert(PreconditionSection);
 						SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
 					}
-					(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
+					(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false, false);
 					SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
 					++OutputCount;
 				}
@@ -14573,9 +14453,9 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						assert(PreconditionSection);
 						SMP_fprintf(HeaderFile, "if X86.InMemoryRange(i, ");
 					}
-					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ", ");
-					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ") ");
 					++OutputCount;
 				}
@@ -14609,7 +14489,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 				assert(PreconditionSection);
 				SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
 			}
-			InArgExpr->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+			InArgExpr->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 			SMP_fprintf(HeaderFile, ", %u)", this->InArgsUsedInMemWriteByteWidths[i]);
 			++OutputCount;
 		}
@@ -14629,7 +14509,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						assert(PreconditionSection);
 						SMP_fprintf(HeaderFile, "if X86.InRange64(i, ");
 					}
-					(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
+					(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false, false);
 					SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
 					++OutputCount;
 				}
@@ -14745,9 +14625,9 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						else
 							SMP_fprintf(HeaderFile, "\n\t\t and not X86.InMemoryRange(i, ");
 					}
-					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ", ");
-					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ") ");
 					++OutputCount;
 				}
@@ -14774,7 +14654,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKInSafeRegion64(HeaderFile, MemWidth);
 					}
 					else {
-						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
+						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false, false);
 						SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
 					}
 					++OutputCount;
@@ -14805,9 +14685,9 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						assert(PreconditionSection);
 						SMP_fprintf(HeaderFile, "if X86.InMemoryRange(i, ");
 					}
-					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteLowerBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ", ");
-					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+					this->LoopMemWriteUpperBoundsExprs[LoopIndex]->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 					SMP_fprintf(HeaderFile, ") ");
 					++OutputCount;
 				}
@@ -14847,7 +14727,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 				InArgExpr->EmitSPARKInSafeRegion64(HeaderFile, MemWidth);
 			}
 			else {
-				InArgExpr->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false);
+				InArgExpr->EmitSPARKAda(HeaderFile, false, !PreconditionSection, false, false);
 				SMP_fprintf(HeaderFile, ", %u)", this->InArgsUsedInMemWriteByteWidths[i]);
 			}
 			++OutputCount;
@@ -14872,7 +14752,7 @@ void SMPFunction::EmitSPARKProcPrePostMemConditions(FILE *BodyFile, FILE *Header
 						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKInSafeRegion64(HeaderFile, MemWidth);
 					}
 					else {
-						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false);
+						(*this->MemAddrExprWidthsFromCallees[i].first)->EmitSPARKAda(HeaderFile, false, false, false, false);
 						SMP_fprintf(HeaderFile, ", %u)", this->MemAddrExprWidthsFromCallees[i].second);
 					}
 					++OutputCount;
@@ -15068,9 +14948,9 @@ string SMPFunction::EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlo
 	STARS_sval_t IncomingStackDelta = FirstInst->GetStackPtrOffset();
 	if (UsesStackPtrRegs) {
 		if (0 != IncomingStackDelta)
-			SMP_fprintf(BodyFile, "\tentryRSP : Unsigned64 := X86.RSP + %d with Ghost;\n", (0 - IncomingStackDelta));
+			SMP_fprintf(BodyFile, "\tSaveStackPtr : Unsigned64 := X86.RSP + %d with Ghost;\n", (0 - IncomingStackDelta));
 		else
-			SMP_fprintf(BodyFile, "\tentryRSP : Unsigned64 := X86.RSP with Ghost;\n");
+			SMP_fprintf(BodyFile, "\tSaveStackPtr : Unsigned64 := X86.RSP with Ghost;\n");
 		if (UseFP) {
 			SMP_fprintf(BodyFile, "\tsavedRBP : Unsigned64 := X86.ReadMem64(X86.RBP) with Ghost;");
 		}
@@ -15092,7 +14972,7 @@ string SMPFunction::EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlo
 	this->EmitSPARKLoopProcGlobals(BodyFile, HeaderFile, MemoryInput, MemoryOutput, LoopInputRegs, LoopOutputRegs);
 
 	// Emit pre-conditions.
-	bool HasNonStackPreconditions = ((nullptr != this->LoopIterationsInitExprs[LoopIndex]) && (nullptr != this->LoopMemWriteLowerBoundsExprs[LoopIndex]));
+	bool HasNonStackPreconditions = this->LoopRequiresNonStackPreconditions(LoopIndex);
 	bool HasPreconditions = (HasNonStackPreconditions || (UseFP && UsesStackPtrRegs));
 	this->LoopHasPreconditions[LoopIndex] = HasPreconditions;
 	if (HasPreconditions) {
@@ -15105,13 +14985,15 @@ string SMPFunction::EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlo
 			else {
 				SMP_fprintf(HeaderFile, "(X86.RBP = X86.RSP + %d)", RBPRSPDelta);
 			}
-		}
-		if (!HasNonStackPreconditions) {
-			SMP_fprintf(HeaderFile, ",\n");  // finished with preconditions
+			if (!HasNonStackPreconditions) {
+				SMP_fprintf(HeaderFile, ",\n");  // finished with preconditions
+			}
+			else {
+				SMP_fprintf(HeaderFile, " and \n\t"); // prepare for more preconditions
+			}
 		}
 		else { // Need preconditions for memory writing range
-			if ((nullptr != this->LoopIterationsInitExprs[LoopIndex]) && (nullptr != this->LoopMemWriteLowerBoundsExprs[LoopIndex])) {
-				SMP_fprintf(HeaderFile, " and \n\t (");
+			if (HasNonStackPreconditions) {
 				STARSInductionVarFamilyList::const_iterator BIVIter = this->LoopAnalyzedBIVIters[LoopIndex];
 				assert(BIVIter != this->LoopInductionVars[LoopIndex].cend());
 				STARS_ea_t BIVInitAddr = BIVIter->BIVIncomingDefAddr;
@@ -15119,6 +15001,7 @@ string SMPFunction::EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlo
 				SMPInstr *BIVInitInst = this->GetInstFromAddr(BIVInitAddr);
 				assert(nullptr != BIVInitInst);
 				STARSOpndTypePtr BIVDefOp = BIVInitInst->GetFirstLeftOperandNoNorm();
+				SMP_fprintf(HeaderFile, " (");
 				FirstInst->PrintSPARKAdaOperand(BIVDefOp, HeaderFile, false, UseFP, true, false);
 				SMP_fprintf(HeaderFile, "= ");
 				this->LoopIterationsInitExprs[LoopIndex]->EmitSPARKAda(HeaderFile, true, false, false, HasArgs);
@@ -15141,6 +15024,18 @@ string SMPFunction::EmitSPARKProcForLoopHeaderBlock(int LoopIndex, int HeaderBlo
 	return ProcName;
 } // end of SMPFunction::EmitSPARKProcForLoopHeaderBlock()
 
+bool SMPFunction::LoopRequiresNonStackPreconditions(size_t LoopIndex) const {
+	bool LoopWritePreconditions = ((nullptr != this->LoopIterationsInitExprs[LoopIndex])
+		&& (nullptr != this->LoopMemWriteLowerBoundsExprs[LoopIndex])
+		&& (nullptr != this->LoopMemWriteUpperBoundsExprs[LoopIndex]));
+	if (LoopWritePreconditions) {
+		LoopWritePreconditions = ((!this->LoopIterationsInitExprs[LoopIndex]->IsStackPtrPlusOffset())
+			&& (!this->LoopMemWriteLowerBoundsExprs[LoopIndex]->IsStackPtrPlusOffset())
+			&& (!this->LoopMemWriteUpperBoundsExprs[LoopIndex]->IsStackPtrPlusOffset()));
+	}
+	return LoopWritePreconditions;
+} // end of SMPFunction::LoopRequiresNonStackPreconditions()
+
 // Analyze reg and mem accesses in loop
 void SMPFunction::AnalyzeLoopGlobals(int HeaderBlockNum, int FollowBlockNum, bool &MemoryInput, bool &MemoryOutput, std::bitset<1 + MD_LAST_REG_NO> &InputRegs, std::bitset<1 + MD_LAST_REG_NO> &OutputRegs) {
 	assert((0 <= HeaderBlockNum) && (HeaderBlockNum < this->RPOBlocks.size()));
diff --git a/src/base/SMPInstr.cpp b/src/base/SMPInstr.cpp
index a359ffcb87b0c125732e33e488e7d37015640336..bc4a120abe6f7f2fe2777c92ccca1a1c71839b02 100644
--- a/src/base/SMPInstr.cpp
+++ b/src/base/SMPInstr.cpp
@@ -437,7 +437,7 @@ void PrintSPARKIndentTabs(FILE *OutFile) {
 }
 
 // Print an operand in SPARK-Ada form.
-void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace) {
+void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool LeftHandSide, bool UseFP, bool UseMachinePrefix, bool OmitTrailingSpace, bool UseSavedStackPtr) {
 	std::size_t OpndByteWidth = Opnd->GetByteWidth();
 	bool MemOpnd = IsMemOperand(Opnd);
 	bool SubwordWidth = (global_STARS_program->GetSTARS_ISA_Bytewidth() > OpndByteWidth);
@@ -457,7 +457,7 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 	if (Opnd->IsStaticMemOp()) {
 		if (Opnd->HasSIBByte()) {
 			SMP_fprintf(OutFile, " %s ", MemWriteString);
-			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), UseSavedStackPtr);
 			SMP_fprintf(OutFile, " + 16#%llx# )", (unsigned long long) Opnd->GetAddr());
 		}
 		else {
@@ -470,7 +470,7 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 	else if (Opnd->IsMemNoDisplacementOp()) {
 		if (Opnd->HasSIBByte()) { // has SIB info
 			SMP_fprintf(OutFile, " %s ", MemWriteString);
-			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), UseSavedStackPtr);
 		}
 		else { // no SIB info
 			STARS_regnum_t BaseReg = Opnd->GetReg();
@@ -486,7 +486,12 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 			}
 			else {
 #endif
-				SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
+				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
+					SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
+				}
+				else {
+					SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString);
+				}
 #if STARS_SPARK_EMIT_SEGMENT_REGS
 			}
 #endif
@@ -506,7 +511,7 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 		int SignedOffset = (int) offset;
 		if (Opnd->HasSIBByte()) {
 			SMP_fprintf(OutFile, " %s ", MemWriteString);
-			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), false);
 			if (SignedOffset > 0) // print plus sign
 				SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset);
 			else if (SignedOffset < 0) // minus sign will print automatically
@@ -527,7 +532,12 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 			}
 			else {
 #endif
-				SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
+				if (!(UseSavedStackPtr && (BaseReg == MD_STACK_POINTER_REG))) {
+					SMP_fprintf(OutFile, " %s X86.%s ", MemWriteString, MDGetRegName(BaseOp));
+				}
+				else {
+					SMP_fprintf(OutFile, " %s SaveStackPtr ", MemWriteString);
+				}
 #if STARS_SPARK_EMIT_SEGMENT_REGS
 			}
 #endif
@@ -544,7 +554,11 @@ void SMPInstr::PrintSPARKAdaOperand(const STARSOpndTypePtr &Opnd, FILE *OutFile,
 		}
 	}
 	else if (Opnd->IsRegOp()) {
-		if (SubwordWidth && LeftHandSide) {
+		if (UseSavedStackPtr && Opnd->MatchesReg(MD_STACK_POINTER_REG)) {
+			assert(!LeftHandSide);
+			SMP_fprintf(OutFile, " SaveStackPtr");
+		}
+		else if (SubwordWidth && LeftHandSide) {
 			// Subword reg writes are procedure calls, e.g. Write_EDI(...
 			SMP_fprintf(OutFile, " X86.Write_%s(", MDGetRegName(Opnd));
 		}
@@ -788,14 +802,14 @@ void SMPInstr::SPARKAdaOperandToString(const STARSOpndTypePtr &Opnd, std::string
 } // end of SMPInstr::SPARKAdaOperandToString()
 
 // Print just the addressing expression for a memory operand in SPARK-Ada form.
-void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP) {
+void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutFile, bool UseFP, bool UseSavedStackPtr) {
 	bool MemOpnd = IsMemOperand(Opnd);
 
 	assert(MemOpnd);
 
 	if (Opnd->IsStaticMemOp()) {
 		if (Opnd->HasSIBByte()) {
-			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, true, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), UseSavedStackPtr);
 			SMP_fprintf(OutFile, " + 16#%llx# )", (uint64_t) Opnd->GetAddr());
 		}
 		else {
@@ -804,7 +818,7 @@ void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutF
 	}
 	else if (Opnd->IsMemNoDisplacementOp()) {
 		if (Opnd->HasSIBByte()) { // has SIB info
-			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, false, OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), UseSavedStackPtr);
 		}
 		else { // no SIB info
 			STARS_regnum_t BaseReg = Opnd->GetReg();
@@ -820,7 +834,12 @@ void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutF
 			}
 			else {
 #endif
-				SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
+				if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) {
+					SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
+				}
+				else {
+					SMP_fprintf(OutFile, " SaveStackPtr ");
+				}
 #if STARS_SPARK_EMIT_SEGMENT_REGS
 			}
 #endif
@@ -833,7 +852,7 @@ void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutF
 		STARS_ea_t offset = Opnd->GetAddr();
 		int SignedOffset = (int) offset;
 		if (Opnd->HasSIBByte()) {
-			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands());
+			SPARKAnnotPrintSIB(Opnd, (SignedOffset != 0), OutFile, Opnd->GetSegReg(), UseFP, this->MDHas64BitOperands(), UseSavedStackPtr);
 			if (SignedOffset > 0) // print plus sign
 				SMP_fprintf(OutFile, "+ 16#%x# )", (unsigned int) SignedOffset);
 			else if (SignedOffset < 0) // minus sign will print automatically
@@ -853,7 +872,12 @@ void SMPInstr::PrintSPARKAdaAddressExpr(const STARSOpndTypePtr &Opnd, FILE *OutF
 			}
 			else {
 #endif
-				SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
+				if (!(UseSavedStackPtr && BaseOp->MatchesReg(MD_STACK_POINTER_REG))) {
+					SMP_fprintf(OutFile, " X86.%s ", MDGetRegName(BaseOp));
+				}
+				else {
+					SMP_fprintf(OutFile, " SaveStackPtr ");
+				}
 #if STARS_SPARK_EMIT_SEGMENT_REGS
 			}
 #endif
@@ -2229,7 +2253,7 @@ void STARSExpression::Dump(const std::size_t TabCount) const {
 
 // Emit SPARK Ada translation of expression to OutputFile, perhaps with Reg'Old suffix.
 // OffByOne should never be true for subtrees, only certain parent trees.
-void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs) const {
+void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool OldSuffix, bool OffByOne, bool HasLoopArgs, bool UseSavedStackPtr) const {
 	bool UseFP = this->GetParentFunc()->UsesFramePointer();
 
 	bool PrefixProcCall = false;
@@ -2272,7 +2296,7 @@ void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool O
 	// Left operand or subtree
 	if (this->HasLeftSubTree()) {
 		SMP_fprintf(OutputFile, "(");
-		this->GetLeftTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs);
+		this->GetLeftTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr);
 		SMP_fprintf(OutputFile, ")");
 	}
 	else if ((nullptr != this->GetLeftOperand()) && (!this->GetLeftOperand()->IsVoidOp())) {
@@ -2282,7 +2306,7 @@ void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool O
 		if (MDIsDirectStackAccessOpnd(LeftOp, UseFP)) {
 			this->GetParentInst()->MDGetUnnormalizedOp(LeftOp);
 		}
-		this->GetParentInst()->PrintSPARKAdaOperand(LeftOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace);
+		this->GetParentInst()->PrintSPARKAdaOperand(LeftOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace, UseSavedStackPtr);
 		if (ProcessingLoop && IsRegOp && HasLoopArgs && (STARS_BADADDR != this->GetLeftPreLoopDefAddr())) { // LiveIn to loop, traced back to InArg
 			std::ostringstream AddrString;
 			AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
@@ -2310,7 +2334,7 @@ void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool O
 		// then the right operand or subtree
 		if (this->HasRightSubTree()) {
 			SMP_fprintf(OutputFile, "(");
-			this->GetRightTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs);
+			this->GetRightTree()->EmitSPARKAda(OutputFile, ProcessingLoop, OldSuffix, false, HasLoopArgs, UseSavedStackPtr);
 			SMP_fprintf(OutputFile, ")");
 		}
 		else if ((nullptr != this->GetRightOperand()) && (!this->GetRightOperand()->IsVoidOp())) {
@@ -2320,7 +2344,7 @@ void STARSExpression::EmitSPARKAda(FILE *OutputFile, bool ProcessingLoop, bool O
 			if (MDIsDirectStackAccessOpnd(RightOp, UseFP)) {
 				this->GetParentInst()->MDGetUnnormalizedOp(RightOp);
 			}
-			this->GetParentInst()->PrintSPARKAdaOperand(RightOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace);
+			this->GetParentInst()->PrintSPARKAdaOperand(RightOp, OutputFile, false, UseFP, !(ProcessingLoop && HasLoopArgs), OmitTrailingSpace, UseSavedStackPtr);
 			if (ProcessingLoop && IsRegOp && HasLoopArgs && (STARS_BADADDR != this->GetRightPreLoopDefAddr())) { // LiveIn to loop, traced back to InArg
 				std::ostringstream AddrString;
 				AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
@@ -2494,8 +2518,7 @@ void STARSExpression::EmitSPARKInSafeRegion64(FILE *OutputFile, size_t MemWidth)
 void STARSExpression::PrintSPARKArgLocationStrings(FILE *OutputFile, bool LoopInvariant) {
 	// Walk the expression tree and find non-constant leaves. These must be incoming arguments or basic induction variables (BIVs).
 	//  This method should not be called on expressions that were expanded with the StopOnIV option flag, so we will assume that
-	//  any non-constant leaf operand is an incoming argument.
-
+	//  any non-constant leaf operand is an incoming argument. EXCEPTION: The stack ptr reg is never made into an incoming arg.
 	if (this->HasLeftSubTree()) {
 		this->GetLeftTree()->PrintSPARKArgLocationStrings(OutputFile, LoopInvariant);
 	}
@@ -2524,49 +2547,51 @@ void STARSExpression::PrintSPARKArgLocationStrings(FILE *OutputFile, bool LoopIn
 } // end of STARSExpression::CreateSPARKArgLocationStrings()
 
 void STARSExpression::PrintSPARKArgLocationStringsHelper(FILE *OutputFile, bool LoopInvariant, const STARSOpndTypePtr &LeafOp, STARS_ea_t PreLoopDefAddr) {
-	bool UseFP = this->GetParentFunc()->UsesFramePointer();
-	std::ostringstream AddrString;
-	AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
-	if ((STARS_BADADDR != PreLoopDefAddr) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr)) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr))) {
-		if (STARS_IsSSAMarkerPseudoID(PreLoopDefAddr)) {
-			// InArg from calling function was unchanged and LiveIn to loop.
-			// We want a string like:  "RDI_400586 = RDI"
-			if (LoopInvariant) {
-				PrintSPARKIndentTabs(OutputFile);
-				SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
-				SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false);
-				SMP_fprintf(OutputFile, ");\n");
-			}
-			else {
-				SMP_fprintf(OutputFile, " and\n\t(");
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
-				SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false);
-				SMP_fprintf(OutputFile, ")");
-			}
-		}
-		else { // A regular instruction is at PreLoopDefAddr
-			// We want a string like:  "RDI_400586 = X86.ReadMem64(X86.RBP-8)"
-			SMPInstr *PreLoopInst = this->GetParentFunc()->GetInstFromAddr(PreLoopDefAddr);
-			assert(nullptr != PreLoopInst);
-			STARSOpndTypePtr PreLoopDefOp = PreLoopInst->GetFirstLeftOperandNoNorm();
-			assert((nullptr != PreLoopDefOp) && (!PreLoopDefOp->IsVoidOp()));
-			if (LoopInvariant) {
-				PrintSPARKIndentTabs(OutputFile);
-				SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
-				SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
-				this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
-				SMP_fprintf(OutputFile, ");\n");
-			}
-			else {
-				SMP_fprintf(OutputFile, " and\n\t(");
-				this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
-				SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
-				this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
-				SMP_fprintf(OutputFile, ")");
+	if (!(LeafOp->IsRegOp() && LeafOp->MatchesReg(MD_STACK_POINTER_REG))) {
+		bool UseFP = this->GetParentFunc()->UsesFramePointer();
+		std::ostringstream AddrString;
+		AddrString << std::hex << this->GetParentFunc()->GetFirstFuncAddr();
+		if ((STARS_BADADDR != PreLoopDefAddr) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr)) && (!STARS_IsBlockNumPseudoID(PreLoopDefAddr))) {
+			if (STARS_IsSSAMarkerPseudoID(PreLoopDefAddr)) {
+				// InArg from calling function was unchanged and LiveIn to loop.
+				// We want a string like:  "RDI_400586 = RDI"
+				if (LoopInvariant) {
+					PrintSPARKIndentTabs(OutputFile);
+					SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
+					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false);
+					SMP_fprintf(OutputFile, ");\n");
+				}
+				else {
+					SMP_fprintf(OutputFile, " and\n\t(");
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
+					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, true, false);
+					SMP_fprintf(OutputFile, ")");
+				}
+			}
+			else { // A regular instruction is at PreLoopDefAddr
+				// We want a string like:  "RDI_400586 = X86.ReadMem64(X86.RBP-8)"
+				SMPInstr *PreLoopInst = this->GetParentFunc()->GetInstFromAddr(PreLoopDefAddr);
+				assert(nullptr != PreLoopInst);
+				STARSOpndTypePtr PreLoopDefOp = PreLoopInst->GetFirstLeftOperandNoNorm();
+				assert((nullptr != PreLoopDefOp) && (!PreLoopDefOp->IsVoidOp()));
+				if (LoopInvariant) {
+					PrintSPARKIndentTabs(OutputFile);
+					SMP_fprintf(OutputFile, "pragma Loop_Invariant(");
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
+					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
+					this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
+					SMP_fprintf(OutputFile, ");\n");
+				}
+				else {
+					SMP_fprintf(OutputFile, " and\n\t(");
+					this->GetParentInst()->PrintSPARKAdaOperand(LeafOp, OutputFile, false, UseFP, false, true);
+					SMP_fprintf(OutputFile, "_%s = ", AddrString.str().c_str());
+					this->GetParentInst()->PrintSPARKAdaOperand(PreLoopDefOp, OutputFile, false, UseFP, true, false);
+					SMP_fprintf(OutputFile, ")");
+				}
 			}
 		}
 	}
@@ -2920,6 +2945,79 @@ bool STARSExpression::SimplifyExpr(STARSExpression *ParentExpr) {
 				} // end of cascading additions and subtractions
 			}
 		}
+	} // end if (LeftNullTree || RightNullTree)
+	else {
+		// Look for the special case of simplifying address ranges, e.g. if we loop from
+		//  RDI + 4 up to RDI + 128, then the iteration count expr will be ((RDI + 128) - (RDI + 4)).
+		//  The address register drops out of the expr and the final answer is 124.
+		if (SMP_SUBTRACT == this->GetOperator() && (!this->GetLeftTree()->HasRightSubTree()) && (!this->GetRightTree()->HasRightSubTree())) {
+			// Check for the LeftTree and RightTree having the same LeftOperand register.
+			if (this->GetLeftTree()->GetLeftOperand()->IsRegOp() && this->GetRightTree()->GetLeftOperand()->IsRegOp()) {
+				STARS_regnum_t LeftReg = this->GetLeftTree()->GetLeftOperand()->GetReg();
+				STARS_regnum_t RightReg = this->GetRightTree()->GetLeftOperand()->GetReg();
+				if (LeftReg == RightReg) {
+					// The registers will drop out of the expression.
+					//  We have ((Reg op RightOp1) - (Reg op RightOp2))
+					//  What to do next depends on the operators and whether we have immediate RightOps
+					SMPoperator LeftOperator = this->GetLeftTree()->GetOperator();
+					SMPoperator RightOperator = this->GetRightTree()->GetOperator();
+					if (SMP_ADD == LeftOperator) {
+						// We need RightOp1 - RightOp2 if RightOperator is addition,
+						//  and RightOp1 + RightOp2 if RightOperator is subtraction.
+						if ((SMP_ADD == RightOperator) || (SMP_SUBTRACT == RightOperator)) {
+							// Make the LeftTree->RightOperand into the new left tree,
+							//  and the RightTree->RightOperand into the new right tree,
+							//  leaving SMP_SUBTRACT as the parent operator.
+							LeftOperandLifted = this->GetLeftTree()->ElevateRightSide(this);
+							RightOperandLifted = this->GetRightTree()->ElevateRightSide(this);
+							assert(LeftOperandLifted && RightOperandLifted);
+							if (SMP_SUBTRACT == RightOperator) {
+								// We simplified ((Reg + RightOp1) - (Reg - RightOp2))
+								//  so the answer is (RightOp1 + RightOp2). Change parent operator
+								//  to SMP_ADD.
+								this->SetOperator(SMP_ADD);
+							}
+						}						
+					}
+					else if (SMP_SUBTRACT == LeftOperator) {
+						// We need (-RightOp1) - RightOp2 if RightOperator is addition,
+						//  and RightOp2 - RightOp1 if RightOperator is subtraction.
+						// We will only deal with the negation case if we have a constant RightOp1.
+						if (SMP_SUBTRACT == RightOperator) {
+							// Make the LeftTree->RightOperand into the new right operand,
+							//  and the RightTree->RightOperand into the new left operand,
+							//  leaving SMP_SUBTRACT as the parent operator.
+							STARSOpndTypePtr LeftRightOp = this->GetLeftTree()->GetRightOperand()->clone();
+							STARSOpndTypePtr RightRightOp = this->GetRightTree()->GetRightOperand()->clone();
+							this->SetLeftOperand(RightRightOp);
+							this->SetRightOperand(LeftRightOp);
+							LeftOperandLifted = RightOperandLifted = true;
+						}
+						else if ((SMP_ADD == RightOperator) && this->GetLeftTree()->GetRightOperand()->IsImmedOp()) {
+							// Take ((Reg - immed) - (Reg + operand)) and produce (-immed - operand) by negating the
+							//  left immediate value, substituting it for the left tree, and raising the right tree's
+							//  right operand and leaving the parent operator as SMP_SUBTRACT.
+							STARS_uval_t LeftRightValue = this->GetLeftTree()->GetRightOperand()->GetImmedValue();
+							LeftRightValue = (0 - LeftRightValue); // negate RightOp1
+							STARSOpndTypePtr NewLeftOp = this->GetLeftTree()->GetParentInst()->MakeImmediateOpnd(LeftRightValue);
+							RightOperandLifted = this->GetRightTree()->ElevateRightSide(this);
+							assert(RightOperandLifted);
+							this->SetLeftOperand(NewLeftOp);
+							LeftOperandLifted = true;
+						}
+					}
+				}
+			}
+			if (LeftOperandLifted || RightOperandLifted) {
+				// See if our simplifications left us with constants.
+				if (!this->HasLeftSubTree() && (!this->HasRightSubTree())) {
+					if (this->GetLeftOperand()->IsImmedOp() && this->GetLeftOperand()->IsImmedOp()) {
+						bool success = this->SimplifyExpr(ParentExpr);
+						assert(success);
+					}
+				}
+			}
+		}
 	}
 
 	return (LeftOperandLifted || RightOperandLifted || RootLeftExprLifted);
@@ -3292,6 +3390,21 @@ bool STARSExpression::UsesInArgReg(void) const {
 	return false;
 } // end of STARSExpression::UsesInArgReg()
 
+// Is Expr just the stack pointer plus optional offset constant?
+bool STARSExpression::IsStackPtrPlusOffset(void) const {
+	SMPoperator CurrOper = this->GetOperator();
+	bool LeftSPOpnd = (!this->HasLeftSubTree()) && this->GetLeftOperand()->IsRegOp() && this->GetLeftOperand()->MatchesReg(MD_STACK_POINTER_REG);
+	bool SPPlusOffset = false;
+	bool JustStackPtr = (CurrOper == SMP_ASSIGN) && LeftSPOpnd;
+	if (!JustStackPtr && LeftSPOpnd && IsIntegerAddOrSubOperator(CurrOper)) {
+		const STARSOpndTypePtr RightOp = this->GetRightOperand();
+		bool HasRightTree = this->HasRightSubTree();
+		bool ImmedRightOp = (nullptr != RightOp) && RightOp->IsImmedOp() && (!HasRightTree);
+		SPPlusOffset = ImmedRightOp;
+	}
+	return (JustStackPtr || SPPlusOffset);
+} // end of STARSExpression::IsStackPtrPlusOffset()
+
 // If expr is SP+offset, add offset to CurrentStackPtrOffset to get FinalStackPtrOffset and return true.
 //  CurrentStackPtrOffset should be relative to function entry and will generally be negative.
 bool STARSExpression::IsStackPtrOffset(const STARS_sval_t CurrentStackPtrOffset, STARS_sval_t &FinalStackPtrOffset) const {
@@ -5332,7 +5445,7 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) {
 						if ((!TargetFunc->FuncReturnsToCaller()) || TargetFunc->HasCallToNonReturningFunc() || TargetFunc->HasCalleeChainWithNonReturningFunc()) {
 							// Call chain could have set X86.Exit_Called, signalling that exit() or something similar was called.
 							PrintSPARKIndentTabs(OutFile);
-							SMP_fprintf(OutFile, " if X86.Exit_Called then ;\n");
+							SMP_fprintf(OutFile, " if X86.Exit_Called then \n");
 							PrintSPARKIndentTabs(OutFile);
 							SMP_fprintf(OutFile, "\t return;\n");
 							PrintSPARKIndentTabs(OutFile);
@@ -5360,6 +5473,77 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) {
 	}
 
 	if (PrintOperands) {
+		if (this->HasIndirectMemoryWrite()) {
+			// If we are in a loop, we need to emit an assertion that the memory address expression is in bounds.
+			int BlockNum = this->GetBlock()->GetNumber();
+			int InnerLoopNum = this->GetBlock()->GetFunc()->GetInnermostLoopNum(BlockNum);
+			STARSOpndTypePtr MemDefOp = this->GetMemDef();
+			bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
+			size_t ByteWidth = MemDefOp->GetByteWidth();
+			if (0 <= InnerLoopNum) {
+				// Inst is in a loop. Did we analyze memory bounds for the loop?
+				size_t LoopIndex = (size_t)InnerLoopNum;
+				STARSExpression *LowerExpr = this->GetBlock()->GetFunc()->GetLoopMemWriteLowerBoundExpr(LoopIndex);
+				STARSExpression *UpperExpr = this->GetBlock()->GetFunc()->GetLoopMemWriteUpperBoundExpr(LoopIndex);
+				if ((nullptr != LowerExpr) && (nullptr != UpperExpr)) {
+					bool HasArgs = this->GetBlock()->GetFunc()->DoesLoopHaveArgs(InnerLoopNum);
+					for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
+						PrintSPARKIndentTabs(OutFile);
+						SMP_fprintf(OutFile, "pragma Assert(X86.InMemoryRange(");
+						this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
+						if (0 < ByteIndex)
+							SMP_fprintf(OutFile, "+%u", ByteIndex);
+						SMP_fprintf(OutFile, ", ");
+						LowerExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true);
+						SMP_fprintf(OutFile, ", ");
+						UpperExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs, true);
+						SMP_fprintf(OutFile, "));\n");
+					}
+				}
+				// Regardless of whether we analyzed the loop, we want to assert that
+				//  the memory write is in the safe stack region, unless it is a stack frame write.
+				if (!MDIsStackAccessOpnd(MemDefOp, UseFP)) {
+					for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
+						PrintSPARKIndentTabs(OutFile);
+						SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64(");
+						this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
+						if (0 < ByteIndex)
+							SMP_fprintf(OutFile, "+%u", ByteIndex);
+						SMP_fprintf(OutFile, ", SaveStackPtr));\n");
+					}
+				}
+			}
+			else {
+				// For indirect writes outside of loops, see if we mapped the address reg operand back to an incoming arg.
+				//  If so, emit an assert that the address reg is just a copy of the InArg.
+				STARSInArgMap::const_iterator AddrRegInArgMapIter = this->GetBlock()->GetFunc()->GetAddressRegToInArgMapping(InstAddr);
+				if (AddrRegInArgMapIter != this->GetBlock()->GetFunc()->GetLastAddressRegToInArgMapping()) {
+					// If RBX maps to saved InArg RDI in a func that starts at 0x400788, we want to emit:
+					//  pragma Assert(X86.RBX = RDI_400788);
+					// The InArg RDI will have been saved in a Ghost variable called RDI_400788 at function entry.
+					STARSOpndTypePtr AddrRegOp = (*AddrRegInArgMapIter).second.first;
+					STARSOpndTypePtr InArgOp = (*AddrRegInArgMapIter).second.second;
+					PrintSPARKIndentTabs(OutFile);
+					SMP_fprintf(OutFile, "pragma Assert(");
+					this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false);
+					SMP_fprintf(OutFile, "=");
+					this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, false, true);
+					// At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix
+					SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str());
+					// In addition to being a copy of the InArg, we want to assert that
+					//  the memory write is in the safe stack region.
+					for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
+						PrintSPARKIndentTabs(OutFile);
+						SMP_fprintf(OutFile, "pragma Assert(X86.InSafeRegion64(");
+						this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP, true);
+						if (0 < ByteIndex)
+							SMP_fprintf(OutFile, "+%u", ByteIndex);
+						SMP_fprintf(OutFile, ", SaveStackPtr));\n");
+					}
+				}
+			}
+		} // end if indirect memory write
+
 		if (this->MDIsCompareOrTest()) {
 			this->MDEmitSPARKAdaCompareOrTest(OutFile);
 		}
@@ -5382,54 +5566,6 @@ void SMPInstr::EmitSPARKAda(FILE *OutFile) {
 				SMP_fprintf(OutFile, " then \n");
 				++STARS_SPARK_IndentCount;
 			}
-			if (this->HasIndirectMemoryWrite()) {
-				// If we are in a loop, we need to emit an assertion that the memory address expression is in bounds.
-				int BlockNum = this->GetBlock()->GetNumber();
-				int InnerLoopNum = this->GetBlock()->GetFunc()->GetInnermostLoopNum(BlockNum);
-				if (0 <= InnerLoopNum) {
-					// Inst is in a loop. Did we analyze memory bounds for the loop?
-					size_t LoopIndex = (size_t) InnerLoopNum;
-					STARSExpression *LowerExpr = this->GetBlock()->GetFunc()->GetLoopMemWriteLowerBoundExpr(LoopIndex);
-					STARSExpression *UpperExpr = this->GetBlock()->GetFunc()->GetLoopMemWriteUpperBoundExpr(LoopIndex);
-					if ((nullptr != LowerExpr) && (nullptr != UpperExpr)) {
-						STARSOpndTypePtr MemDefOp = this->GetMemDef();
-						bool UseFP = this->GetBlock()->GetFunc()->UsesFramePointer();
-						size_t ByteWidth = MemDefOp->GetByteWidth();
-						bool HasArgs = this->GetBlock()->GetFunc()->DoesLoopHaveArgs(InnerLoopNum);
-						for (size_t ByteIndex = 0; ByteIndex < ByteWidth; ++ByteIndex) {
-							PrintSPARKIndentTabs(OutFile);
-							SMP_fprintf(OutFile, "pragma Assert(X86.InMemoryRange(");
-							this->PrintSPARKAdaAddressExpr(MemDefOp, OutFile, UseFP);
-							if (0 < ByteIndex)
-								SMP_fprintf(OutFile, "+%u", ByteIndex);
-							SMP_fprintf(OutFile, ", ");
-							LowerExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs);
-							SMP_fprintf(OutFile, ", ");
-							UpperExpr->EmitSPARKAda(OutFile, true, false, false, HasArgs);
-							SMP_fprintf(OutFile, "));\n");
-						}
-					}
-				}
-				else {
-					// For indirect writes outside of loops, see if we mapped the address reg operand back to an incoming arg.
-					//  If so, emit an assert that the address reg is just a copy of the InArg.
-					STARSInArgMap::const_iterator AddrRegInArgMapIter = this->GetBlock()->GetFunc()->GetAddressRegToInArgMapping(InstAddr);
-					if (AddrRegInArgMapIter != this->GetBlock()->GetFunc()->GetLastAddressRegToInArgMapping()) {
-						// If RBX maps to saved InArg RDI in a func that starts at 0x400788, we want to emit:
-						//  pragma Assert(X86.RBX = RDI_400788);
-						// The InArg RDI will have been saved in a Ghost variable called RDI_400788 at function entry.
-						STARSOpndTypePtr AddrRegOp = (*AddrRegInArgMapIter).second.first;
-						STARSOpndTypePtr InArgOp = (*AddrRegInArgMapIter).second.second;
-						PrintSPARKIndentTabs(OutFile);
-						SMP_fprintf(OutFile, "pragma Assert(");
-						this->PrintSPARKAdaOperand(AddrRegOp, OutFile, false, UseFP, true, false);
-						SMP_fprintf(OutFile, "=");
-						this->PrintSPARKAdaOperand(InArgOp, OutFile, false, UseFP, true, true);
-						// At this point, we have "pragma Assert(RBX = RDI" and we need the "_400788" suffix
-						SMP_fprintf(OutFile, "%s );\n", this->GetBlock()->GetFunc()->GetFuncSPARKSuffixString().c_str());
-					}
-				}
-			} // end if indirect memory write
 
 			SMPRegTransfer *CurrRT;
 			for (std::size_t RTLindex = 0; RTLindex < this->RTL.GetCount(); ++RTLindex) {