public Varnode add(Varnode val1, Varnode val2, ContextEvaluator evaluator) {
		if (val1 == null || val2 == null) {
			return null;
		}
		// try to make the constant value the addend.
		if (isConstant(val1) || val1.isAddress()) {
			Varnode swap = val1;
			val1 = val2;
			val2 = swap;
		}
		int spaceID = val1.getSpace();
		long valbase = 0;
		if (isRegister(val1) && val1.equals(val2)) {
			// if both are registers, don't need to do extra
			// checking, adding a register and a register will fail.
		}
		else if (isRegister(val1)) {
			Register reg = trans.getRegister(val1);
			if (reg == null) {
				return null;
			}
			spaceID = getAddressSpace(reg.getName(),reg.getBitLength());
			valbase = 0;
			// check if evaluator wants to override unknown
			Instruction instr = getCurrentInstruction(currentAddress);
			if (evaluator != null) {
				Long uval = evaluator.unknownValue(this, instr, val1);
				if (uval != null) {
					// 2nd value could be a constant, or a register, which would create an offset from reg
					valbase = uval.longValue();
					spaceID = val2.getSpace();
				}
			}
		}
		else if (val1.getAddress() == BAD_ADDRESS) {
			// use bad address offset space, allows offsets to unknown things to continue
			// TODO: Investigate if the source of the BAD_ADDRESS can be known
			spaceID = BAD_OFFSET_SPACEID;
			valbase = 0;
			// check if evaluator wants to override unknown
			Instruction instr = getCurrentInstruction(currentAddress);
			if (evaluator != null) {
				Long uval = evaluator.unknownValue(this, instr, val1);
				if (uval != null) {
					// 2nd value could be a constant, or a register, which would create an offset from reg
					valbase = uval.longValue();
					spaceID = val2.getSpace();
				}
			}
		}
		else if (isConstant(val1)) {
			valbase = val1.getOffset();
			if (!isSuspectConstant(val1)) {
				spaceID = val2.getSpace();
			}
		}
		else if (isSymbolicSpace(spaceID)) {
			Instruction instr = getCurrentInstruction(currentAddress);
			valbase = val1.getOffset();
			if (evaluator != null) {
				Long uval = evaluator.unknownValue(this, instr, val1);
				if (uval != null) {
					if (val2.isRegister()) {
						String spaceName = addrFactory.getAddressSpace(spaceID).getName();
						Register reg2 = trans.getRegister(val2);
						if (spaceName.equals(reg2.getName()) ||
							spaceName.startsWith(reg2.getName() + "-")) {
							// since this is essentially a multiply by two, and it is the same register
							//   just multiply the current offset by 2, since we really don't know
							//   the base register anyway...
							valbase += uval.longValue() * 2;
							return createConstantVarnode(valbase, val1.getSize());
						}
					}
					valbase = uval.longValue();
					return add(createConstantVarnode(valbase, val1.getSize()), val2, evaluator);

				}
			}
		}
		else {
			return null;
		}

		// create a new varnode with the correct space and offset
		// note: if spaceID is a bad space, createVarnode will create a new BAD_ADDRESS
		Long val2Const = getConstant(val2, null);
		if (val2Const == null) {
			return null;
		}
		long result = (valbase + val2Const) &
			(0xffffffffffffffffL >>> ((8 - val1.getSize()) * 8));
		return createVarnode(result, spaceID, val1.getSize());
	}
Add two varnodes together to get a new value
This could create a new space and return a varnode pointed into that space

@param val1 first value
@param val2 second value
@return varnode that could be a constant, or an offset into a space, or null
Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java