private int findOpIndexForRef(VarnodeContext vcontext, Instruction instruction, int opIndex,
			long wordOffset, RefType refType) {

		int numOperands = instruction.getNumOperands();

		for (int i = 0; i < numOperands; i++) {
			int opType = instruction.getOperandType(i);

			if ((opType & OperandType.ADDRESS) != 0) {
				Address opAddr = instruction.getAddress(i);
				if (opAddr != null && opAddr.getAddressableWordOffset() == wordOffset) {
					opIndex = i;
					break;
				}
			}
			if ((opType & OperandType.SCALAR) != 0) {
				Scalar s = instruction.getScalar(i);
				if (s != null) {
					long val = s.getUnsignedValue();
					// sort of a hack, for memory that is not byte addressable
					if (val == wordOffset || val == (wordOffset >> 1)) {
						opIndex = i;
						break;
					}
				}
			}
			
			// Don't check more complicated operands if already found an operand that matches
			// only continue checking for an exact scalar/address operand
			if (opIndex != Reference.MNEMONIC) {
				continue;
			}
			
			// markup the program counter for any flow
			if ((opType & OperandType.REGISTER) != 0) {
				Register reg = instruction.getRegister(i);
				if (refType.isFlow() && reg != null && reg.isProgramCounter()) {
					opIndex = i;
					break;
				}
				if (reg != null) {
					// value for pointer can differ by 1 bit, which is sometimes ignored for flow
					if (checkOffByOne(reg, wordOffset)) {
						opIndex = i;
						if (refType.isFlow()) {
							break;
						}
					}
					if (checkOffByOne(reg.getParentRegister(), wordOffset)) {
						opIndex = i;
						if (refType.isFlow()) {
							break;
						}
					}
				}
			}

			if ((opType & OperandType.DYNAMIC) != 0) {
				List<Object> list = instruction.getDefaultOperandRepresentationList(i);
				int len = list.size();
				if (len > 0) {
					long baseRegVal = 0;
					long offset_residue_pos = wordOffset; // subtract all register values and add constants, check for zero
					long offset_residue_neg = wordOffset; // subtract all registers and subtract constants, check for zero
					for (int idx = 0; idx < len; idx++) {
						Object obj = list.get(idx);
						if (obj instanceof Scalar) {
							long val = ((Scalar) obj).getUnsignedValue();
							// sort of a hack, for memory that is not byte addressable
							if (val == wordOffset || val == (wordOffset >> 1) ||
								(val + baseRegVal) == wordOffset) {
								opIndex = i;
								break;
							}
							val = ((Scalar) obj).getSignedValue();
							offset_residue_neg -= val;
							offset_residue_pos += val;
						}
						if (obj instanceof Register) {
							Register reg = (Register) obj;
							BigInteger val = vcontext.getValue(reg, false);
							if (val != null) {
								baseRegVal = val.longValue();
								if ((baseRegVal & pointerMask) == wordOffset) {
									opIndex = i;
								}
								offset_residue_neg -= baseRegVal;
								offset_residue_pos -= baseRegVal;
							}
						}
					}
					if (offset_residue_neg == 0 || offset_residue_pos == 0) {
						opIndex = i;
						break;
					}
					if (opIndex == Reference.MNEMONIC && i == (numOperands - 1)) {
						opIndex = i;
					}
				}
			}
		}
		return opIndex;
	}
Evaluate reference type for a pure data reference for valid reference to instructions

@param instruction that reference is from
@param target of reference
@param wordOffset target address word offset
@param refType type of reference

@return true if not a pure data ref, or the reference is OK to make
Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java