private void addStackParameters(Function func, List<Variable> sortedVariables,
			VariableStorageConflicts conflicts, TaskMonitor monitor) {

		Parameter[] oldParamList = func.getParameters();
		List<Variable> newParamList = new ArrayList<>();

		boolean growsNegative = func.getStackFrame().growsNegative();

		int sortedVarCnt = sortedVariables.size();

		int index = 0;
		for (index = 0; index < sortedVarCnt; ++index) {
			Variable var = sortedVariables.get(index);
			if (growsNegative && (var instanceof Parameter)) {
				break;
			}
			else if (!growsNegative && !(var instanceof Parameter)) {
				--index;
				break;
			}
		}

		if (index < 0 || index == sortedVarCnt) {
			// no parameters found
			return;
		}

		PrototypeModel callingConvention = func.getCallingConvention();
		if (callingConvention == null) {
			callingConvention = program.getCompilerSpec().getDefaultCallingConvention();
		}

		if (callingConvention == null) {
			return;
		}

		boolean hasStackParams = (callingConvention.getStackParameterAlignment() >= 0);

		int nextCopyParamIndex = 0;
		if (growsNegative) {
			for (int i = index; i < sortedVarCnt; ++i) {
				Variable v = sortedVariables.get(i);
				if (conflicts.isConflicted(v, null)) {
					continue;
				}
				nextCopyParamIndex = addMissingParameters(v, nextCopyParamIndex, oldParamList,
					newParamList, callingConvention, hasStackParams);
				if (nextCopyParamIndex < 0) {
					return;
				}
				newParamList.add(v);
			}
		}
		else {
			for (int i = index; i >= 0; --i) {
				Variable v = sortedVariables.get(i);
				if (conflicts.isConflicted(v, null)) {
					continue;
				}
				nextCopyParamIndex = addMissingParameters(v, nextCopyParamIndex, oldParamList,
					newParamList, callingConvention, hasStackParams);
				if (nextCopyParamIndex < 0) {
					return;
				}
				newParamList.add(v);
			}
		}

		while (nextCopyParamIndex < oldParamList.length) {
			newParamList.add(oldParamList[nextCopyParamIndex++]);
		}

		try {
			func.replaceParameters(newParamList,
				func.hasCustomVariableStorage() ? FunctionUpdateType.CUSTOM_STORAGE
						: FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
				true, func.getSignatureSource());
			if (!VariableUtilities.storageMatches(newParamList, func.getParameters())) {
				func.replaceParameters(newParamList, FunctionUpdateType.CUSTOM_STORAGE, true,
					func.getSignatureSource());
			}
		}
		catch (DuplicateNameException e) {
			// ignore - unexpected
		}
		catch (InvalidInputException e) {
			// ignore - unexpected
		}

	}
Create locals and parameters based on references involving purely the stack pointer.
Pushes, Pops, and arithmetic manipulation of the stack pointer must be tracked.

@param func - function to analyze stack pointer references
Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/NewFunctionStackAnalysisCmd.java