/* ------------------------------------------------------------------------ */ /* ---------- Gen3Op: GENERATE CODE FOR A 3 OPERAND INSTRUCTION ---------- */ /* ------------------------------------------------------------------------ */ /* * Generate the code to perform "result := addr1 instr addr2", i.e., generate * code for a "quadruple", where result is always a register (determined by * this routine), but addr1 and addr2 can be arbitrary addresses. * * SPIM: instr result, addr1, addr2 * * To minimize register usage, if addr1 is already in a register use this as the * result register. * * If the instr can commute, then swap addr1 and addr2 depending on which is * already in a register. * * Spim restrictions: addr2 can be register or immediate so when the instr * commutes you want to swap addr1 and addr2 to have immediate last */ static void Gen3Op(INSTRUCTION instr, MACHINEADDRPTR result, MACHINEADDRPTR addr1, MACHINEADDRPTR addr2) { MACHINEADDRPTR temp; if (PtraceCode) { Entering("Gen3Op"); } switch (instr) { case Isne: case Ior: case Ixor: case Iand: case Iseq: case Imult: case Iadd: /* * These operations commute, so we will reverse the order of * evaluation if it is to our advantage. */ if (addr1->mode == directregister) { MaCopy(result, addr1); /* keep the result in same * register */ /* * note - if addr2 is a direct register or an * immediate, addr2 ready to go */ /* * if addr2 is registeroffset, must load in a * register */ if (addr2->mode == registeroffset) { temp = mach_alloc(); LoadArithReg(temp, addr2); /* * overwrite addr2 with temp - addr2 is * already to go now */ MaCopy(addr2, temp); } WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr1); fprintf(CodeFile, ","); WriteAddr(addr2); fprintf(CodeFile, "\n"); /* * if both operands were in registers, indicate the * second register is free. */ if (addr2->mode == directregister) regfree[addr2->ma.regaddr] = TRUE; } /* end if addr1 is directregister */ else if (addr2->mode == directregister) { /* * see comments above when addr1 was a * directregister, similar ops */ MaCopy(result, addr2); if (addr1->mode == registeroffset) { temp = mach_alloc(); LoadArithReg(temp, addr1); MaCopy(addr1, temp); } WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr2); fprintf(CodeFile, ","); WriteAddr(addr1); if (addr1->mode == directregister) regfree[addr1->ma.regaddr] = TRUE; fprintf(CodeFile, "\n"); } /* end elseif addr2 is directregister */ /* * neither operand is an expression already since it's not * already in a tree - so now we to load the leaves */ else { /* due do SPIM, can be efficient with * immediates here */ /* * check if either operand is an immediate then load * the other one - note an exprtree with 2 + 4 would * have been folded in sem.c */ if (addr1->mode == immediateValue) { /* * Move a copy of the second operand to a * register */ LoadArithReg(result, addr2); WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr1); fprintf(CodeFile, "\n"); } /* end if addr1 is immediate */ else if (addr2->mode == immediateValue) { /* * Move a copy of the first operand to a * register */ LoadArithReg(result, addr1); WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr2); fprintf(CodeFile, "\n"); } /* end else if addr2 is immediate */ /* * both operands are register offset, so both must be * loaded to reg */ else { LoadArithReg(result, addr1); temp = mach_alloc(); LoadArithReg(temp, addr2); WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(temp); regfree[temp->ma.regaddr] = TRUE; fprintf(CodeFile, "\n"); } /* end else - neither was immediate */ } /* end else - neither is a directregister */ break; /* * ------- non-commuting operators * ------------------------------- */ case Idiv: case Isge: case Isgt: case Isle: case Islt: case Isub: if (addr1->mode == directregister) { MaCopy(result, addr1); /* keep the result in same * register */ /* * note - if addr2 is a direct register or an * immediate, addr2 ready to go */ /* * if addr2 is registeroffset, must load in a * register */ if (addr2->mode == registeroffset) { temp = mach_alloc(); LoadArithReg(temp, addr2); /* * overwrite addr2 with temp - addr2 is * already to go now */ MaCopy(addr2, temp); } WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr1); fprintf(CodeFile, ","); WriteAddr(addr2); fprintf(CodeFile, "\n"); /* * if both operands were in registers, indicate the * second register is free. */ if (addr2->mode == directregister) regfree[addr2->ma.regaddr] = TRUE; } /* end if addr1 is directregister */ else { /* need to load addr1 into a register, but * know nothing about addr2 yet */ LoadArithReg(result, addr1); if (addr2->mode != directregister) { temp = mach_alloc(); LoadArithReg(temp, addr2); MaCopy(addr2, temp); } WriteInstr(instr); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(result); fprintf(CodeFile, ","); WriteAddr(addr2); regfree[addr2->ma.regaddr] = TRUE; fprintf(CodeFile, "\n"); } break; /* sub/div which do not commute */ default: fprintf(stderr, "Illegal opcode in Gen3Op\n"); } /* case */ if (PtraceCode) { /* fprintf(CodeFile,"\n"); */ Leaving("Gen3Op"); } } /* Gen3Op */