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);
        }
Beispiel #2
0
        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();
            }
        }
Beispiel #3
0
        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();
            }
        }
Beispiel #5
0
        // %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);
        }
Beispiel #6
0
        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);
            }
        }
Beispiel #7
0
        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();
            }
        }