Mercurial > projects > dang
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; +} +