private boolean applyPcode(Stack<SavedFlowState> contextStack, VarnodeContext vContext, Instruction instruction, int startIndex, int continueAfterHittingFlow, TaskMonitor monitor) {
		Address nextAddr = null;

		if (instruction == null) {
			return false;
		}

		// might have run into this pcode before, cache it, in case we run into it again.
		PcodeOp[] ops = getInstructionPcode(instruction);

		if (ops.length <= 0) {
			// is a nop
			return true;
		}

		Address minInstrAddress = instruction.getMinAddress();
		if (debug)
		{
			Msg.info(this, minInstrAddress + "   " + instruction + "   " + startIndex);
		}

		// callfixup injection targets that have already been used
		HashSet<Address> previousInjectionTarget = new HashSet<>();

		int mustClearAllUntil_PcodeIndex = -1;
		// flag won't get set until there is something to clear
		boolean mustClearAll = false;
		// if inject pcode, don't want to do any store pcode ops for the injected code
		boolean injected = false;

		int ptype = 0;
		for (int pcodeIndex = startIndex; pcodeIndex < ops.length; pcodeIndex++) {

			mustClearAll = pcodeIndex < mustClearAllUntil_PcodeIndex;

			PcodeOp pcodeOp = ops[pcodeIndex];
			ptype = pcodeOp.getOpcode();
			Varnode out = pcodeOp.getOutput();
			Varnode[] in = pcodeOp.getInputs();

			Varnode val1, val2, val3;
			Varnode result = null;
			Long longVal1, longVal2;
			long lresult;
			boolean suspectOffset = false;
			Varnode vt;
			if (debug) {
				Msg.info(this, "   " + pcodeOp);
			}

			try {
				switch (ptype) {
					case PcodeOp.COPY:
						if (in[0].isAddress() &&
							!in[0].getAddress().getAddressSpace().hasMappedRegisters()) {
							makeReference(vContext, instruction,  Reference.MNEMONIC, in[0],
								null, RefType.READ, ptype, true, monitor);
						}
						vContext.copy(out, in[0], mustClearAll, evaluator);
						break;

					case PcodeOp.LOAD:
						Varnode memVal = null;
						val1 = vContext.getValue(in[0], evaluator);
						val2 = vContext.getValue(in[1], evaluator);
						if (val1 != null && val2 != null) {
							suspectOffset = vContext.isSuspectConstant(val2);
							
							vt = vContext.getVarnode(in[0], val2, out.getSize(), evaluator);
							
							// TODO: may need to use DATA refType in some cases
							
							if (vt != null) {
								addLoadStoreReference(vContext, instruction, ptype, vt, in[0], in[1],
									RefType.READ, suspectOffset==false, monitor);
								// If vt is a bad varnode (bad space, no memory, no value in varnode) you won't get a value
								memVal = vContext.getValue(vt, evaluator);
							}
						}
						vContext.putValue(out, memVal, mustClearAll);
						break;

					case PcodeOp.STORE:

						Varnode offs = null;
						offs = vContext.getValue(in[1], true, evaluator);
						if (offs != null) {
							suspectOffset = vContext.isSuspectConstant(offs);
							out = getStoredLocation(vContext, in[0], offs, in[2]);
						}
						
						// TODO: may need to use DATA refType in some cases
						addLoadStoreReference(vContext, instruction, ptype, out, in[0], in[1],
							RefType.WRITE, suspectOffset==false, monitor);

						val3 = vContext.getValue(in[2], null);

						if (val3 != null && !injected) {
							addStoredReferences(vContext, instruction, out, val3, monitor);
						}
						vContext.putValue(out, val3, mustClearAll);
						break;

					case PcodeOp.BRANCHIND:
						val1 = vContext.getValue(in[0], evaluator);
						if (val1 != null) {
							suspectOffset = vContext.isSuspectConstant(val1);
							
							vt = getConstantOrExternal(vContext, minInstrAddress, val1);
							if (vt != null) {
								makeReference(vContext, instruction, -1, vt, null,
									instruction.getFlowType(), ptype, !suspectOffset, monitor);
							}
						}
						
						// even if we don't know the destination, branch to any jump
						// references already on the branch indirect
						vContext.propogateResults(true);
						Reference[] flowRefs = instruction.getReferencesFrom();
						for (Reference flowRef : flowRefs) {
							RefType referenceType = flowRef.getReferenceType();
							if (referenceType.isComputed() && referenceType.isJump()) {
								contextStack.push(new SavedFlowState(vContext,
									FlowType.UNCONDITIONAL_JUMP, flowRef.getFromAddress(),
									flowRef.getToAddress(), continueAfterHittingFlow));
							}
						}

						if (evaluator != null &&
							evaluator.evaluateDestination(vContext, instruction)) {
							canceled = true;
							return false;
						}
						break;

					case PcodeOp.CALLIND:
					case PcodeOp.CALL:
						Address target = null;
						Function func = null;
						val1 = in[0];
						if (ptype == PcodeOp.CALLIND) {
								val1 = vContext.getValue(val1, evaluator);

								if (val1 != null) {
									// TODO: Revisit handling of external functions...
	
									if (vContext.isConstant(val1)) {
										suspectOffset = vContext.isSuspectConstant(val1);
										// indirect target - assume single code space (same as instruction)
										target = instruction.getAddress()
												.getNewTruncatedAddress(val1.getOffset(), true);
									}
									else if (val1.isAddress()) {
										// TODO: could this also occur if a memory location was copied ??
										// unable to resolve indirect value - can we trust stored pointer?
										// if not, we must rely on reference to function.
										target = resolveFunctionReference(val1.getAddress());
									}
									else if (vContext.isExternalSpace(val1.getSpace())) {
										target = val1.getAddress();
									}
									// if the value didn't get changed, then the real value isn't in here, don't make a reference
									if (target != null) {
										Reference[] refs = instruction.getReferencesFrom();
										// make sure we aren't replacing a read ref with a call to the same place
										if (refs.length <= 0 ||
											!refs[0].getToAddress().equals(target)) {
	
											target = makeReference(vContext, instruction, Reference.MNEMONIC,
												//  Use target in case location has shifted (external...)
												target.getAddressSpace().getSpaceID(),
												target.getAddressableWordOffset(), val1.getSize(),
												null,
												instruction.getFlowType(), ptype, !suspectOffset, false, monitor);
										}
									}
								}
						}
						else {
							// CALL will always provide address
							target = val1.getAddress();

							// TODO: If address not contained within memory we should 
							//       try to locate corresponding external function
						}

						Program prog = instruction.getProgram();

						if (target != null) {
							if (target.isMemoryAddress()) {
								vContext.propogateResults(false);
							}
							func = getFunctionAt(target);
							if (func == null && ptype == PcodeOp.CALLIND) {
								Reference[] refs = instruction.getReferencesFrom();
								if (refs != null && refs.length > 0) {
									Reference firstRef = refs[0];
									if (firstRef.getReferenceType().isData() ||
										firstRef.getReferenceType().isIndirect()) {
										target = firstRef.getToAddress();
										func = getFunctionAt(target);
									}
								}
							}
							// check for pcode replacement - callfixup
							//   don't re-inject to the same site.
							if (!previousInjectionTarget.contains(target)) {
								PcodeOp[] injectionPcode =
									checkForCallFixup(prog, func, instruction);
								if (injectionPcode != null && injectionPcode.length > 0) {
									previousInjectionTarget.add(target);
									ops = injectPcode(ops, pcodeIndex, injectionPcode);
									pcodeIndex = -1;
									injected = true;
									continue;
								}
							}
						}

						if (func != null && func.isInline()) {
							// push fallthru pcodeIndex after call
							contextStack.push(new SavedFlowState(vContext, FALL_THROUGH, minInstrAddress, func.getEntryPoint(), pcodeIndex+1 , continueAfterHittingFlow));
							// push the call so it will happen first
							contextStack.push(new SavedFlowState(vContext, UNCONDITIONAL_CALL, minInstrAddress, func.getEntryPoint(), continueAfterHittingFlow));
							return false;
						}
						handleFunctionSideEffects(instruction, target, monitor);

						// check for pcode replacement - calling convention uponreturn injection
						PcodeOp[] injectionPcode = checkForUponReturnCallMechanismInjection(prog,
							func, target, instruction);
						if (injectionPcode != null && injectionPcode.length > 0) {
							ops = injectPcode(ops, pcodeIndex, injectionPcode);
							pcodeIndex = -1;
							injected = true;
							continue;
						}
						
						break;

					// for callother, could be an interrupt, need to look at it like a call
					case PcodeOp.CALLOTHER:
						PcodeOp[] callOtherPcode = doCallOtherPcodeInjection(instruction, in, out);

						if (callOtherPcode != null) {
							ops = injectPcode(ops, pcodeIndex, callOtherPcode);
							pcodeIndex = -1;
							injected = true;
						}
						else if (out != null) {
							// clear out settings for the output from call other.
							vContext.putValue(out, vContext.createBadVarnode(), mustClearAll);
						}
						break;

					case PcodeOp.BRANCH:

						if (in[0].isConstant()) {
							// handle internal branch
							int sequenceOffset = (int) in[0].getOffset();
							if (sequenceOffset < 0) { // avoid internal looping
								pcodeIndex = ops.length; // break out of the processing
								break;
							}
							pcodeIndex += sequenceOffset - 1;
							ptype = PcodeOp.UNIMPLEMENTED; // just in case we are branching to the next instruction - allow context propagation
							break; // follow internal branch
						}

						if (!in[0].isAddress()) {
							throw new AssertException("Not a valid Address on instruction at " +
								instruction.getAddress());
						}
						vContext.propogateResults(true);
						nextAddr = minInstrAddress.getAddressSpace()
								.getOverlayAddress(in[0].getAddress());
						contextStack.push(new SavedFlowState(vContext, UNCONDITIONAL_JUMP, minInstrAddress, nextAddr, continueAfterHittingFlow));
						return false;

					case PcodeOp.CBRANCH:
						vt = null;
						boolean internalBranch = in[0].isConstant();
						if (internalBranch) {
							int sequenceOffset = (int) in[0].getOffset();
							if ((pcodeIndex + sequenceOffset) >= ops.length) {
								vContext.propogateResults(false);
							}
						}
						else if (in[0].isAddress()) {
							vt = in[0];
							vContext.propogateResults(false);
						}

						Varnode condition = vContext.getValue(in[1], null);

						if (condition != null) {
							longVal1 = vContext.getConstant(condition, null);
						} else {
							// couldn't find the condition, so arbitrary which way to go
							longVal1 = Long.valueOf(0);  // do fallthru first
						}
						boolean followFalse = evaluator.followFalseConditionalBranches();
						boolean conditionMet = longVal1 != null && longVal1 != 0;
						// if conditionMet, followBranch (local/mem), if followFalse, push new state for (local/mem)
						//        Need to push (local/mem) first, false first,  Then push branch, so happens first, return false to continue this run.
						// if conditionNotMet, followFallThru, if followFalse, push new state for branch (local/mem)
						if (conditionMet) {
							if (internalBranch) {
								// handle internal branch
								int sequenceOffset = (int) in[0].getOffset();
								// only go forwards in sequence, backwards could be a loop
								if (sequenceOffset > 0) {
									if (followFalse) {
										contextStack.push(new SavedFlowState(vContext, FALL_THROUGH, minInstrAddress,
											minInstrAddress, pcodeIndex+1, continueAfterHittingFlow));
									}
									pcodeIndex += sequenceOffset - 1;
								}
								else if (!followFalse) {
									// if not forward internal branch, and not following False flows, processing
									pcodeIndex = ops.length;
									break;
								}
							}
							else { // memory branch
								if (followFalse) {
									// push follow false first
									contextStack.push(new SavedFlowState(vContext, FALL_THROUGH, minInstrAddress,
										minInstrAddress, pcodeIndex+1, continueAfterHittingFlow));
								}
								
								// pcode addresses are raw addresses, make sure address is in same instruction space
								nextAddr = minInstrAddress.getAddressSpace()
										.getOverlayAddress(in[0].getAddress());
								contextStack.push(new SavedFlowState(vContext, CONDITIONAL_JUMP, minInstrAddress,
									nextAddr, continueAfterHittingFlow));
								
								pcodeIndex = ops.length; // break out of the processing
								return false; // don't keep going
							}
						} else {
							if (internalBranch) {
								// handle internal branch
								int sequenceOffset = (int) in[0].getOffset();
								// only go forwards in sequence, backwards could be a loop
								if (sequenceOffset > 0) {							
									int internalIndex = pcodeIndex + sequenceOffset;
									if (followFalse) {
										contextStack.push(new SavedFlowState(vContext, FALL_THROUGH, minInstrAddress,
											minInstrAddress, internalIndex, continueAfterHittingFlow));
									}
								}
								else if (!followFalse) {
									// if not forward internal branch, and not following False flows, processing
									pcodeIndex = ops.length;
									break;
								}
							}
							else { // memory branch
								if (followFalse) {
									// push follow false first
									nextAddr = minInstrAddress.getAddressSpace()
											.getOverlayAddress(in[0].getAddress());
									contextStack.push(new SavedFlowState(vContext, CONDITIONAL_JUMP, minInstrAddress,
										nextAddr, continueAfterHittingFlow));
								}
							}
						}
						break;

					case PcodeOp.RETURN:

						// if return value is a location, give evaluator a chance to check the value
						val1 = vContext.getValue(in[0], evaluator);
						if (val1 != null && evaluator != null &&
							evaluator.evaluateReturn(val1, vContext, instruction)) {
							canceled = true;
							return false;
						}
						// put references on any return value that is a pointer and could be returned

						addReturnReferences(instruction, vContext, monitor);
						break;

					case PcodeOp.INT_ZEXT:
						if (in[0].isAddress()) {
							makeReference(vContext, instruction, Reference.MNEMONIC, in[0],
								null, RefType.READ, ptype, true, monitor);
						}
						val1 = vContext.extendValue(out, in, false, evaluator);
						vContext.putValue(out, val1, mustClearAll);
						break;

					case PcodeOp.INT_SEXT:
						if (in[0].isAddress()) {
							makeReference(vContext, instruction,  Reference.MNEMONIC, in[0],
								null, RefType.READ, ptype, true, monitor);
						}
						val1 = vContext.extendValue(out, in, true, evaluator);
						vContext.putValue(out, val1, mustClearAll);
						break;

					case PcodeOp.INT_ADD:
						val1 = vContext.getValue(in[0], false, evaluator);
						if (val1 == null) {
							val1 = vContext.createBadVarnode();
						}
						val2 = vContext.getValue(in[1], false, evaluator);
						if (val2 == null) {
							val2 = vContext.createBadVarnode();
						}
						if (val1.equals(val2)) {
							Long v = vContext.getConstant(val1, evaluator);
							if (v != null) {
								val1 = val2 = vContext.createConstantVarnode(v, val1.getSize());
							}
						}
						
						result = vContext.add(val1, val2, evaluator);
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SUB:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						result = vContext.subtract(val1, val2, evaluator);
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_CARRY:
					case PcodeOp.INT_SCARRY:
					case PcodeOp.INT_SBORROW:
						BinaryOpBehavior binaryBehavior =
							(BinaryOpBehavior) OpBehaviorFactory.getOpBehavior(ptype);
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = binaryBehavior.evaluateBinary(out.getSize(), in[0].getSize(),
								longVal1, longVal2);
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_2COMP:
						UnaryOpBehavior unaryBehavior =
							(UnaryOpBehavior) OpBehaviorFactory.getOpBehavior(ptype);
						val1 = vContext.getValue(in[0], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						if (longVal1 != null) {
							lresult = unaryBehavior.evaluateUnary(out.getSize(), in[0].getSize(),
								longVal1);
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_NEGATE:
						val1 = vContext.getValue(in[0], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						if (longVal1 != null) {
							result = vContext.createConstantVarnode(
								~longVal1, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_XOR:
						if (in[0].isRegister() && in[0].equals(in[1])) {
							result = vContext.createConstantVarnode(0, out.getSize());
						}
						else {
							val1 = vContext.getValue(in[0], false, evaluator);
							val2 = vContext.getValue(in[1], false, evaluator);
							longVal1 = vContext.getConstant(val1, evaluator);
							longVal2 = vContext.getConstant(val2, evaluator);
							if (longVal1 != null && longVal2 != null) {	
								lresult = longVal1 ^ longVal2;
								result = vContext.createConstantVarnode(lresult, val1.getSize());
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_AND:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						result = vContext.and(val1, val2, evaluator);
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_OR:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						result = vContext.or(val1, val2, evaluator);
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_LEFT:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						result = vContext.left(val1, val2, evaluator);
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_RIGHT:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult =  longVal1 >> longVal2 ;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SRIGHT:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = longVal1 >>> longVal2;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_MULT:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = longVal1 * longVal2;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_DIV:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null & longVal2 != null) {
							if (longVal2 != 0) {
								lresult = longVal1 / longVal2;
								result = vContext.createConstantVarnode(lresult, val1.getSize());
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SDIV:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							if (longVal2 != 0) {
								lresult = longVal1 / longVal2;
								result = vContext.createConstantVarnode(lresult, val1.getSize());
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_REM:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							if (longVal2 != 0) {
								lresult = longVal1 % longVal2;
								result = vContext.createConstantVarnode(lresult, val1.getSize());
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SREM:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							if (longVal2 != 0) {
								lresult = longVal1 % longVal2;
								result = vContext.createConstantVarnode(lresult, val1.getSize());
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.SUBPIECE:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (val1 != null && longVal2 != null) {
							long subbyte = 8 * longVal2;
	
							if (vContext.isSymbol(val1) & subbyte == 0 &&
								out.getSize() == instruction.getAddress().getPointerSize()) {
								// assume the subpiece is just downcasting to be used as a pointer, just ignore, since this is already an offset, and shouldn't matter.
								result = val1;
							}
							else if (out.getSize() > 8) {
								// too big, result will be null
							}
							else {
								longVal1 = vContext.getConstant(val1, evaluator);
								if (longVal1 != null) {
									lresult = (longVal1 >> (subbyte)) & maskSize[out.getSize()];
									result = vContext.createConstantVarnode(lresult, out.getSize());
								}
							}
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_LESS:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = Long.compareUnsigned(longVal1, longVal2) < 0 ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SLESS:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = (longVal1 < longVal2) ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_LESSEQUAL:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = Long.compareUnsigned(longVal1, longVal2) <= 0 ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_SLESSEQUAL:
						val1 = vContext.getValue(in[0], true, evaluator);
						val2 = vContext.getValue(in[1], true, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = (longVal1 <= longVal2) ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_EQUAL:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = (longVal1 == longVal2) ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.INT_NOTEQUAL:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = (longVal1 != longVal2) ? 1 : 0;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.BOOL_NEGATE:
						val1 = vContext.getValue(in[0], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						if (longVal1 != null) {
							lresult = (longVal1 == 0 ? 1 : 0);
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.BOOL_XOR:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = longVal1 ^ longVal2;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.BOOL_AND:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = longVal1 & longVal2;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					case PcodeOp.BOOL_OR:
						val1 = vContext.getValue(in[0], false, evaluator);
						val2 = vContext.getValue(in[1], false, evaluator);
						longVal1 = vContext.getConstant(val1, evaluator);
						longVal2 = vContext.getConstant(val2, evaluator);
						if (longVal1 != null && longVal2 != null) {
							lresult = longVal1 | longVal2;
							result = vContext.createConstantVarnode(lresult, val1.getSize());
						}
						vContext.putValue(out, result, mustClearAll);
						break;

					default:
						// clear out any output varnode - set to null
						if (out != null) {
							vContext.putValue(out, null, false);
						}
						break;
				}
			}
			catch (AddressOutOfBoundsException e) {
				// The computation did something bad for some reason, need to null the out varnode
				if (out != null) {
					vContext.putValue(out, null, false);
				}
			}
		}

		vContext.propogateResults(true);

		return true;
	}
Apply pcode from an instruction to current varnode context.
Following a flow will push a new context state based on the current context state onto the contextStack

@param contextStack context state stack
@param vContext varnode context
@param instruction instruction to apply pcode from
@param continueAfterHittingFlow true if should continue after hitting an already processed flow
@param monitor to cancel
@return true to to continue this instruction path, false otherwise
Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java