/**
 * 
 */
package dspl.backend.x86.operands;

import dspl.intermediate.variable.Variable;

/**
 * X86IndexedMemoryOperand is an operand of the form: variable(base, index, size)<br>
 * <ul>
 * <li>variable: an 8, 16, or 32 bit value (from parent variable: either array or complex)</li>
 * <li>base: (register) or can be null</li>
 * <li>index: an index into the variable specified by displacement</li>
 * <li>size: the size of the type of the variable (must be either 2, 4, or 8)</li>
 * </ul>
 * Example: <br>
 * movl $5, %edx<br>
 * movl $10, a(,%edx,4)<br>
 * The above is equivalent to a[5] = 10; //assuming a is an int_array (data type of size 4)
 * @author David
 */
public class X86IndexMemoryOperand extends X86Operand {
	private String varStr; //can either be explicitly provided in constructor or taken from Variable, depending on which constructor is used
	private X86Register baseRegister; 
	private X86Register indexRegister; 
	private int size; 
	
	/**
	 * Used when one wants to explicitly create an IndexMemoryOperand like (%eax, %ecx, 4), which might not have a variable
	 * @param var
	 * @param baseRegister
	 * @param indexRegister
	 * @param size
	 */
	public X86IndexMemoryOperand(String var, X86Register baseRegister, X86Register indexRegister, int size) {
		if (var==null) { 
			throw new Error("var cannot be null"); 
		}
		if (indexRegister==null) { 
			throw new Error("indexRegister cannot be null"); 
		}
		if (size!=1 && size!= 2 && size !=4 && size !=8) { 
			throw new Error("invalid size; must be 1,2,4, or 8"); 
		}
		
		this.varStr = var;
		this.baseRegister = baseRegister;
		this.indexRegister = indexRegister;
		this.size = size; 
	}
	
	public X86IndexMemoryOperand(Variable var, X86Register baseRegister, X86Register indexRegister, int size) {
		if (var==null) { 
			throw new Error("var cannot be null"); 
		}
		if (indexRegister==null) { 
			throw new Error("indexRegister cannot be null"); 
		}
		if (size!=1 && size!= 2 && size !=4 && size !=8) { 
			throw new Error("invalid size; must be 1,2,4, or 8"); 
		}
		
		this.varStr = var.getIdentifier();
		this.baseRegister = baseRegister;
		this.indexRegister = indexRegister;
		this.size = size; 
	}
	
	/* (non-Javadoc)
	 * @see dspl.backend.x86.operands.X86Operand#freeOperand()
	 */
	public void freeOperand() {
		if (baseRegister!=null) { 
			baseRegister.freeRegister(); 
		}
		if (indexRegister!=null) { 
			indexRegister.freeRegister(); 
		}
	}

	/* (non-Javadoc)
	 * @see dspl.backend.x86.operands.X86Operand#getOperandType()
	 */
	public int getOperandType() {
		return X86Operand.OPERAND_TYPE_INDEXED_MEMORY;
	}

	/* (non-Javadoc)
	 * @see dspl.backend.x86.operands.X86Operand#toString()
	 */
	public String toString() {
		String baseString, indexString, sizeString; 
	
		//var(%eax, %ebx, 4) 
		if (baseRegister!=null) { 
			baseString = baseRegister.toString(); 
		}
		//var(,%ebx, 4) 
		else { 
			baseString = ""; 
		}
		indexString = indexRegister.toString(); 
		sizeString = Integer.toString(size); 
		
		return new String(varStr + "(" + baseString + "," + indexString + "," + sizeString + ")"); 
	}

	public int getOperandSize() {
		return size; 
	}

}
