public Reachability checkFallthroughAndAccumulate(PcodeProgram from) {
		if (instruction instanceof DecodeErrorInstruction) {
			stride.opsForStride.addAll(opsForThisStep);
			for (Branch branch : branchesForThisStep) {
				switch (branch) {
					case ErrBranch eb -> stride.passage.otherBranches.put(eb.from(), eb);
					default -> throw new AssertionError();
				}
			}
			return null;
		}
		if (opsForThisStep.isEmpty()) {
			return Reachability.WITHOUT_CTXMOD;
		}

		ExitPcodeOp probeOp = ExitPcodeOp.exit(AddrCtx.NOWHERE);
		opsForThisStep.add(probeOp);
		SExtBranch probeBranch = new SExtBranch(probeOp, AddrCtx.NOWHERE);
		branchesForThisStep.add(probeBranch);

		PcodeProgram program = new PcodeProgram(from, opsForThisStep);
		BlockSplitter splitter = new BlockSplitter(program) {
			@Override
			protected IntBranch newFallthroughIntBranch(PcodeOp from, PcodeOp to) {
				return new SIntBranch(from, to, true);
			}
		};
		splitter.addBranches(branchesForThisStep);
		SequencedMap<PcodeOp, JitBlock> blocks = splitter.splitBlocks();
		JitBlock entry = blocks.firstEntry().getValue();
		JitBlock exit = blocks.lastEntry().getValue();

		Map<JitBlock, Reachability> reachable = new HashMap<>();
		collectReachable(reachable, entry, Reachability.WITHOUT_CTXMOD);

		for (JitBlock block : blocks.values()) {
			Reachability reach = reachable.get(block);
			if (reach == null) {
				continue;
			}
			for (PcodeOp op : block.getCode()) {
				if (op != probeOp) {
					stride.opsForStride.add(op);
				}
			}
			for (IntBranch branch : block.branchesFrom()) {
				if (!branch.isFall()) {
					switch (branch) {
						case SIntBranch ib -> stride.passage.internalBranches.put(ib.from(),
							ib.withReach(reach));
						default -> throw new AssertionError();
					}
				}
			}
			for (Branch branch : block.branchesOut()) {
				if (branch != probeBranch) {
					switch (branch) {
						case SExtBranch eb -> stride.passage.flowTo(eb.withReach(reach));
						case SIndBranch ib -> stride.passage.otherBranches.put(ib.from(),
							ib.withReach(reach));
						case PBranch pb -> stride.passage.otherBranches.put(pb.from(), pb);
						default -> throw new AssertionError();
					}
				}
			}
		}

		return reachable.get(exit);
	}
After p-code interpretation, check if the instruction has fall through, notify the stride
decoder of the instruction's ops, and notify the passage of the instruction's branches.

<p>
To determine whether there's fall through, this performs a miniature control flow analysis on
just this step's p-code ops. This is required because a user inject can be very complex, and
need not obey all of the usual control flow checks imposed by the Sleigh semantic compiler.
In particular {@link Instruction#hasFallthrough()} is not sufficient, for at least two
reasons: 1) The aforementioned user inject possibilities, 2) We do not consider a
{@link PcodeOp#CALL call} or {@link PcodeOp#CALLIND callind} as having fall through.

<p>
To use control flow analysis as a means of checking for fall through, we append a special
"probe" {@link ExitPcodeOp} along with an {@link ExtBranch} record to {@link AddrCtx#NOWHERE
nowhere}. The probe thus serves the secondary purpose of preventing any complaints from the
analyzer about unterminated control flow. We then perform the analysis, borrowing
{@link BlockSplitter} from {@link JitControlFlowModel}. In practice, this seems fast enough.
Because the splitter keeps the blocks in the original order, the first op will certainly be
in the first block, and the probe op will certainly be in the last block. We perform a simple
reachability test between the two. The step has fall through if and only if a path is found.

@param from the instruction's or inject's p-code
@return the reachability of the fall-through flow
Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/jit/decode/DecoderExecutor.java