@Override
	public void generateRunCode(JitCodeGenerator gen, JitCBranchOp op, JitBlock block,
			MethodVisitor rv) {
		if (op.op() instanceof ExitPcodeOp && op.branch() instanceof RExtBranch eb) {
			assert eb.reach() == Reachability.MAYBE_CTXMOD;
			Label fall = new Label();
			RunFixedLocal.CTXMOD.generateLoadCode(rv);
			rv.visitJumpInsn(IFEQ, fall);
			BranchOpGen.generateExitCode(gen, eb.to().address, block, rv);
			rv.visitLabel(fall);
			return;
		}

		JitType cType = gen.generateValReadCode(op.cond(), op.condType());
		TypeConversions.generateIntToBool(cType, rv);
		switch (op.branch()) {
			case RIntBranch ib -> IntCBranchGen.C_INT.generateCode(gen, op, ib, block, rv);
			case RExtBranch eb -> ExtCBranchGen.C_EXT.generateCode(gen, op, eb, block, rv);
			default -> throw new AssertionError("Branch type confusion");
		}
	}
{@inheritDoc}

@implNote In addition to implementing the proper logic for a conditional branch, this
          contains a special case for synthetic branches created using
          {@link ExitPcodeOp#cond(AddrCtx)}. Such synthetic ops are employed to check for
          context modification at instruction fall through. It's rare, but if there are
          multiple paths in an instruction's p-code or an injection, where one causes context
          modification and the other does not, then we must check for context modification at
          run time.
          <p>
          Conventionally, all {@link PcodeOp#CBRANCH} ops should have the condition as its
          second operand. Our special "conditional exit" does not. The
          {@link JitDataFlowModel} recognizes this and uses {@link JitFailVal} for
          {@link JitCBranchOp#cond()}. The "fail" value asserts that it never gets generated,
          which will ensure we apply special handling here.
Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/jit/gen/op/CBranchOpGen.java