public void CGenPrepareWord(Env env, CGenState state) { // 1. Load lhs to EAX. // // regs: // %eax = lhs // // stack: // +-----+ // | ... | <- %esp // +-----+ // if (lhs.CGenValue(env, state) != Reg.EAX) { throw new InvalidOperationException(); } // 2. Push lhs to stack. // // regs: // %eax = lhs // // stack: // +-----+ // | ... | // +-----+ // | lhs | <- %esp has decreased by 4 // +-----+ // Int32 stack_size = state.CGenPushLong(Reg.EAX); // 3. Load rhs to EAX. // // regs: // %eax = rhs // // stack: // +-----+ // | ... | // +-----+ // | lhs | <- %esp // +-----+ // if (rhs.CGenValue(env, state) != Reg.EAX) { throw new InvalidOperationException(); } // 4. Move rhs into EBX. Pop lhs from stack, into EAX. // // regs: // %eax = lhs // %ebx = rhs // // stack: // +-----+ // | ... | <- %esp has moved back. // +-----+ // state.MOVL(Reg.EAX, Reg.EBX); state.CGenPopLong(stack_size, Reg.EAX); }
public virtual void CGenPush(Env env, CGenState state) { Reg ret = CGenValue(env, state); switch (type.kind) { case ExprType.Kind.CHAR: case ExprType.Kind.UCHAR: case ExprType.Kind.SHORT: case ExprType.Kind.USHORT: case ExprType.Kind.LONG: case ExprType.Kind.ULONG: // Integral if (ret != Reg.EAX) { throw new InvalidProgramException("Integral values should be returned to %eax"); } state.CGenPushLong(Reg.EAX); break; case ExprType.Kind.FLOAT: // Float if (ret != Reg.ST0) { throw new InvalidProgramException("Floats should be returned to %st(0)"); } state.CGenExpandStackBy4Bytes(); state.FSTS(0, Reg.ESP); break; case ExprType.Kind.DOUBLE: // Double if (ret != Reg.ST0) { throw new InvalidProgramException("Doubles should be returned to %st(0)"); } state.CGenExpandStackBy8Bytes(); state.FSTL(0, Reg.ESP); break; case ExprType.Kind.ARRAY: case ExprType.Kind.FUNCTION: case ExprType.Kind.POINTER: // Pointer if (ret != Reg.EAX) { throw new InvalidProgramException("Pointer values should be returned to %eax"); } state.CGenPushLong(Reg.EAX); break; case ExprType.Kind.INCOMPLETE_ARRAY: case ExprType.Kind.VOID: throw new InvalidProgramException(type.kind.ToString() + " can't be pushed onto the stack"); case ExprType.Kind.STRUCT_OR_UNION: throw new NotImplementedException(); } }
public override Reg CGenValue(Env env, CGenState state) { // 1. %eax = &lhs lvalue.CGenAddress(env, state); // 2. push %eax Int32 pos = state.CGenPushLong(Reg.EAX); Reg ret = rvalue.CGenValue(env, state); switch (lvalue.type.kind) { case ExprType.Kind.CHAR: case ExprType.Kind.UCHAR: // pop %ebx // now %ebx = %lhs state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVB(Reg.AL, 0, Reg.EBX); return Reg.EAX; case ExprType.Kind.SHORT: case ExprType.Kind.USHORT: // pop %ebx // now %ebx = %lhs state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVW(Reg.AX, 0, Reg.EBX); return Reg.EAX; case ExprType.Kind.LONG: case ExprType.Kind.ULONG: case ExprType.Kind.POINTER: // pop %ebx // now %ebx = &lhs state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVL(Reg.EAX, 0, Reg.EBX); return Reg.EAX; case ExprType.Kind.FLOAT: // pop %ebx // now %ebx = &lhs state.CGenPopLong(pos, Reg.EBX); // *%ebx = %st(0) state.FSTS(0, Reg.EBX); return Reg.ST0; case ExprType.Kind.DOUBLE: // pop %ebx // now %ebx = &lhs state.CGenPopLong(pos, Reg.EBX); // *%ebx = %st(0) state.FSTL(0, Reg.EBX); return Reg.ST0; case ExprType.Kind.STRUCT_OR_UNION: // pop %edi // now %edi = &lhs state.CGenPopLong(pos, Reg.EDI); // %esi = &rhs state.MOVL(Reg.EAX, Reg.ESI); // %ecx = nbytes state.MOVL(lvalue.type.SizeOf, Reg.ECX); state.CGenMemCpy(); // %eax = &lhs state.MOVL(Reg.EDI, Reg.EAX); return Reg.EAX; case ExprType.Kind.FUNCTION: case ExprType.Kind.VOID: case ExprType.Kind.ARRAY: case ExprType.Kind.INCOMPLETE_ARRAY: default: throw new InvalidProgramException("cannot assign to a " + type.kind.ToString()); } }
public override Reg CGenValue(Env env, CGenState state) { // 1. Get the address of expr. // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // expr.CGenAddress(env, state); // 2. Push address. // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // Int32 stack_size = state.CGenPushLong(Reg.EAX); // 3. Get current value of expr. // // 1) If expr is an integral or pointer: // // regs: // %eax = expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // // // 2) If expr is a float: // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // // float stack: // +-------+ // | expr | <- %st(0) // +-------+ // Reg ret = expr.CGenValue(env, state); switch (ret) { case Reg.EAX: // expr is an integral or pointer. // 4. Pop address to %ecx. // // regs: // %eax = expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.CGenPopLong(stack_size, Reg.ECX); // 5. Cache current value of expr in %ebx. // // regs: // %eax = expr // %ebx = expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.MOVL(Reg.EAX, Reg.EBX); // 6. Calculate the new value in %ebx or %eax and save. // Set %eax to be the return value. // // regs: // %eax = expr or (expr +- 1) // %ebx = (expr +- 1) or expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // switch (expr.type.kind) { case ExprType.Kind.CHAR: case ExprType.Kind.UCHAR: CalcAndSaveByte(state); return Reg.EAX; case ExprType.Kind.SHORT: case ExprType.Kind.USHORT: CalcAndSaveWord(state); return Reg.EAX; case ExprType.Kind.LONG: case ExprType.Kind.ULONG: CalcAndSaveByte(state); return Reg.EAX; case ExprType.Kind.POINTER: CalcAndSavePtr(state); return Reg.EAX; default: throw new InvalidProgramException(); } case Reg.ST0: // expr is a float. // 4. Pop address to %ecx. // // regs: // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.CGenPopLong(stack_size, Reg.ECX); // 5. Load 1.0 to FPU stack. // // regs: // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // // float stack: // +-------+ // | expr | <- %st(1) // +-------+ // | 1.0 | <- %st(0) // +-------+ // state.FLD1(); // 6. Calculate the new value and save back. // Set %st(0) to be the new or original value. // // regs: // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // // float stack: // +---------------------+ // | expr or (epxr +- 1) | <- %st(0) // +---------------------+ // switch (expr.type.kind) { case ExprType.Kind.FLOAT: CalcAndSaveFloat(state); return Reg.ST0; case ExprType.Kind.DOUBLE: CalcAndSaveDouble(state); return Reg.ST0; default: throw new InvalidProgramException(); } default: throw new InvalidProgramException(); } }
// %eax = left, %ebx = right, stack unchanged private void CGenPrepareIntegralOperands(CGenState state) { // 1. Load Left to EAX. // // regs: // %eax = Left // // stack: // +-----+ // | ... | <- %esp // +-----+ // if (this.Left.CGenValue(state) != Reg.EAX) { throw new InvalidOperationException(); } // 2. Push Left to stack. // // regs: // %eax = Left // // stack: // +-----+ // | ... | // +-----+ // | Left | <- %esp has decreased by 4 // +-----+ // Int32 stack_size = state.CGenPushLong(Reg.EAX); // 3. Load Right to EAX. // // regs: // %eax = Right // // stack: // +-----+ // | ... | // +-----+ // | Left | <- %esp // +-----+ // if (this.Right.CGenValue(state) != Reg.EAX) { throw new InvalidOperationException(); } // 4. Move Right into EBX. Pop Left from stack, into EAX. // // regs: // %eax = Left // %ebx = Right // // stack: // +-----+ // | ... | <- %esp has moved back. // +-----+ // state.MOVL(Reg.EAX, Reg.EBX); state.CGenPopLong(stack_size, Reg.EAX); }
public override Reg CGenValue(CGenState state) { // 1. %eax = &left this.Left.CGenAddress(state); // 2. push %eax Int32 pos = state.CGenPushLong(Reg.EAX); Reg ret = this.Right.CGenValue(state); switch (this.Left.Type.Kind) { case ExprTypeKind.CHAR: case ExprTypeKind.UCHAR: // pop %ebx // now %ebx = %Left state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVB(Reg.AL, 0, Reg.EBX); return(Reg.EAX); case ExprTypeKind.SHORT: case ExprTypeKind.USHORT: // pop %ebx // now %ebx = %Left state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVW(Reg.AX, 0, Reg.EBX); return(Reg.EAX); case ExprTypeKind.LONG: case ExprTypeKind.ULONG: case ExprTypeKind.POINTER: // pop %ebx // now %ebx = &Left state.CGenPopLong(pos, Reg.EBX); // *%ebx = %al state.MOVL(Reg.EAX, 0, Reg.EBX); return(Reg.EAX); case ExprTypeKind.FLOAT: // pop %ebx // now %ebx = &Left state.CGenPopLong(pos, Reg.EBX); // *%ebx = %st(0) state.FSTS(0, Reg.EBX); return(Reg.ST0); case ExprTypeKind.DOUBLE: // pop %ebx // now %ebx = &Left state.CGenPopLong(pos, Reg.EBX); // *%ebx = %st(0) state.FSTL(0, Reg.EBX); return(Reg.ST0); case ExprTypeKind.STRUCT_OR_UNION: // pop %edi // now %edi = &Left state.CGenPopLong(pos, Reg.EDI); // %esi = &Right state.MOVL(Reg.EAX, Reg.ESI); // %ecx = nbytes state.MOVL(this.Left.Type.SizeOf, Reg.ECX); state.CGenMemCpy(); // %eax = &Left state.MOVL(Reg.EDI, Reg.EAX); return(Reg.EAX); case ExprTypeKind.FUNCTION: case ExprTypeKind.VOID: case ExprTypeKind.ARRAY: case ExprTypeKind.INCOMPLETE_ARRAY: default: throw new InvalidProgramException("cannot assign to a " + this.Type.Kind); } }
public override sealed Reg CGenValue(CGenState state) { // 1. Get the address of expr. // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // this.Expr.CGenAddress(state); // 2. Push address. // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // Int32 stack_size = state.CGenPushLong(Reg.EAX); // 3. Get current Value of expr. // // 1) If expr is an integral or pointer: // // regs: // %eax = expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // // // 2) If expr is a float: // // regs: // %eax = &expr // // stack: // +-------+ // | ..... | // +-------+ // | &expr | <- %esp // +-------+ // // float stack: // +-------+ // | expr | <- %st(0) // +-------+ // Reg ret = this.Expr.CGenValue(state); switch (ret) { case Reg.EAX: // expr is an integral or pointer. // 4. Pop address to %ecx. // // regs: // %eax = expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.CGenPopLong(stack_size, Reg.ECX); // 5. Cache current Value of Expr in %ebx. // // regs: // %eax = expr // %ebx = expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.MOVL(Reg.EAX, Reg.EBX); // 6. Calculate the new value in %ebx or %eax and save. // Set %eax to be the return Value. // // regs: // %eax = expr or (expr +- 1) // %ebx = (expr +- 1) or expr // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // switch (this.Expr.Type.Kind) { case ExprTypeKind.CHAR: case ExprTypeKind.UCHAR: CalcAndSaveByte(state); return(Reg.EAX); case ExprTypeKind.SHORT: case ExprTypeKind.USHORT: CalcAndSaveWord(state); return(Reg.EAX); case ExprTypeKind.LONG: case ExprTypeKind.ULONG: CalcAndSaveByte(state); return(Reg.EAX); case ExprTypeKind.POINTER: CalcAndSavePtr(state); return(Reg.EAX); default: throw new InvalidProgramException(); } case Reg.ST0: // Expr is a float. // 4. Pop address to %ecx. // // regs: // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // state.CGenPopLong(stack_size, Reg.ECX); // 5. Load 1.0 to FPU stack. // // regs: // %ecx = &expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // // float stack: // +-------+ // | expr | <- %st(1) // +-------+ // | 1.0 | <- %st(0) // +-------+ // state.FLD1(); // 6. Calculate the new value and save back. // Set %st(0) to be the new or original Value. // // regs: // %ecx = &Expr // // stack: // +-------+ // | ..... | <- %esp // +-------+ // // float stack: // +---------------------+ // | expr or (epxr +- 1) | <- %st(0) // +---------------------+ // switch (this.Expr.Type.Kind) { case ExprTypeKind.FLOAT: CalcAndSaveFloat(state); return(Reg.ST0); case ExprTypeKind.DOUBLE: CalcAndSaveDouble(state); return(Reg.ST0); default: throw new InvalidProgramException(); } default: throw new InvalidProgramException(); } }