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

import dspl.SymbolTable;
import dspl.backend.AssemblyfileGenerator;
import dspl.backend.InstructionProcessor;
import dspl.backend.LoopInstructionProcessor;
import dspl.backend.x86.operands.X86Operand;
import dspl.intermediate.instructions.LoopInstruction;
import dspl.intermediate.variable.Variable;

/**
 * Converts Loop Instructions into the appriopriate X86 machine code. 
 * @author David
 *
 */
public class X86LoopInstructionProcessor extends LoopInstructionProcessor {

	/* (non-Javadoc)
	 * @see dspl.backend.LoopInstructionProcessor#ProcessLoopInstruction(dspl.intermediate.instructions.LoopInstruction, dspl.backend.InstructionProcessor, dspl.SymbolTable, dspl.backend.AssemblyfileGenerator)
	 */
	public void ProcessLoopInstruction(LoopInstruction inst,
			InstructionProcessor ip, SymbolTable st, AssemblyfileGenerator afg) {
		Variable arg1 = inst.comp.arg1; 
		Variable arg2 = inst.comp.arg2;
		
		//TODO: (Dave) branch instructions involving comparisons between arrays, or redefine LRM to elminate comparisons between arrays
		if (arg1.isArray() || arg2.isArray()) { 
			throw new Error("Comparisons of arrays is not yet supported"); 
		}
		
		else {
			String startOfLoopLabel  = afg.getBranchLabel(); //the label to branch to if the comparison evaluates false
			String afterBranchLabel = afg.getBranchLabel(); 
			
			X86Operand argOp1, argOp2; 
			
			afg.writeLabel(startOfLoopLabel); 
			
			//if arg2 is constant, can utilize immediate comparison
			argOp1 = X86VariableManager.prepareArg1Variable(arg1, X86Operand.OPERAND_TYPE_REGISTER, afg); 
			argOp2 = X86VariableManager.prepareArg2Variable(arg2, X86Operand.OPERAND_CLASS_ANY, afg); 
			afg.writeAsmInstr("cmp", argOp2.toString(), argOp1.toString()); //ORDER OF OPERANDS VERY IMPORTANT!!! 
					
			//write the appriopriate branch instruction which occurs if arg1 *operation* arg2 is false
			afg.writeAsmInstr(X86BranchInstructionProcessor.getConditionalJumpInstruction(inst.comp.condition, inst.comp.arg1), afterBranchLabel); 
			
			//write out all of the instructions within the loop
			ip.processInstruction(inst.loopInstr); 
			
			//if it is a "for" loop, perform the arithmatic instructions listed in the for loop
			ip.processInstruction(inst.arithmaticInstr); //at the end, write out the loop's arithmatic instructions
			
			//at the end of loop jump back to the begining
			afg.writeAsmInstr("jmp", startOfLoopLabel); 
			
			//write the afterBranchLabel which if will jump to after it has evalutead all of its instructions
			afg.writeLabel(afterBranchLabel);  
		}
	}

}
