diff --git a/ChangeLog b/ChangeLog index e7e6312..54c406f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Wed May 6 15:50:22 2009 Minero Aoki + + * net/loveruby/cflat/asm/Type.java: types should not know signed + or not. + + * net/loveruby/cflat/ir/Op.java: have signed/unsigned information. + + * net/loveruby/cflat/compiler/IRGenerator.java: use new op and + type. + + * net/loveruby/cflat/compiler/CodeGenerator.java: ditto. + + * net/loveruby/cflat/compiler/TypeChecker.java (FuncallNode): + should check optional argument types. + + * net/loveruby/cflat/compiler/CodeGenerator.java: now use simple + mov to load values from memory (and cast it later). + + * net/loveruby/cflat/type/TypeTable.java: provide stack value + type. + Wed May 6 14:54:27 2009 Minero Aoki * net/loveruby/cflat/compiler/IRGenerator.java: isStatement() did diff --git a/net/loveruby/cflat/asm/Type.java b/net/loveruby/cflat/asm/Type.java index c0085b2..67a90ed 100644 --- a/net/loveruby/cflat/asm/Type.java +++ b/net/loveruby/cflat/asm/Type.java @@ -1,71 +1,32 @@ package net.loveruby.cflat.asm; public enum Type { - S_INT8, - U_INT8, - S_INT16, - U_INT16, - S_INT32, - U_INT32, - S_INT64, - U_INT64; + INT8, INT16, INT32, INT64; - static public Type get(boolean isSigned, long size) { - if (isSigned) { - switch ((int)size) { - case 1: - return S_INT8; - case 2: - return S_INT16; - case 4: - return S_INT32; - case 8: - return S_INT64; - default: - throw new Error("unsupported asm type size: " + size); - } - } - else { - switch ((int)size) { - case 1: - return U_INT8; - case 2: - return U_INT16; - case 4: - return U_INT32; - case 8: - return U_INT64; - default: - throw new Error("unsupported asm type size: " + size); - } - } - } - - public boolean isSigned() { - switch (this) { - case S_INT8: - case S_INT16: - case S_INT32: - case S_INT64: - return true; + static public Type get(long size) { + switch ((int)size) { + case 1: + return INT8; + case 2: + return INT16; + case 4: + return INT32; + case 8: + return INT64; default: - return false; + throw new Error("unsupported asm type size: " + size); } } public int size() { switch (this) { - case S_INT8: - case U_INT8: + case INT8: return 1; - case S_INT16: - case U_INT16: + case INT16: return 2; - case S_INT32: - case U_INT32: + case INT32: return 4; - case S_INT64: - case U_INT64: + case INT64: return 8; default: throw new Error("must not happen"); diff --git a/net/loveruby/cflat/compiler/CodeGenerator.java b/net/loveruby/cflat/compiler/CodeGenerator.java index ab4f0a7..0340d44 100644 --- a/net/loveruby/cflat/compiler/CodeGenerator.java +++ b/net/loveruby/cflat/compiler/CodeGenerator.java @@ -851,10 +851,13 @@ public class CodeGenerator implements IRVisitor, ELFConstants { // #@@range/doesSpillRegister{ protected boolean doesSpillRegister(Op op) { switch (op) { - case DIV: - case MOD: - case LSHIFT: - case RSHIFT: + case S_DIV: + case U_DIV: + case S_MOD: + case U_MOD: + case BIT_LSHIFT: + case BIT_RSHIFT: + case ARITH_RSHIFT: return true; default: return false; @@ -877,17 +880,19 @@ public class CodeGenerator implements IRVisitor, ELFConstants { case MUL: as.imul(t, right, left); break; - case DIV: - case MOD: - if (t.isSigned()) { - as.cltd(); - as.idiv(t, reg("cx", t)); + case S_DIV: + case S_MOD: + as.cltd(); + as.idiv(t, reg("cx", t)); + if (op == Op.S_MOD) { + as.mov(reg("dx"), left); } - else { - as.mov(imm(0), reg("dx")); - as.div(t, reg("cx", t)); - } - if (op == Op.MOD) { + break; + case U_DIV: + case U_MOD: + as.mov(imm(0), reg("dx")); + as.div(t, reg("cx", t)); + if (op == Op.U_MOD) { as.mov(reg("dx"), left); } break; @@ -902,45 +907,33 @@ public class CodeGenerator implements IRVisitor, ELFConstants { case BIT_XOR: as.xor(t, right, left); break; - case RSHIFT: - if (t.isSigned()) { - as.sar(t, cl(), left); - } - else { - as.shr(t, cl(), left); - } - break; - case LSHIFT: + case BIT_LSHIFT: as.sal(t, cl(), left); break; + case BIT_RSHIFT: + as.shr(t, cl(), left); + break; + case ARITH_RSHIFT: + as.sar(t, cl(), left); + break; // #@@} // #@@range/compileBinaryOp_cmpops{ default: // Comparison operators as.cmp(t, right, reg("ax", t)); - if (t.isSigned()) { - switch (op) { - case EQ: as.sete (al()); break; - case NEQ: as.setne(al()); break; - case GT: as.setg (al()); break; - case GTEQ: as.setge(al()); break; - case LT: as.setl (al()); break; - case LTEQ: as.setle(al()); break; - default: - throw new Error("unknown binary operator: " + op); - } - } - else { - switch (op) { - case EQ: as.sete (al()); break; - case NEQ: as.setne(al()); break; - case GT: as.seta (al()); break; - case GTEQ: as.setae(al()); break; - case LT: as.setb (al()); break; - case LTEQ: as.setbe(al()); break; - default: - throw new Error("unknown binary operator: " + op); - } + switch (op) { + case EQ: as.sete (al()); break; + case NEQ: as.setne(al()); break; + case S_GT: as.setg (al()); break; + case S_GTEQ: as.setge(al()); break; + case S_LT: as.setl (al()); break; + case S_LTEQ: as.setle(al()); break; + case U_GT: as.seta (al()); break; + case U_GTEQ: as.setae(al()); break; + case U_LT: as.setb (al()); break; + case U_LTEQ: as.setbe(al()); break; + default: + throw new Error("unknown binary operator: " + op); } as.movzb(t, al(), reg("ax", t)); } @@ -964,14 +957,18 @@ public class CodeGenerator implements IRVisitor, ELFConstants { as.sete(al()); as.movzbl(al(), reg("ax")); break; - case CAST: - Type src = node.expr().type(); - Type dest = node.type(); - if (src.isSigned()) { + case S_CAST: + { + Type src = node.expr().type(); + Type dest = node.type(); as.movsx(src, dest, reg("ax").forType(src), reg("ax").forType(dest)); } - else { + break; + case U_CAST: + { + Type src = node.expr().type(); + Type dest = node.type(); as.movzx(src, dest, reg("ax").forType(src), reg("ax").forType(dest)); } @@ -1172,28 +1169,7 @@ public class CodeGenerator implements IRVisitor, ELFConstants { // #@@range/load{ protected void load(Type type, MemoryReference mem, Register reg) { - switch (type.size()) { - case 1: - if (type.isSigned()) { // signed char - as.movsbl(mem, reg); - } else { // unsigned char - as.movzbl(mem, reg); - } - break; - case 2: - if (type.isSigned()) { // signed short - as.movswl(mem, reg); - } else { // unsigned short - as.movzwl(mem, reg); - } - break; - case 4: - case 8: // int, long, long_long - as.mov(type, mem, reg.forType(type)); - break; - default: - throw new Error("unloadable value size: " + type.size()); - } + as.mov(type, mem, reg.forType(type)); } // #@@} diff --git a/net/loveruby/cflat/compiler/IRGenerator.java b/net/loveruby/cflat/compiler/IRGenerator.java index 0a05cce..a9ee7a8 100644 --- a/net/loveruby/cflat/compiler/IRGenerator.java +++ b/net/loveruby/cflat/compiler/IRGenerator.java @@ -471,7 +471,7 @@ class IRGenerator implements ASTVisitor { Expr rhs = transformExpr(node.rhs()); Expr lhs = transformLHS(node.lhs()); return transformOpAssign(lhs, - Op.internBinary(node.operator()), + Op.internBinary(node.operator(), node.rhs().type().isSigned()), rhs, node.lhs().type()); } @@ -572,7 +572,7 @@ class IRGenerator implements ASTVisitor { } } return new Bin(asmType(node.type()), - Op.internBinary(node.operator()), + Op.internBinary(node.operator(), node.type().isSigned()), left, right); } // #@@} @@ -651,7 +651,8 @@ class IRGenerator implements ASTVisitor { public Expr visit(CastNode node) { if (node.isEffectiveCast()) { return new Uni(asmType(node.type()), - Op.CAST, transformExpr(node.expr())); + node.expr().type().isSigned() ? Op.S_CAST : Op.U_CAST, + transformExpr(node.expr())); } else { return transformExpr(node.expr()); @@ -726,36 +727,26 @@ class IRGenerator implements ASTVisitor { private net.loveruby.cflat.asm.Type asmType(Type t) { if (t.isVoid()) return signedInt(); - return net.loveruby.cflat.asm.Type.get( - t.isInteger() && t.isSigned(), - t.size()); + return net.loveruby.cflat.asm.Type.get(t.size()); } private net.loveruby.cflat.asm.Type varType(Type t) { if (t.size() == 0 || t.size() > typeTable.maxIntSize()) { return null; } - return net.loveruby.cflat.asm.Type.get( - t.isInteger() && t.isSigned(), - t.size()); + return net.loveruby.cflat.asm.Type.get(t.size()); } private net.loveruby.cflat.asm.Type signedInt() { - return net.loveruby.cflat.asm.Type.get( - true, - (int)typeTable.intSize()); + return net.loveruby.cflat.asm.Type.get((int)typeTable.intSize()); } private net.loveruby.cflat.asm.Type pointer() { - return net.loveruby.cflat.asm.Type.get( - false, - (int)typeTable.pointerSize()); + return net.loveruby.cflat.asm.Type.get((int)typeTable.pointerSize()); } private net.loveruby.cflat.asm.Type ptrDiffType() { - return net.loveruby.cflat.asm.Type.get( - true, - (int)typeTable.pointerSize()); + return net.loveruby.cflat.asm.Type.get((int)typeTable.pointerSize()); } private void error(Node n, String msg) { diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index 67d77ba..158c13e 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -458,20 +458,32 @@ class TypeChecker extends Visitor { error(node, "wrong number of argments: " + node.numArgs()); return null; } - // Check type of only mandatory parameters. Iterator args = node.arguments().iterator(); List newArgs = new ArrayList(); + // mandatory args for (Type param : type.paramTypes()) { ExprNode arg = args.next(); newArgs.add(checkRHS(arg) ? implicitCast(param, arg) : arg); } + // optional args while (args.hasNext()) { - newArgs.add(args.next()); + ExprNode arg = args.next(); + newArgs.add(checkRHS(arg) ? castOptionalArg(arg) : arg); } node.replaceArgs(newArgs); return null; } + private ExprNode castOptionalArg(ExprNode arg) { + if (! arg.type().isInteger()) { + return arg; + } + Type t = arg.type().isSigned() + ? typeTable.signedStackType() + : typeTable.unsignedStackType(); + return arg.type().size() < t.size() ? implicitCast(t, arg) : arg; + } + public Void visit(ArefNode node) { super.visit(node); mustBeInteger(node.index(), "[]"); diff --git a/net/loveruby/cflat/ir/IR.java b/net/loveruby/cflat/ir/IR.java index e78987d..fde932d 100644 --- a/net/loveruby/cflat/ir/IR.java +++ b/net/loveruby/cflat/ir/IR.java @@ -80,7 +80,7 @@ public class IR { public net.loveruby.cflat.asm.Type naturalType() { // platform dependent!!! - return Type.S_INT32; + return Type.INT32; } public void dump() { diff --git a/net/loveruby/cflat/ir/Op.java b/net/loveruby/cflat/ir/Op.java index 7a7d2db..2acc8bf 100644 --- a/net/loveruby/cflat/ir/Op.java +++ b/net/loveruby/cflat/ir/Op.java @@ -4,28 +4,36 @@ public enum Op { ADD, SUB, MUL, - DIV, - MOD, + S_DIV, + U_DIV, + S_MOD, + U_MOD, BIT_AND, BIT_OR, BIT_XOR, - LSHIFT, - RSHIFT, + BIT_LSHIFT, + BIT_RSHIFT, + ARITH_RSHIFT, EQ, NEQ, - GT, - GTEQ, - LT, - LTEQ, + S_GT, + S_GTEQ, + S_LT, + S_LTEQ, + U_GT, + U_GTEQ, + U_LT, + U_LTEQ, UMINUS, BIT_NOT, NOT, - CAST; + S_CAST, + U_CAST; - static public Op internBinary(String op) { + static public Op internBinary(String op, boolean isSigned) { if (op.equals("+")) { return Op.ADD; } @@ -36,10 +44,10 @@ public enum Op { return Op.MUL; } else if (op.equals("/")) { - return Op.DIV; + return isSigned ? Op.S_DIV : Op.U_DIV; } else if (op.equals("%")) { - return Op.MOD; + return isSigned ? Op.S_MOD : Op.U_MOD; } else if (op.equals("&")) { return Op.BIT_AND; @@ -51,10 +59,10 @@ public enum Op { return Op.BIT_XOR; } else if (op.equals("<<")) { - return Op.LSHIFT; + return Op.BIT_LSHIFT; } else if (op.equals(">>")) { - return Op.RSHIFT; + return isSigned ? Op.ARITH_RSHIFT : Op.BIT_RSHIFT; } else if (op.equals("==")) { return Op.EQ; @@ -63,16 +71,16 @@ public enum Op { return Op.NEQ; } else if (op.equals("<")) { - return Op.LT; + return isSigned ? Op.S_LT : Op.U_LT; } else if (op.equals("<=")) { - return Op.LTEQ; + return isSigned ? Op.S_LTEQ : Op.U_LTEQ; } else if (op.equals(">")) { - return Op.GT; + return isSigned ? Op.S_GT : Op.U_GT; } else if (op.equals(">=")) { - return Op.GTEQ; + return isSigned ? Op.S_GTEQ : Op.U_GTEQ; } else { throw new Error("unknown binary op: " + op); diff --git a/net/loveruby/cflat/type/TypeTable.java b/net/loveruby/cflat/type/TypeTable.java index cacccea..fb85b28 100644 --- a/net/loveruby/cflat/type/TypeTable.java +++ b/net/loveruby/cflat/type/TypeTable.java @@ -118,6 +118,14 @@ public class TypeTable { throw new Error("must not happen: integer.size != pointer.size"); } + public Type signedStackType() { + return signedLong(); + } + + public Type unsignedStackType() { + return unsignedLong(); + } + public Collection types() { return table.values(); }