changeset 107:189c049cbfcc new_gen

Cleanup of codegen, better support for operators a few bugfixes
author Anders Halager <halager@gmail.com>
date Sun, 25 May 2008 14:40:14 +0200
parents 09b4d74cb3f5
children 5e383b3755d6
files ast/Decl.d ast/Exp.d basic/Messages.d gen/CodeGen.d sema/DType.d sema/Operation.d sema/Scope.d sema/ScopeBuilder.d sema/TypeCheck.d tests/code/sarray_1.d tests/code/sarray_2.d tests/sema/deref_1.d tests/sema/deref_2.d
diffstat 13 files changed, 550 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Thu May 08 10:54:29 2008 +0200
+++ b/ast/Decl.d	Sun May 25 14:40:14 2008 +0200
@@ -130,9 +130,9 @@
             }
         }
 
-        foreach ( funcArg ; funcArgs )
+        foreach (funcArg; funcArgs)
             funcArg.simplify();
-        foreach ( stmt ; statements )
+        foreach (stmt; statements)
             stmt.simplify();
     }
 
--- a/ast/Exp.d	Thu May 08 10:54:29 2008 +0200
+++ b/ast/Exp.d	Sun May 25 14:40:14 2008 +0200
@@ -27,7 +27,7 @@
     CastExp,
 }
 
-class Exp
+abstract class Exp
 {
     this(ExpType expType, SLoc loc)
     {
@@ -36,7 +36,7 @@
     }
 
     /// Get the type of the expression
-    DType type() { return null; }
+    DType type();
 
     /// Indicates which type the expression is - to avoid a lot of casts
     ExpType expType;
@@ -59,10 +59,8 @@
     /// Get the full extents of the expression
     SourceRange sourceRange() { return SourceRange(loc, loc + 1); }
 
-    Exp simplify()
-    {
-        return this;
-    }
+    /// Do some simplifications
+    Exp simplify() { return this; }
 }
 
 class CallExp : Exp
@@ -284,7 +282,7 @@
     }
 
     override DType type() 
-    { 
+    {
         return exp.type().asPointer.pointerOf; 
     }
 
--- a/basic/Messages.d	Thu May 08 10:54:29 2008 +0200
+++ b/basic/Messages.d	Sun May 25 14:40:14 2008 +0200
@@ -67,6 +67,7 @@
         InvalidDeclType     : E(Err, "Invalid declaration type"),
         InvalidType         : E(Err, "Invalid type"),
         ExpectedIdAfterPackage : E(Err, "Identifier expected following package"),
+
         CannotFindModule    : E(Err, "Cannot find module '%0'")
     ];
 }
--- a/gen/CodeGen.d	Thu May 08 10:54:29 2008 +0200
+++ b/gen/CodeGen.d	Sun May 25 14:40:14 2008 +0200
@@ -4,12 +4,12 @@
        Int = tango.text.convert.Integer;
 import tango.core.Array : find, partition;
 
-import LLVM = llvm.llvm;
+import llvm.llvm;
 
-import ast.Module,
-       ast.Decl,
+import ast.Decl,
        ast.Stmt,
-       ast.Exp;
+       ast.Exp,
+       ast.Module : DModule = Module;
 
 import misc.Error,
        basic.SmallArray;
@@ -19,78 +19,75 @@
 import sema.Scope,
        sema.Visitor;
 
-alias LLVM.Value Value;
-alias LLVM.Type Type;
-alias LLVM.Function Function;
-alias LLVM.PointerType PointerType;
-alias LLVM.FunctionType FunctionType;
-alias LLVM.IntPredicate IntPredicate;
-alias LLVM.ParamAttr ParamAttr;
-alias LLVM.ConstantInt ConstantInt;
-alias LLVM.GlobalVariable GlobalVariable;
-alias LLVM.IntegerType IntegerType;
-alias LLVM.BasicBlock BasicBlock;
-alias LLVM.StructType StructType;
-alias LLVM.ArrayType ArrayType;
+/**
+  Wrapper for Values representing rvalues (things you can only read from)
+ **/
+private struct RValue
+{
+    /**
+      Returns true if this is a simple value, like an int or a pointer.
+      This is basicly anything except a struct, which will contain a Value that
+      is a pointer to the struct.
+     **/
+    bool isSimple() { return simple; }
+    /// Opposite of isSimple
+    bool isAggregate() { return !simple; }
 
-private char[] genBuildCmp(char[] p)
+    Value value;
+    private bool simple = true;
+}
+
+/**
+  Wrapper for Values representing lvalues (things you can write to)
+ **/
+private struct LValue
 {
-    return `
-        Value build`~p~`(Value l, Value r, char[] n)
-        {
-            return b.buildICmp(IntPredicate.`~p~`, l, r, n);
-        }`;
+    Value getAddress() { return value; }
+    private Value value;
 }
 
 class CodeGen
 {
-private:
-    mixin(genBuildCmp("EQ"));
-    mixin(genBuildCmp("NE"));
-    mixin(genBuildCmp("SLT"));
-    mixin(genBuildCmp("SLE"));
-    mixin(genBuildCmp("SGT"));
-    mixin(genBuildCmp("SGE"));
-
 public:
     this()
     {
-        alias BinaryExp.Operator op;
-        b = new LLVM.Builder;
+        b = new Builder;
+        ZeroIndex = ConstantInt.GetU(Type.Int32, 0);
         
-        opToLLVM = [
-            op.Add      : &b.buildAdd,
-            op.Sub      : &b.buildSub,
-            op.Mul      : &b.buildMul,
-            op.Div      : &b.buildSDiv,
-            op.Eq       : &buildEQ,
-            op.Ne       : &buildNE,
-            op.Lt       : &buildSLT,
-            op.Le       : &buildSLE,
-            op.Gt       : &buildSGT,
-            op.Ge       : &buildSGE
-        ];
         table = new SimpleSymbolTable();
 
         createBasicTypes();
     }
 
-    ~this()
-    {
-//        b.dispose();
-    }
+    /**
+       Generate a new module.
+     **/
+    /*
+        Find all function decls and add the functions to the llvm module, so
+        they can be referenced.
 
-    void gen(Module mod, uint handle, bool optimize, bool inline)
+        Make sure all var-decls are located before functions, so we wont get
+        problems when referencing the global vars.
+
+        Generate the actual llvm code needed for all decls
+
+        Optimize if requested
+
+        Write to filehandle (can be a file or stdout)
+     */
+    void gen(DModule mod, uint handle, bool optimize, bool inline)
     {
         this.mod = mod;
         // create module
-        m = new LLVM.Module("main_module");
+        m = new .llvm.llvm.Module("main_module");
         scope(exit) m.dispose();
 
         table.enterScope;
 
         BytePtr = PointerType.Get(Type.Int8);
-        auto temp = FunctionType.Get(Type.Void, [BytePtr, BytePtr, Type.Int32, Type.Int32]);
+        auto temp = FunctionType.Get(
+                Type.Void,
+                [BytePtr, BytePtr, Type.Int32, Type.Int32]);
         llvm_memcpy = m.addFunction(temp, "llvm.memcpy.i32");
 
         auto registerFunc =
@@ -100,12 +97,12 @@
                 foreach (i, p; fd.funcArgs)
                 {
                     DType t = p.env.find(p.identifier).type;
-                    if(auto st = t.asStruct)
+                    if (auto st = t.asStruct())
                     {
                         Type pointer = PointerType.Get(llvm(st));
                         param_types ~= pointer;
                     }
-                    else if(auto ar = t.asArray)
+                    else if (auto ar = t.asArray())
                     {
                         Type pointer = PointerType.Get(llvm(ar));
                         param_types ~= pointer;
@@ -127,15 +124,15 @@
                         llfunc.addParamAttr(0, ParamAttr.StructRet);
 
                     DType t = p.env.find(p.identifier).type;
-                    if(auto st = t.asStruct)
+                    if (auto st = t.asStruct)
                     {
-                        if(i == 0 && fd.sret)
+                        if (i == 0 && fd.sret)
                             continue;
-                        llfunc.addParamAttr(i,ParamAttr.ByVal);
+                        llfunc.addParamAttr(i, ParamAttr.ByVal);
                     }
-                    else if(auto ar = t.asArray)
+                    else if (auto ar = t.asArray)
                     {
-                        llfunc.addParamAttr(i,ParamAttr.ByVal);
+                        llfunc.addParamAttr(i, ParamAttr.ByVal);
                     }
                 }
             };
@@ -160,6 +157,10 @@
         m.writeBitcodeToFileHandle(handle);
     }
 
+private:
+    /**
+      Generate a single top-level Decl
+     **/
     void genRootDecl(Decl decl)
     {
         switch(decl.declType)
@@ -186,7 +187,7 @@
                 {
                     llfunc.getParam(i).name = v.identifier.get;
                     auto name = v.identifier.get;
-                    if(!cast(PointerType)llfunc.getParam(i).type)
+                    if (!cast(PointerType)llfunc.getParam(i).type)
                     {
                         auto AI = b.buildAlloca(llfunc.getParam(i).type, name);
  //                       Value va = b.buildLoad(val, name);
@@ -231,6 +232,9 @@
         }
     }
 
+    /**
+      Generate a single local Decl
+     **/
     void genDecl(Decl decl)
     {
         switch(decl.declType)
@@ -242,13 +246,18 @@
                 auto AI = b.buildAlloca(llvm(sym.type), name);
                 table[name] = AI;
                 if (varDecl.init)
-                    buildAssign(varDecl.identifier, varDecl.init);
+                {
+                    LValue dst = genLValue(varDecl.identifier);
+                    RValue src = genExpression(varDecl.init);
+                    storeThroughLValue(dst, src, sym.type);
+                }
                 break;
         
             default:
         }
     }
 
+    // Remove - do it right (basic/Messages.d)
     struct PE
     {
         static char[] NoImplicitConversion =
@@ -257,6 +266,14 @@
             "Only void functions can return without an expression";
     }
 
+    /**
+      Takes two iX and overwrite the smaller one, with a sign-extended version
+      so both values can be operated on without worrying about the exact types.
+
+      Used when adding a int and a long or similar.
+
+      Currently unused
+     **/
     void sextSmallerToLarger(ref Value left, ref Value right)
     {
         if (left.type != right.type)
@@ -276,86 +293,153 @@
         }
     }
 
-    Value genExpression(Exp exp)
+    /**
+      Generate a single expression.
+
+      This is the most general way of generating expressions and therefore
+      returns an RValue.
+     **/
+    RValue genExpression(Exp exp)
     {
         switch(exp.expType)
         {
             case ExpType.Binary:
-                auto binaryExp = cast(BinaryExp)exp;
-
-                auto left = genExpression(binaryExp.left);
-                auto right = genExpression(binaryExp.right);
-
-//                sextSmallerToLarger(left, right);
-
-                OpBuilder op = opToLLVM[binaryExp.op];
-
-                return op(left, right, ".");
-
+                return RValue(genBinExp(cast(BinaryExp)exp));
             case ExpType.IntegerLit:
                 auto integetLit = cast(IntegerLit)exp;
-                auto val = integetLit.get;
-                return ConstantInt.GetS(Type.Int32, Integer.parse(val));
+                auto val = Integer.parse(integetLit.get);
+                return RValue(ConstantInt.GetS(Type.Int32, val));
             case ExpType.Negate:
                 auto negateExp = cast(NegateExp)exp;
                 auto target = genExpression(negateExp.exp);
-                return b.buildNeg(target, "neg");
+                return RValue(b.buildNeg(target.value, "neg"));
             case ExpType.Deref:
                 auto derefExp = cast(DerefExp)exp;
                 auto target = genExpression(derefExp.exp);
-                return b.buildLoad(target, "deref");
+                return RValue(b.buildLoad(target.value, "deref"));
             case ExpType.AssignExp:
-                auto assignExp = cast(AssignExp)exp;
-                return buildAssign(assignExp.identifier, assignExp.exp);
+                auto AE = cast(AssignExp)exp;
+                LValue dst = genLValue(AE.identifier);
+                RValue src = genExpression(AE.exp);
+                storeThroughLValue(dst, src, AE.exp.type());
+                return src;
             case ExpType.Index:
                 auto indexExp = cast(IndexExp)exp;
-                return b.buildLoad(getPointer(exp), ".");
+                return loadLValue(genLValue(exp));
             case ExpType.CallExp:
                 auto callExp = cast(CallExp)exp;
+                // BUG: Might not be a simple identifier, a.foo(x) is also a
+                // valid call - or foo(x)(y) for that matter.
                 auto id = exp.env.find(cast(Identifier)callExp.exp);
-                Value[] args;
-                foreach (arg; callExp.args)
-                {
-                    Value v = genExpression(arg);
-                    args ~= v;
-
-                }
+                scope args = new Value[callExp.args.length];
+                foreach (i, arg; callExp.args)
+                    args[i] = genExpression(arg).value;
                 llvm(id.type);
-                // BUG: doesn't do implicit type-conversion
-                if(callExp.sret)
-                    return b.buildCall(m.getNamedFunction(id.getMangled), args, "");
-                return b.buildCall(m.getNamedFunction(id.getMangled), args, ".call");
+                auto f = m.getNamedFunction(id.getMangled);
+                DFunction f_type = cast(DFunction)id.type;
+                bool isVoid = f_type.returnType is DType.Void;
+                // BUG: doesn't do implicit type-conversion on args
+                auto r = b.buildCall(f, args, isVoid? "" : "call");
+                return RValue(r);
             case ExpType.CastExp:
                 auto castExp = cast(CastExp)exp;
-                auto value = genExpression(castExp.exp);
+                auto value = genExpression(castExp.exp).value;
 
-                if(!castExp.type.hasImplicitConversionTo(castExp.type))
+                if (!castExp.type.hasImplicitConversionTo(castExp.type))
                     assert(0, "Invalid cast");
 
                 Value v;
                 if(castExp.exp.type.byteSize <= castExp.type.byteSize)
-                    v = b.buildZExt(value, llvm(castExp.type), "cast");
+                    v = b.buildZExt(value, llvm(castExp.type), "zext");
                 else
-                    v = b.buildTrunc(value, llvm(castExp.type), "cast");
+                    v = b.buildTrunc(value, llvm(castExp.type), "trunc");
 
-                return v;
+                return RValue(v);
 
             case ExpType.Identifier:
                 auto identifier = cast(Identifier)exp;
                 auto id = exp.env.find(identifier);
-                if(id.type.isStruct || id.type.isArray)
-                    return table.find(id.get);
+                if(id.type.isStruct() || id.type.isArray())
+                    return RValue(table.find(id.get));
                 else
-                    return b.buildLoad(table.find(id.get), id.get);
+                    return RValue(b.buildLoad(table.find(id.get), id.get));
             case ExpType.MemberReference:
-                auto v = getPointer(exp);
-//                return v;
-                return b.buildLoad(v, v.name);
+                return loadLValue(genLValue(exp));
         }
         assert(0, "Reached end of switch in genExpression");
-        return null;
+        return RValue(null);
     }
 
+    /**
+      Generate a binary expression.
+
+      Currently only works for signed and unsigned integers, but is almost
+      ready for floats and should be expanded to everything else.
+     **/
+    Value genBinExp(BinaryExp e)
+    {
+        auto left = genExpression(e.left).value;
+        auto right = genExpression(e.right).value;
+        DType t_a = e.left.type;
+        DType t_b = e.right.type;
+
+        Value res;
+        // TODO: do usual type promotions on a and b
+        // TODO: support floats
+        if (t_a.isInteger() && t_b.isInteger())
+        {
+            Operation op = t_a.getOperationWith(op2op(e.op), t_b);
+            assert(op.isBuiltin(),
+                    "integers should only use builtin ops");
+            alias BuiltinOperation BO;
+            BO val = op.builtinOp();
+            // map val to buildAdd or similar
+            switch (val) {
+                case BO.Add: res = b.buildAdd(left, right, "add"); break;
+                case BO.Sub: res = b.buildSub(left, right, "sub"); break;
+                case BO.Mul: res = b.buildMul(left, right, "mul"); break;
+                case BO.SDiv: res = b.buildSDiv(left, right, "div"); break;
+                case BO.UDiv: res = b.buildUDiv(left, right, "div"); break;
+                case BO.FDiv: res = b.buildFDiv(left, right, "div"); break;
+                case BO.SRem: res = b.buildSRem(left, right, "rem"); break;
+                case BO.URem: res = b.buildURem(left, right, "rem"); break;
+                case BO.FRem: res = b.buildFRem(left, right, "rem"); break;
+                default:
+                    LLVMPred pred = predFromBI(val);
+                    IntPredicate ip = pred.intPred;
+                    RealPredicate rp = pred.realPred;
+                    assert(pred.isValid, "Not a predicate");
+                    if (pred.isReal)
+                        res = b.buildFCmp(rp, left, right, "cmp");
+                    else
+                        res = b.buildICmp(ip, left, right, "cmp");
+                    break;
+                }
+        }
+        else
+        /*
+            if left has op for right's type:
+                a_op = left.op(right)
+            if right has usable op_r:
+                b_op_r = right.op_r(left)
+            if a_op or b_op_r is set, choose the best one
+            else if op is commutative
+                if left has usable op_r
+                    a_op_r = left.op_r(right)
+                if right has usable op
+                    b_op = right.op(left)
+                choose best one from a_op_r and b_op
+            else error
+         */
+            assert(0, "Not integers?");
+
+        return res;
+    }
+
+    /**
+      Generates one statement
+     **/
+    // This should be split into specific methods - one per Stmt type?
     void genStmt(Stmt stmt)
     {
         switch(stmt.stmtType)
@@ -378,7 +462,7 @@
                     else
                         throw error(__LINE__, PE.VoidRetInNonVoidFunc);
 
-                Value v = genExpression(ret.exp);
+                RValue v = genExpression(ret.exp);
 /*                if (v.type != t)
                 {
                     IntegerType v_t = cast(IntegerType) v.type;
@@ -393,7 +477,7 @@
                     else
                         v = b.buildTrunc(v, t, ".cast");
                 }*/
-                b.buildRet(v);
+                b.buildRet(v.value);
                 break;
             case StmtType.Decl:
                 auto declStmt = cast(DeclStmt)stmt;
@@ -405,7 +489,7 @@
                 break;
             case StmtType.If:
                 auto ifStmt = cast(IfStmt)stmt;
-                Value cond = genExpression(ifStmt.cond);
+                Value cond = genExpression(ifStmt.cond).value;
                 if (cond.type !is Type.Int1)
                 {
                     Value False = ConstantInt.GetS(cond.type, 0);
@@ -448,7 +532,7 @@
 
                 b.buildBr(condBB);
                 b.positionAtEnd(condBB);
-                Value cond = genExpression(wStmt.cond);
+                Value cond = genExpression(wStmt.cond).value;
                 if (cond.type !is Type.Int1)
                 {
                     Value False = ConstantInt.GetS(cond.type, 0);
@@ -465,7 +549,7 @@
                 break;
             case StmtType.Switch:
                 auto sw = cast(SwitchStmt)stmt;
-                Value cond = genExpression(sw.cond);
+                Value cond = genExpression(sw.cond).value;
 
                 auto func_name = stmt.env.parentFunction().identifier.get;
                 Function func = m.getNamedFunction(func_name);
@@ -516,39 +600,57 @@
         }
     }
 
-    Value getPointer(Exp exp)
+    /**
+      Given the address of something, load it into an alloc.
+     **/
+    RValue loadLValue(LValue addr, char[] name = null)
+    {
+        Value val = addr.getAddress();
+        if (name is null)
+            name = val.name.length > 0? val.name : "load";
+
+        auto res = b.buildLoad(val, name);
+        return RValue(res);
+    }
+
+    /*
+       Get the address of an expression - allowing us to modify something in
+       memory or on the stack.
+     */
+    LValue genLValue(Exp exp)
     {
         switch(exp.expType)
         {
             case ExpType.Identifier:
                 auto identifier = cast(Identifier)exp;
                 auto id = exp.env.find(identifier);
-                return table.find(id.get);
+                return LValue(table.find(id.get));
             case ExpType.Deref:
-                auto derefExp = cast(DerefExp)exp;
-                auto target = getPointer(derefExp.exp);
-                return b.buildLoad(target, "deref");
+                // LValue(*x): x
+                // RValue(*x): load(x)
+                // This way *x = *x + 1 will work
+                // TODO: Get's an i32** rather than i32* because it's alloc'd
+                //        so there needs to be a load?
+                auto DE = cast(DerefExp)exp;
+                return genLValue(DE.exp);
             case ExpType.Index:
                 auto indexExp = cast(IndexExp)exp;
                 auto type = indexExp.target.type;
                 auto index = genExpression(indexExp.index);
                 Value[2] gep_indices;
-                gep_indices[0] = ConstantInt.Get(IntegerType.Int32, 0, false);
-                gep_indices[1] = index;
+                gep_indices[0] = ZeroIndex;
+                gep_indices[1] = index.value;
+                Value res;
+                auto target = genLValue(indexExp.target).getAddress();
                 if (type.isArray())
-                {
-                    auto array = getPointer(indexExp.target);
-                    return b.buildGEP(array, gep_indices[0 .. 2], "index");
-                }
+                    res = b.buildGEP(target, gep_indices[0 .. 2], "index");
                 else if (type.isPointer())
-                {
-                    auto array = genExpression(indexExp.target);
-                    return b.buildGEP(array, gep_indices[1 .. 2], "index");
-                }
+                    res = b.buildGEP(target, gep_indices[1 .. 2], "index");
                 else assert(0, "Can only index pointers and arrays");
+                return LValue(res);
             case ExpType.MemberReference:
                 auto mem = cast(MemberReference)exp;
-                switch(mem.target.expType)
+                switch (mem.target.expType)
                 {
                     case ExpType.Identifier:
                         auto identifier = cast(Identifier)mem.target;
@@ -560,15 +662,15 @@
 
                         int i = st.indexOf(child.get);
 
-                        Value[] vals;   
-                        vals ~= ConstantInt.Get(IntegerType.Int32, 0, false);
-                        vals ~= ConstantInt.Get(IntegerType.Int32, i, false);
+                        Value[2] vals;
+                        vals[0] = ZeroIndex;
+                        vals[1] = ConstantInt.GetU(IntegerType.Int32, i);
 
                         Value val = b.buildGEP(v, vals, id.get~"."~child.get);
-                        return val;
+                        return LValue(val);
 
                     case ExpType.MemberReference:
-                        auto v = getPointer(mem.target);
+                        auto addr = genLValue(mem.target).getAddress();
                         auto child = mem.child;
                         auto symChild = child.env.find(child);
                         DType t = mem.target.type;
@@ -576,69 +678,50 @@
 
                         int i = st.indexOf(child.get);
 
-                        Value[] vals;   
-                        vals ~= ConstantInt.Get(IntegerType.Int32, 0, false);
-                        vals ~= ConstantInt.Get(IntegerType.Int32, i, false);
-
-                        Value val = b.buildGEP(v, vals, "."~child.get);
-                        return val;
+                        Value[2] vals;   
+                        vals[0] = ZeroIndex;
+                        vals[1] = ConstantInt.GetU(IntegerType.Int32, i);
 
-                    default:
-                        Value val = genExpression(exp);
-                        auto AI = b.buildAlloca(val.type, ".s");
-                        return b.buildStore(val, AI);
+                        Value val = b.buildGEP(addr, vals, "."~child.get);
+                        return LValue(val);
                 }
-            default:
-                Value val = genExpression(exp);
-                auto AI = b.buildAlloca(val.type, ".s");
-                return b.buildStore(val, AI);
+                break;
         }
         assert(0, "Reached end of switch in getPointer");
-        return null;
+        return LValue(null);
     }
 
-    private Value buildAssign(Exp target, Exp exp)
+    /**
+      Store into an lvalue from a rvalue. Both are assumed to have type t.
+     **/
+    void storeThroughLValue(LValue dst, RValue src, DType t)
     {
-        Value t = getPointer(target);
-        Value v = genExpression(exp);
-
-        auto a = cast(PointerType)t.type;
+        Value to = dst.getAddress();
+        Value from = src.value;
 
-        assert(a, "Assing to type have to be of type PointerType");
-
-        Type value_type = v.type;
-        if (auto value_ptr = cast(PointerType)v.type)
-        {
-            value_type = value_ptr.elementType;
+        auto a = cast(PointerType)to.type;
+        assert(a !is null, "Can only store through pointers");
 
-            if (a.elementType is value_type && cast(StructType)value_type)
-            {
-                // bitcast "from" to i8*
-                Value from = b.buildBitCast(v, BytePtr, ".copy_from");
-                // bitcast "to" to i8*
-                Value to = b.buildBitCast(t, BytePtr, ".copy_to");
-                // call llvm.memcpy.i32( "to", "from", type_size, alignment (32 in clang) );
-                b.buildCall(llvm_memcpy, [to, from, ConstantInt.GetS(Type.Int32, 4), ConstantInt.GetS(Type.Int32, 32)], null);
-                // return "to"
-                return t;
-            }
-        }
+        if (auto st = t.asStruct())
+            genMemcpy(to, from, t);
+        else
+            b.buildStore(from, to);
+    }
 
-        if (value_type != a.elementType)
-        {
-            IntegerType v_t = cast(IntegerType) value_type;
-            IntegerType i_t = cast(IntegerType) a.elementType;
-            if (v_t is null || i_t is null)
-                throw error(__LINE__, PE.NoImplicitConversion)
-                    .arg(a.elementType.toString)
-                    .arg(v.type.toString);
-
-            if (v_t.numBits() < i_t.numBits())
-                v = b.buildSExt(v, a.elementType, ".cast");
-            else
-                v = b.buildTrunc(v, a.elementType, ".cast");
-        }
-        return b.buildStore(v, t);
+    /**
+      Copy from src into dst. The values are assumed to have the same size,
+      and the amount of bytes to copy is taken from t.
+     **/
+    void genMemcpy(Value dst, Value src, DType t)
+    {
+        Value from = b.buildBitCast(src, BytePtr, ".copy_from");
+        Value to = b.buildBitCast(dst, BytePtr, ".copy_to");
+        Value[4] args;
+        args[0] = to;
+        args[1] = from;
+        args[2] = ConstantInt.GetS(Type.Int32, t.byteSize());
+        args[3] = ConstantInt.GetS(Type.Int32, 32);
+        b.buildCall(llvm_memcpy, args[], null);
     }
 
     Error error(uint line, char[] msg)
@@ -678,10 +761,10 @@
             DType[] array;
             array.length = s.members.length;
 
-            foreach(m; s.members)
+            foreach (m; s.members)
                 array[m.index] = m.type;
 
-            foreach(m; array)
+            foreach (m; array)
                 members ~= llvm(m);
 
             Type res = StructType.Get(members.unsafe());
@@ -761,18 +844,90 @@
 private:
 
     // llvm stuff
-    Module mod;
-    LLVM.Module m;
-    LLVM.Builder b;
+    DModule mod;
+    .llvm.llvm.Module m;
+    Builder b;
     Function llvm_memcpy;
+    ConstantInt ZeroIndex;
     Type BytePtr;
     Type[DType] type_map;
 
     FuncDecl[char[]] functions;
 
     SimpleSymbolTable table;
-    alias Value delegate(Value, Value, char[]) OpBuilder;
-    static OpBuilder[BinaryExp.Operator] opToLLVM;
+}
+
+private Operator op2op(BinaryExp.Operator op)
+{
+    alias BinaryExp.Operator O;
+    Operator res;
+    switch (op) {
+        case O.Add: res = Operator.Add; break;
+        case O.Sub: res = Operator.Sub; break;
+        case O.Mul: res = Operator.Mul; break;
+        case O.Div: res = Operator.Div; break;
+
+        case O.Eq: res = Operator.Eq; break;
+        case O.Ne: res = Operator.Ne; break;
+        case O.Lt: res = Operator.Lt; break;
+        case O.Le: res = Operator.Le; break;
+        case O.Gt: res = Operator.Gt; break;
+        case O.Ge: res = Operator.Ge; break;
+    }
+    return res;
+}
+
+private struct LLVMPred
+{
+    bool isValid = false;
+    bool isReal;
+    union {
+        IntPredicate intPred;
+        RealPredicate realPred;
+    }
+
+    static LLVMPred Int(IntPredicate p)
+    {
+        LLVMPred res;
+        res.isValid = true;
+        res.isReal = false;
+        res.intPred = p;
+        return res;
+    }
+    static LLVMPred Real(RealPredicate p)
+    {
+        LLVMPred res;
+        res.isValid = true;
+        res.isReal = true;
+        res.realPred = p;
+        return res;
+    }
+}
+private LLVMPred predFromBI(BuiltinOperation op)
+{
+    alias BuiltinOperation O;
+    LLVMPred pred;
+    switch (op) {
+        case O.Eq:  pred = LLVMPred.Int(IntPredicate.EQ);  break;
+        case O.Ne:  pred = LLVMPred.Int(IntPredicate.NE);  break;
+
+        case O.SLt: pred = LLVMPred.Int(IntPredicate.SLT); break;
+        case O.ULt: pred = LLVMPred.Int(IntPredicate.ULT); break;
+        case O.FLt: pred = LLVMPred.Real(RealPredicate.OLT); break;
+
+        case O.SLe: pred = LLVMPred.Int(IntPredicate.SLE); break;
+        case O.ULe: pred = LLVMPred.Int(IntPredicate.ULE); break;
+        case O.FLe: pred = LLVMPred.Real(RealPredicate.OLE); break;
+
+        case O.SGt: pred = LLVMPred.Int(IntPredicate.SGT); break;
+        case O.UGt: pred = LLVMPred.Int(IntPredicate.UGT); break;
+        case O.FGt: pred = LLVMPred.Real(RealPredicate.OGT); break;
+
+        case O.SGe: pred = LLVMPred.Int(IntPredicate.SGE); break;
+        case O.UGe: pred = LLVMPred.Int(IntPredicate.UGE); break;
+        case O.FGe: pred = LLVMPred.Real(RealPredicate.OGE); break;
+    };
+    return pred;
 }
 
 private class VisitFuncDecls : Visitor!(void)
@@ -783,7 +938,7 @@
         this.dg = dg;
     }
 
-    override void visitModule(Module m)
+    override void visitModule(DModule m)
     {
         foreach (decl; m.decls)
             if (auto f = cast(FuncDecl)decl)
--- a/sema/DType.d	Thu May 08 10:54:29 2008 +0200
+++ b/sema/DType.d	Sun May 25 14:40:14 2008 +0200
@@ -3,7 +3,8 @@
 import lexer.Token,
        ast.Exp;
 
-import tango.io.Stdout;
+public
+import sema.Operation;
 
 class DType
 {
@@ -86,6 +87,16 @@
     bool hasImplicitConversionTo(DType that) { return false; }
 
     /**
+      Get an Operation describing how to use the supplied operator on the two
+      types given.
+     */
+    Operation getOperationWith(Operator op, DType other)
+    {
+        Operation res;
+        return res;
+    }
+
+    /**
       Get a type representing a pointer to this type (from int to int*)
      */
     DPointer getPointerTo()
@@ -188,6 +199,14 @@
     override bool isInteger() { return true; }
     override DInteger asInteger() { return this; }
 
+    override Operation getOperationWith(Operator op, DType that)
+    {
+        Operation operation;
+        if (this is that)
+            operation = Operation.builtin(op, unsigned, false);
+        return operation;
+    }
+
     override char[] mangle()
     {
         return mangle_types[this];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sema/Operation.d	Sun May 25 14:40:14 2008 +0200
@@ -0,0 +1,136 @@
+module sema.Operation;
+
+/// Operators
+public enum Operator
+{
+    Add, Sub, Mul, Div, Rem,
+    Shl, LShr, AShr,
+    And, Or, Xor,
+
+    Eq, Ne,
+    Lt, Le,
+    Gt, Ge,
+}
+
+/**
+  Enum for the basic builtin operations.
+
+  S for signed, U for unsigned and F for floating point.
+ **/
+public enum BuiltinOperation
+{
+    Add, Sub, Mul, SDiv, UDiv, FDiv, SRem, URem, FRem,
+
+    Shl, LShr, AShr,
+    And, Or, Xor,
+
+    Eq, Ne,
+    SLt, ULt, FLt, SLe, ULe, FLe,
+    SGt, UGt, FGt, SGe, UGe, FGe,
+
+    None
+}
+
+/**
+  Returns true if the operation has an unsigned variant.
+
+  Will only be true for the S version, so SDiv gives true, UDiv or FDiv dont.
+ **/
+private bool hasUnsignedVariant(BuiltinOperation op)
+{
+    alias BuiltinOperation O;
+    return op is O.SDiv
+        || op is O.SRem
+        || op is O.SLt
+        || op is O.SLe
+        || op is O.SGt
+        || op is O.SGe;
+}
+
+/// Same as hasUnsignedVariant, but for float variants
+private bool hasFloatVariant(BuiltinOperation op)
+{
+    alias BuiltinOperation O;
+    return op is O.SDiv
+        || op is O.SRem
+        || op is O.SLt
+        || op is O.SLe
+        || op is O.SGt
+        || op is O.SGe;
+}
+
+private BuiltinOperation OpToBI(Operator op)
+{
+    // This is dependent on the definition of Operator
+    // Maps from an Operator to the first appropiate BuiltinOperation
+    static const BuiltinOperation[] map =
+        [
+            BuiltinOperation.Add,
+            BuiltinOperation.Sub,
+            BuiltinOperation.Mul,
+            BuiltinOperation.SDiv,
+            BuiltinOperation.SRem,
+
+            BuiltinOperation.Shl,
+            BuiltinOperation.LShr,
+            BuiltinOperation.AShr,
+            BuiltinOperation.And,
+            BuiltinOperation.Or,
+            BuiltinOperation.Xor,
+
+            BuiltinOperation.Eq,
+            BuiltinOperation.Ne,
+            BuiltinOperation.SLt,
+            BuiltinOperation.SLe,
+            BuiltinOperation.SGt,
+            BuiltinOperation.SGe,
+
+        ];
+    if (op >= Operator.Add && op <= Operator.Ge)
+        return map[op];
+
+    return BuiltinOperation.None;
+}
+
+/**
+    Represents an operation on to values of (potentionally) different types.
+
+    Can be either some built-in thing (addition of floats, int etc) or a user
+    defined operation (a method in a struct/class).
+ **/
+struct Operation
+{
+    /// Returns true if the operation is legal
+    bool isPossible() { return is_valid; }
+
+    /// True for <, <=, ==, !=, >, >=
+    bool isComparison() { return false; }
+
+    /// Built in operations like adding ints or floats
+    bool isBuiltin() { return is_bi; }
+
+    /// Get the builtin operation - only valid if isBuiltin() returns true
+    BuiltinOperation builtinOp() { return bi_op; };
+
+    /// Create builtin operation
+    static Operation builtin(Operator op, bool unsigned, bool fp)
+    {
+        assert(!(unsigned && fp), "Can't be both unsigned and a float");
+        Operation res;
+        res.is_valid = true;
+        res.is_bi = true;
+        res.bi_op = OpToBI(op);
+
+        if (unsigned && hasUnsignedVariant(res.bi_op))
+            res.bi_op += 1;
+        if (fp && hasFloatVariant(res.bi_op))
+            res.bi_op += 2;
+        return res;
+    }
+
+private:
+    bool is_valid = false;
+    bool is_bi;
+    BuiltinOperation bi_op;
+}
+
--- a/sema/Scope.d	Thu May 08 10:54:29 2008 +0200
+++ b/sema/Scope.d	Sun May 25 14:40:14 2008 +0200
@@ -24,6 +24,7 @@
     Scope enclosing;
     ModuleHandler mHandle;
     Module inModule;
+    Scope[] imported;
 
     ImportDecl[] imports;
 
@@ -35,7 +36,7 @@
 
     Identifier find(Identifier id)
     {
-        if(!id)
+        if(id is null)
             return null;
         if (auto sym = id in symbols)
             return *sym;
--- a/sema/ScopeBuilder.d	Thu May 08 10:54:29 2008 +0200
+++ b/sema/ScopeBuilder.d	Sun May 25 14:40:14 2008 +0200
@@ -42,14 +42,16 @@
 
     override void visitStructDecl(StructDecl s)
     {
+        super.visitStructDecl(s);
+
         DType[char[]] types;
 
         auto st = s.env.types[s.identifier.get].asStruct;
-        foreach(decl ; s.decls)
-            if(auto varDecl = cast(VarDecl)decl)
+        foreach (decl; s.decls)
+            if (auto varDecl = cast(VarDecl)decl)
                 st.addMember(typeOf(varDecl.varType, varDecl.env), varDecl.identifier.get);
-
-        super.visitStructDecl(s);
+            else if (auto fd = cast(FuncDecl)decl)
+                st.addMember(fd.type, fd.identifier.get);
     }
 
     DType typeOf(Identifier id, Scope sc)
--- a/sema/TypeCheck.d	Thu May 08 10:54:29 2008 +0200
+++ b/sema/TypeCheck.d	Sun May 25 14:40:14 2008 +0200
@@ -90,7 +90,7 @@
 
             auto castExp = new CastExp(
                     SLoc.Invalid,
-                    new Identifier(expType.name),
+                    new Identifier(identifierType.name),
                     exp.exp);
             castExp.env = exp.exp.env;
             exp.exp = castExp;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/sarray_1.d	Sun May 25 14:40:14 2008 +0200
@@ -0,0 +1,7 @@
+int main()
+{
+    int[10] a;
+    a[0] = 1;
+    a[1] = a[0];
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/sarray_2.d	Sun May 25 14:40:14 2008 +0200
@@ -0,0 +1,8 @@
+//fail
+int main()
+{
+    int[10] a;
+    // static array assignment is illegal - we fail for other reasons though
+    int[10] b = a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/sema/deref_1.d	Sun May 25 14:40:14 2008 +0200
@@ -0,0 +1,7 @@
+//fail
+int main()
+{
+    int a = 2;
+    int b = *a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/sema/deref_2.d	Sun May 25 14:40:14 2008 +0200
@@ -0,0 +1,10 @@
+int main()
+{
+    int *a;
+    int *b;
+    a = b;
+    *a = 1;
+
+    return *a == *b;
+}
+