@Override
	public AddressSetView flowConstants(final Program program, Address flowStart, AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
			throws CancelledException {

		Register linkReg = program.getRegister("o7");

		// follow all flows building up context
		// use context to fill out addresses on certain instructions 
		ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {

			@Override
			public boolean evaluateContext(VarnodeContext context, Instruction instr) {
				FlowType ftype = instr.getFlowType();
				// Check for a call with a restore in the delay slot
				//    Then it is a non-returning call (share the called function return
				if (o7CallReturnAnalysis && ftype.isCall()) {
					Address fallAddr = instr.getFallThrough();
					if (fallAddr == null) {
						return false;
					}
					Instruction delayInstr =
						instr.getProgram().getListing().getInstructionAfter(instr.getMaxAddress());
					if (delayInstr == null) {
						return false;
					}
					PcodeOp[] pcode = delayInstr.getPcode();
					for (PcodeOp pcodeOp : pcode) {
						Varnode output = pcodeOp.getOutput();
						if (output == null || !output.equals(context.getRegisterVarnode(linkReg))) {
							continue;
						}
						Varnode input = pcodeOp.getInput(0);
						if (input.isConstant()) {
							continue; // this is just assigning the return value after the call
						}
						instr.setFallThrough(null);
						Instruction fallInstr =
							instr.getProgram().getListing().getInstructionAt(fallAddr);
						if (fallInstr == null) {
							return false;
						}
						if (fallInstr.getReferenceIteratorTo().hasNext()) {
							return false;
						}
						ClearFlowAndRepairCmd cmd =
							new ClearFlowAndRepairCmd(fallAddr, false, false, true);
						cmd.applyTo(instr.getProgram(), monitor);
						
						break;
					}
				}
				return false;
			}

			@Override
			public boolean evaluateDestination(VarnodeContext context, Instruction instruction) {
				FlowType flowType = instruction.getFlowType();
				if (!flowType.isJump()) {
					return false;
				}
				// TODO: if this is a switch stmt, add to destSet
				Reference[] refs = instruction.getReferencesFrom();
				if (refs.length <= 0 ||
					(refs.length == 1 && refs[0].getReferenceType().isData())) {
					destSet.addRange(instruction.getMinAddress(), instruction.getMinAddress());
				}
				return false;
			}
		};
		
		eval.setTrustWritableMemory(trustWriteMemOption)
		    .setMinSpeculativeOffset(minSpeculativeRefAddress)
		    .setMaxSpeculativeOffset(maxSpeculativeRefAddress)
		    .setMinStoreLoadOffset(minStoreLoadRefAddress)
		    .setCreateComplexDataFromPointers(createComplexDataFromPointers);
		
		AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);

		return resultSet;
	}
Analyze Sparc binaries for certain patterns of instructions.
Ghidra/Processors/Sparc/src/main/java/ghidra/app/plugin/core/analysis/SparcAnalyzer.java