# HG changeset patch # User Anders Halager # Date 1209218094 -7200 # Node ID c96cdcbdb9d6579fc4c7b725982b5deeaf7a61b6 # Parent e24515bcd4ef3671c11b45aad6e33fe4e9d0a4dd Rearranged some stuff, and renamed LLVMGen -> CodeGen diff -r e24515bcd4ef -r c96cdcbdb9d6 dang/compiler.d --- a/dang/compiler.d Sat Apr 26 15:31:20 2008 +0200 +++ b/dang/compiler.d Sat Apr 26 15:54:54 2008 +0200 @@ -14,10 +14,10 @@ import tools.AstPrinter, tools.DotPrinter; -import gen.LuaGen, - gen.LLVMGen; +import gen.CodeGen; import sema.Visitor, + sema.AstAction, sema.SymbolTableBuilder, sema.Declarations; @@ -107,7 +107,7 @@ ["--gen-llvm"], { /* postParse.attach( (Decl[] decls, DataSource src) { - auto llvmGen = new LLVMGen(); + auto llvmGen = new CodeGen(); llvmGen.gen(decls); }); */ } @@ -140,7 +140,7 @@ postParse.attach( (Decl[] decls, DataSource src) { - auto llvmGen = new LLVMGen(); + auto llvmGen = new CodeGen(); llvmGen.gen(decls, optimize, inline); }); @@ -164,7 +164,7 @@ preParse(lexer); auto parser = new Parser; - auto decls = cast(Decl[])parser.parse(lexer); + auto decls = cast(Decl[])parser.parse(lexer, new AstAction); (new SymbolTableBuilder).visit(decls); (new Declarations).visit(decls); diff -r e24515bcd4ef -r c96cdcbdb9d6 gen/CodeGen.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/CodeGen.d Sat Apr 26 15:54:54 2008 +0200 @@ -0,0 +1,652 @@ +module gen.CodeGen; + +import tango.io.Stdout, + Int = tango.text.convert.Integer; +import tango.core.Array : find; + +import llvm.llvm; + +import ast.Decl, + ast.Stmt, + ast.Exp; + +import misc.Error; + +import lexer.Token; + +import sema.SymbolTableBuilder, + sema.Visitor; + +private char[] genBuildCmp(char[] p) +{ + return ` + (Value l, Value r, char[] n) + { + return b.buildICmp(IntPredicate.`~p~`, l, r, n); + }`; +} + +class CodeGen +{ +public: + this() + { + alias BinaryExp.Operator op; + b = new Builder; + + opToLLVM = [ + op.Add : &b.buildAdd, + op.Sub : &b.buildSub, + op.Mul : &b.buildMul, + op.Div : &b.buildSDiv, + op.Eq : mixin(genBuildCmp("EQ")), + op.Ne : mixin(genBuildCmp("NE")), + op.Lt : mixin(genBuildCmp("SLT")), + op.Le : mixin(genBuildCmp("SLE")), + op.Gt : mixin(genBuildCmp("SGT")), + op.Ge : mixin(genBuildCmp("SGE")) + ]; + table = new SimpleSymbolTable(); + + createBasicTypes(); + } + + ~this() + { + b.dispose(); + } + + void gen(Decl[] decls, bool optimize, bool inline) + { + // create module + m = new 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]); + llvm_memcpy = m.addFunction(temp, "llvm.memcpy.i32"); + auto registerFunc = + (FuncDecl fd) + { + Type[] param_types; + foreach (p; fd.funcArgs) + { + DType t = p.env.find(p.identifier).type; + if(cast(DStruct)t) + { + Type pointer = PointerType.Get(llvm(t)); + param_types ~= pointer; + } + else + param_types ~= llvm(t); + } + auto ret_t = llvm(fd.env.find(fd.identifier).type); + auto func_t = FunctionType.Get(ret_t, param_types); + auto llfunc = m.addFunction(func_t, fd.identifier.get); + }; + auto visitor = new VisitFuncDecls(registerFunc); + visitor.visit(decls); + + foreach (decl; decls) + genRootDecl(decl); + + table.leaveScope; + + char[] err; + m.verify(err); + Stderr(err).newline; + + if(optimize) + m.optimize(inline); + + m.writeBitcodeToFile("out.bc"); + } + + void genRootDecl(Decl decl) + { + switch(decl.declType) + { + case DeclType.FuncDecl: + FuncDecl funcDecl = cast(FuncDecl)decl; + + auto llfunc = m.getNamedFunction(funcDecl.identifier.get); + auto func_tp = cast(PointerType)llfunc.type; + auto func_t = cast(FunctionType)func_tp.elementType(); + auto ret_t = func_t.returnType(); + + auto bb = llfunc.appendBasicBlock("entry"); + b.positionAtEnd(bb); + + table.enterScope; + foreach (i, v; funcDecl.funcArgs) + { + llfunc.getParam(i).name = v.identifier.get; + auto name = v.identifier.get; + if(!cast(PointerType)llfunc.getParam(i).type) + { + auto AI = b.buildAlloca(llfunc.getParam(i).type, name); + // Value va = b.buildLoad(val, name); + b.buildStore(llfunc.getParam(i), AI); + table[name] = AI; + } + else + table[name] = llfunc.getParam(i); + } + + foreach (stmt; funcDecl.statements) + genStmt(stmt); + + // if the function didn't end with a return, we automatically + // add one (return 0 as default) + if (b.getInsertBlock().terminated() is false) + if (ret_t is Type.Void) + b.buildRetVoid(); + else + b.buildRet(ConstantInt.GetS(ret_t, 0)); + + table.leaveScope; + break; + + case DeclType.VarDecl: + auto varDecl = cast(VarDecl)decl; + auto sym = varDecl.env.find(varDecl.identifier); + Type t = llvm(sym.type); + GlobalVariable g = m.addGlobal(t, sym.id.get); + g.initializer = ConstantInt.GetS(t, 0); + table[varDecl.identifier.get] = g; + break; + + case DeclType.StructDecl: + auto structDecl = cast(StructDecl)decl; + Type[] types; + foreach(varDecl ; structDecl.vars) + { + auto sym = varDecl.env.find(varDecl.identifier); + Type t = llvm(sym.type); + types ~= t; + } + + StructType t = StructType.Get(types); + m.addTypeName(structDecl.identifier.get, t); +// table[structDecl.identifier.get] = g; + + break; + + default: + break; + } + } + + void genDecl(Decl decl) + { + switch(decl.declType) + { + case DeclType.VarDecl: + auto varDecl = cast(VarDecl)decl; + auto name = varDecl.identifier.get; + auto sym = varDecl.env.find(varDecl.identifier); + auto AI = b.buildAlloca(llvm(sym.type), name); + table[name] = AI; + if (varDecl.init) + buildAssign(varDecl.identifier, varDecl.init); + break; + + default: + } + } + + struct PE + { + static char[] NoImplicitConversion = + "Can't find an implicit conversion between %0 and %1"; + static char[] VoidRetInNonVoidFunc = + "Only void functions can return without an expression"; + } + + void sextSmallerToLarger(ref Value left, ref Value right) + { + if (left.type != right.type) + { + // try to find a convertion - only works for iX + IntegerType l = cast(IntegerType) left.type; + IntegerType r = cast(IntegerType) right.type; + if (l is null || r is null) + throw error(__LINE__, PE.NoImplicitConversion) + .arg(left.type.toString) + .arg(right.type.toString); + + if (l.numBits() < r.numBits()) + left = b.buildSExt(left, r, ".cast"); + else + right = b.buildSExt(right, l, ".cast"); + } + } + + Value 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, "."); + + case ExpType.IntegerLit: + auto integetLit = cast(IntegerLit)exp; + auto val = integetLit.token.get; + return ConstantInt.GetS(Type.Int32, Integer.parse(val)); + case ExpType.Negate: + auto negateExp = cast(NegateExp)exp; + auto target = genExpression(negateExp.exp); + return b.buildNeg(target, "neg"); + case ExpType.AssignExp: + auto assignExp = cast(AssignExp)exp; + return buildAssign(assignExp.identifier, assignExp.exp); + case ExpType.CallExp: + auto callExp = cast(CallExp)exp; + auto func_sym = exp.env.find(cast(Identifier)callExp.exp); + Value[] args; + foreach (arg; callExp.args) + { + Value v = genExpression(arg); + + if(auto ptr = cast(PointerType)v.type) + { + args ~= v; + } + else + args ~= v; + + } + return b.buildCall(m.getNamedFunction(func_sym.id.get), args, ".call"); + case ExpType.Identifier: + auto identifier = cast(Identifier)exp; + auto sym = exp.env.find(identifier); + if(cast(DStruct)sym.type) + return table.find(sym.id.get); + else + return b.buildLoad(table.find(sym.id.get), sym.id.get); + case ExpType.MemberLookup: + auto v = getPointer(exp); + return b.buildLoad(v, v.name); + } + assert(0, "Reached end of switch in genExpression"); + return null; + } + + void genStmt(Stmt stmt) + { + switch(stmt.stmtType) + { + case StmtType.Compound: + auto stmts = cast(CompoundStatement)stmt; + foreach (s; stmts.statements) + genStmt(s); + break; + case StmtType.Return: + auto ret = cast(ReturnStmt)stmt; + auto sym = stmt.env.parentFunction(); + Type t = llvm(sym.type); + if (ret.exp is null) + if (t is Type.Void) + { + b.buildRetVoid(); + return; + } + else + throw error(__LINE__, PE.VoidRetInNonVoidFunc); + + Value v = genExpression(ret.exp); + if (v.type != t) + { + IntegerType v_t = cast(IntegerType) v.type; + IntegerType i_t = cast(IntegerType) t; + if (v_t is null || i_t is null) + throw error(__LINE__, PE.NoImplicitConversion) + .arg(v.type.toString) + .arg(t.toString); + + if (v_t.numBits() < i_t.numBits()) + v = b.buildSExt(v, t, ".cast"); + else + v = b.buildTrunc(v, t, ".cast"); + } + b.buildRet(v); + break; + case StmtType.Decl: + auto declStmt = cast(DeclStmt)stmt; + genDecl(declStmt.decl); + break; + case StmtType.Exp: + auto expStmt = cast(ExpStmt)stmt; + genExpression(expStmt.exp); + break; + case StmtType.If: + auto ifStmt = cast(IfStmt)stmt; + Value cond = genExpression(ifStmt.cond); + if (cond.type !is Type.Int1) + { + Value False = ConstantInt.GetS(cond.type, 0); + cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond"); + } + auto func_name = stmt.env.parentFunction().id.get; + Function func = m.getNamedFunction(func_name); + bool has_else = (ifStmt.else_body !is null); + + auto thenBB = func.appendBasicBlock("then"); + auto elseBB = has_else? func.appendBasicBlock("else") : null; + auto mergeBB = func.appendBasicBlock("merge"); + + b.buildCondBr(cond, thenBB, has_else? elseBB : mergeBB); + b.positionAtEnd(thenBB); + genStmt(ifStmt.then_body); + thenBB = b.getInsertBlock(); + if (b.getInsertBlock().terminated() is false) + b.buildBr(mergeBB); + + if (has_else) + { + b.positionAtEnd(elseBB); + genStmt(ifStmt.else_body); + elseBB = b.getInsertBlock(); + if (elseBB.terminated() is false) + b.buildBr(mergeBB); + } + + b.positionAtEnd(mergeBB); + break; + case StmtType.While: + auto wStmt = cast(WhileStmt)stmt; + auto func_name = stmt.env.parentFunction().id.get; + Function func = m.getNamedFunction(func_name); + + auto condBB = func.appendBasicBlock("cond"); + auto bodyBB = func.appendBasicBlock("body"); + auto doneBB = func.appendBasicBlock("done"); + + b.buildBr(condBB); + b.positionAtEnd(condBB); + Value cond = genExpression(wStmt.cond); + if (cond.type !is Type.Int1) + { + Value False = ConstantInt.GetS(cond.type, 0); + cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond"); + } + b.buildCondBr(cond, bodyBB, doneBB); + + b.positionAtEnd(bodyBB); + genStmt(wStmt.whileBody); + if (b.getInsertBlock().terminated() is false) + b.buildBr(condBB); + + b.positionAtEnd(doneBB); + break; + case StmtType.Switch: + auto sw = cast(SwitchStmt)stmt; + Value cond = genExpression(sw.cond); + + auto func_name = stmt.env.parentFunction().id.get; + Function func = m.getNamedFunction(func_name); + + BasicBlock oldBB = b.getInsertBlock(); + BasicBlock defBB; + BasicBlock endBB = func.appendBasicBlock("sw.end"); + if (sw.defaultBlock) + { + defBB = Function.InsertBasicBlock(endBB, "sw.def"); + b.positionAtEnd(defBB); + foreach (case_statement; sw.defaultBlock) + genStmt(case_statement); + if (!defBB.terminated()) + b.buildBr(endBB); + b.positionAtEnd(oldBB); + } + else + defBB = endBB; + auto SI = b.buildSwitch(cond, defBB, sw.cases.length); + foreach (c; sw.cases) + { + BasicBlock prevBB; + foreach (i, val; c.values) + { + auto BB = Function.InsertBasicBlock(defBB, "sw.bb"); + SI.addCase(ConstantInt.GetS(cond.type, c.values_converted[i]), BB); + + if (i + 1 == c.values.length) + { + b.positionAtEnd(BB); + foreach (case_statement; c.stmts) + genStmt(case_statement); + if (!BB.terminated()) + b.buildBr(c.followedByDefault? defBB : endBB); + } + + if (prevBB !is null && !prevBB.terminated()) + { + b.positionAtEnd(prevBB); + b.buildBr(BB); + } + prevBB = BB; + } + } + b.positionAtEnd(endBB); + break; + } + } + + Value getPointer(Exp exp) + { + switch(exp.expType) + { + case ExpType.Identifier: + auto identifier = cast(Identifier)exp; + auto sym = exp.env.find(identifier); + return table.find(sym.id.get); + case ExpType.MemberLookup: + auto mem = cast(MemberLookup)exp; + switch(mem.target.expType) + { + case ExpType.Identifier: + auto identifier = cast(Identifier)mem.target; + auto child = mem.child; + auto sym = exp.env.find(identifier); + auto symChild = child.env.find(child); + Value v = table.find(sym.id.get); + DType t = sym.type; + auto st = cast(DStruct)t; + + int i = 0; + foreach(char[] name, DType type ; st.members) + if(name == child.get) + break; + else + i++; + + Value[] vals; + vals ~= ConstantInt.Get(IntegerType.Int32, 0, false); + vals ~= ConstantInt.Get(IntegerType.Int32, i, false); + + Value val = b.buildGEP(v, vals, sym.id.get~"."~child.get); + return val; + + default: + Value val = genExpression(exp); + auto AI = b.buildAlloca(val.type, ".s"); + return b.buildStore(val, AI); + } + default: + Value val = genExpression(exp); + auto AI = b.buildAlloca(val.type, ".s"); + return b.buildStore(val, AI); + } + assert(0, "Reached end of switch in getPointer"); + return null; + } + + private Value buildAssign(Exp target, Exp exp) + { + Value t = getPointer(target); + Value v = genExpression(exp); + + auto a = cast(PointerType)t.type; + + 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; + + 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( "from", "to", type_size, alignment (32 in clang) ); + b.buildCall(llvm_memcpy, [from, to, ConstantInt.GetS(Type.Int32, 8), ConstantInt.GetS(Type.Int32, 32)], null); + // return "to" + return t; + } + } + + 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); + } + + Error error(uint line, char[] msg) + { + return new Error(msg); + } + + /** + Get the LLVM Type corresponding to a DType. + + Currently using the built-in associative array - not sure if it works + well when the hashes are so uniform. + + Other possibilities would be to find a hash-function that works on + something as small as 4 bytes or to create a sparse array perhaps. + */ + Type llvm(DType t) + { + if (auto llvm_t = t in type_map) + return *llvm_t; + return llvmCreateNew(t); + } + + // Create an LLVM type and insert it into the type map, and return the + // result + Type llvmCreateNew(DType t) + { + if (auto i = cast(DInteger)t) + { + Type res = IntegerType.Get(i.byteSize() * 8); + type_map[t] = res; + return res; + } + assert(0, "Only integers are supported"); + } + + // Might as well insert all the basic types from the start + void createBasicTypes() + { + type_map[DType.Void] = Type.Void; + + type_map[DType.Bool] = Type.Int1; + type_map[DType.Byte] = Type.Int8; + type_map[DType.UByte] = Type.Int8; + type_map[DType.Short] = Type.Int16; + type_map[DType.UShort] = Type.Int16; + type_map[DType.Int] = Type.Int32; + type_map[DType.UInt] = Type.Int32; + type_map[DType.Long] = Type.Int64; + type_map[DType.ULong] = Type.Int64; + } + +private: + + // llvm stuff + Module m; + Builder b; + Function llvm_memcpy; + Type BytePtr; + Type[DType] type_map; + + FuncDecl[char[]] functions; + + SimpleSymbolTable table; + alias Value delegate(Value, Value, char[]) OpBuilder; + static OpBuilder[BinaryExp.Operator] opToLLVM; +} + +private class VisitFuncDecls : Visitor!(void) +{ + void delegate(FuncDecl) dg; + this(void delegate(FuncDecl funcDecl) dg) + { + this.dg = dg; + } + + override void visit(Decl[] decls) + { + foreach (decl; decls) + if (auto f = cast(FuncDecl)decl) + dg(f); + } +} + +private class SimpleSymbolTable +{ + Value[char[]][] namedValues; + + void enterScope() + { + namedValues ~= cast(Value[char[]])["__dollar":null]; + } + + void leaveScope() + { + namedValues.length = namedValues.length - 1; + } + + Value put(Value val, char[] key) + { + namedValues[$ - 1][key] = val; + return val; + } + + Value find(char[] key) + { + foreach_reverse (map; namedValues) + if(auto val_ptr = key in map) + return *val_ptr; + return null; + } + + alias find opIndex; + alias put opIndexAssign; +} + diff -r e24515bcd4ef -r c96cdcbdb9d6 gen/LLVMGen.d --- a/gen/LLVMGen.d Sat Apr 26 15:31:20 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,652 +0,0 @@ -module gen.LLVMGen; - -import tango.io.Stdout, - Int = tango.text.convert.Integer; -import tango.core.Array : find; - -import llvm.llvm; - -import ast.Decl, - ast.Stmt, - ast.Exp; - -import misc.Error; - -import lexer.Token; - -import sema.SymbolTableBuilder, - sema.Visitor; - -private char[] genBuildCmp(char[] p) -{ - return ` - (Value l, Value r, char[] n) - { - return b.buildICmp(IntPredicate.`~p~`, l, r, n); - }`; -} - -class LLVMGen -{ -public: - this() - { - alias BinaryExp.Operator op; - b = new Builder; - - opToLLVM = [ - op.Add : &b.buildAdd, - op.Sub : &b.buildSub, - op.Mul : &b.buildMul, - op.Div : &b.buildSDiv, - op.Eq : mixin(genBuildCmp("EQ")), - op.Ne : mixin(genBuildCmp("NE")), - op.Lt : mixin(genBuildCmp("SLT")), - op.Le : mixin(genBuildCmp("SLE")), - op.Gt : mixin(genBuildCmp("SGT")), - op.Ge : mixin(genBuildCmp("SGE")) - ]; - table = new SimpleSymbolTable(); - - createBasicTypes(); - } - - ~this() - { - b.dispose(); - } - - void gen(Decl[] decls, bool optimize, bool inline) - { - // create module - m = new 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]); - llvm_memcpy = m.addFunction(temp, "llvm.memcpy.i32"); - auto registerFunc = - (FuncDecl fd) - { - Type[] param_types; - foreach (p; fd.funcArgs) - { - DType t = p.env.find(p.identifier).type; - if(cast(DStruct)t) - { - Type pointer = PointerType.Get(llvm(t)); - param_types ~= pointer; - } - else - param_types ~= llvm(t); - } - auto ret_t = llvm(fd.env.find(fd.identifier).type); - auto func_t = FunctionType.Get(ret_t, param_types); - auto llfunc = m.addFunction(func_t, fd.identifier.get); - }; - auto visitor = new VisitFuncDecls(registerFunc); - visitor.visit(decls); - - foreach (decl; decls) - genRootDecl(decl); - - table.leaveScope; - - char[] err; - m.verify(err); - Stderr(err).newline; - - if(optimize) - m.optimize(inline); - - m.writeBitcodeToFile("out.bc"); - } - - void genRootDecl(Decl decl) - { - switch(decl.declType) - { - case DeclType.FuncDecl: - FuncDecl funcDecl = cast(FuncDecl)decl; - - auto llfunc = m.getNamedFunction(funcDecl.identifier.get); - auto func_tp = cast(PointerType)llfunc.type; - auto func_t = cast(FunctionType)func_tp.elementType(); - auto ret_t = func_t.returnType(); - - auto bb = llfunc.appendBasicBlock("entry"); - b.positionAtEnd(bb); - - table.enterScope; - foreach (i, v; funcDecl.funcArgs) - { - llfunc.getParam(i).name = v.identifier.get; - auto name = v.identifier.get; - if(!cast(PointerType)llfunc.getParam(i).type) - { - auto AI = b.buildAlloca(llfunc.getParam(i).type, name); - // Value va = b.buildLoad(val, name); - b.buildStore(llfunc.getParam(i), AI); - table[name] = AI; - } - else - table[name] = llfunc.getParam(i); - } - - foreach (stmt; funcDecl.statements) - genStmt(stmt); - - // if the function didn't end with a return, we automatically - // add one (return 0 as default) - if (b.getInsertBlock().terminated() is false) - if (ret_t is Type.Void) - b.buildRetVoid(); - else - b.buildRet(ConstantInt.GetS(ret_t, 0)); - - table.leaveScope; - break; - - case DeclType.VarDecl: - auto varDecl = cast(VarDecl)decl; - auto sym = varDecl.env.find(varDecl.identifier); - Type t = llvm(sym.type); - GlobalVariable g = m.addGlobal(t, sym.id.get); - g.initializer = ConstantInt.GetS(t, 0); - table[varDecl.identifier.get] = g; - break; - - case DeclType.StructDecl: - auto structDecl = cast(StructDecl)decl; - Type[] types; - foreach(varDecl ; structDecl.vars) - { - auto sym = varDecl.env.find(varDecl.identifier); - Type t = llvm(sym.type); - types ~= t; - } - - StructType t = StructType.Get(types); - m.addTypeName(structDecl.identifier.get, t); -// table[structDecl.identifier.get] = g; - - break; - - default: - break; - } - } - - void genDecl(Decl decl) - { - switch(decl.declType) - { - case DeclType.VarDecl: - auto varDecl = cast(VarDecl)decl; - auto name = varDecl.identifier.get; - auto sym = varDecl.env.find(varDecl.identifier); - auto AI = b.buildAlloca(llvm(sym.type), name); - table[name] = AI; - if (varDecl.init) - buildAssign(varDecl.identifier, varDecl.init); - break; - - default: - } - } - - struct PE - { - static char[] NoImplicitConversion = - "Can't find an implicit conversion between %0 and %1"; - static char[] VoidRetInNonVoidFunc = - "Only void functions can return without an expression"; - } - - void sextSmallerToLarger(ref Value left, ref Value right) - { - if (left.type != right.type) - { - // try to find a convertion - only works for iX - IntegerType l = cast(IntegerType) left.type; - IntegerType r = cast(IntegerType) right.type; - if (l is null || r is null) - throw error(__LINE__, PE.NoImplicitConversion) - .arg(left.type.toString) - .arg(right.type.toString); - - if (l.numBits() < r.numBits()) - left = b.buildSExt(left, r, ".cast"); - else - right = b.buildSExt(right, l, ".cast"); - } - } - - Value 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, "."); - - case ExpType.IntegerLit: - auto integetLit = cast(IntegerLit)exp; - auto val = integetLit.token.get; - return ConstantInt.GetS(Type.Int32, Integer.parse(val)); - case ExpType.Negate: - auto negateExp = cast(NegateExp)exp; - auto target = genExpression(negateExp.exp); - return b.buildNeg(target, "neg"); - case ExpType.AssignExp: - auto assignExp = cast(AssignExp)exp; - return buildAssign(assignExp.identifier, assignExp.exp); - case ExpType.CallExp: - auto callExp = cast(CallExp)exp; - auto func_sym = exp.env.find(cast(Identifier)callExp.exp); - Value[] args; - foreach (arg; callExp.args) - { - Value v = genExpression(arg); - - if(auto ptr = cast(PointerType)v.type) - { - args ~= v; - } - else - args ~= v; - - } - return b.buildCall(m.getNamedFunction(func_sym.id.get), args, ".call"); - case ExpType.Identifier: - auto identifier = cast(Identifier)exp; - auto sym = exp.env.find(identifier); - if(cast(DStruct)sym.type) - return table.find(sym.id.get); - else - return b.buildLoad(table.find(sym.id.get), sym.id.get); - case ExpType.MemberLookup: - auto v = getPointer(exp); - return b.buildLoad(v, v.name); - } - assert(0, "Reached end of switch in genExpression"); - return null; - } - - void genStmt(Stmt stmt) - { - switch(stmt.stmtType) - { - case StmtType.Compound: - auto stmts = cast(CompoundStatement)stmt; - foreach (s; stmts.statements) - genStmt(s); - break; - case StmtType.Return: - auto ret = cast(ReturnStmt)stmt; - auto sym = stmt.env.parentFunction(); - Type t = llvm(sym.type); - if (ret.exp is null) - if (t is Type.Void) - { - b.buildRetVoid(); - return; - } - else - throw error(__LINE__, PE.VoidRetInNonVoidFunc); - - Value v = genExpression(ret.exp); - if (v.type != t) - { - IntegerType v_t = cast(IntegerType) v.type; - IntegerType i_t = cast(IntegerType) t; - if (v_t is null || i_t is null) - throw error(__LINE__, PE.NoImplicitConversion) - .arg(v.type.toString) - .arg(t.toString); - - if (v_t.numBits() < i_t.numBits()) - v = b.buildSExt(v, t, ".cast"); - else - v = b.buildTrunc(v, t, ".cast"); - } - b.buildRet(v); - break; - case StmtType.Decl: - auto declStmt = cast(DeclStmt)stmt; - genDecl(declStmt.decl); - break; - case StmtType.Exp: - auto expStmt = cast(ExpStmt)stmt; - genExpression(expStmt.exp); - break; - case StmtType.If: - auto ifStmt = cast(IfStmt)stmt; - Value cond = genExpression(ifStmt.cond); - if (cond.type !is Type.Int1) - { - Value False = ConstantInt.GetS(cond.type, 0); - cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond"); - } - auto func_name = stmt.env.parentFunction().id.get; - Function func = m.getNamedFunction(func_name); - bool has_else = (ifStmt.else_body !is null); - - auto thenBB = func.appendBasicBlock("then"); - auto elseBB = has_else? func.appendBasicBlock("else") : null; - auto mergeBB = func.appendBasicBlock("merge"); - - b.buildCondBr(cond, thenBB, has_else? elseBB : mergeBB); - b.positionAtEnd(thenBB); - genStmt(ifStmt.then_body); - thenBB = b.getInsertBlock(); - if (b.getInsertBlock().terminated() is false) - b.buildBr(mergeBB); - - if (has_else) - { - b.positionAtEnd(elseBB); - genStmt(ifStmt.else_body); - elseBB = b.getInsertBlock(); - if (elseBB.terminated() is false) - b.buildBr(mergeBB); - } - - b.positionAtEnd(mergeBB); - break; - case StmtType.While: - auto wStmt = cast(WhileStmt)stmt; - auto func_name = stmt.env.parentFunction().id.get; - Function func = m.getNamedFunction(func_name); - - auto condBB = func.appendBasicBlock("cond"); - auto bodyBB = func.appendBasicBlock("body"); - auto doneBB = func.appendBasicBlock("done"); - - b.buildBr(condBB); - b.positionAtEnd(condBB); - Value cond = genExpression(wStmt.cond); - if (cond.type !is Type.Int1) - { - Value False = ConstantInt.GetS(cond.type, 0); - cond = b.buildICmp(IntPredicate.NE, cond, False, ".cond"); - } - b.buildCondBr(cond, bodyBB, doneBB); - - b.positionAtEnd(bodyBB); - genStmt(wStmt.whileBody); - if (b.getInsertBlock().terminated() is false) - b.buildBr(condBB); - - b.positionAtEnd(doneBB); - break; - case StmtType.Switch: - auto sw = cast(SwitchStmt)stmt; - Value cond = genExpression(sw.cond); - - auto func_name = stmt.env.parentFunction().id.get; - Function func = m.getNamedFunction(func_name); - - BasicBlock oldBB = b.getInsertBlock(); - BasicBlock defBB; - BasicBlock endBB = func.appendBasicBlock("sw.end"); - if (sw.defaultBlock) - { - defBB = Function.InsertBasicBlock(endBB, "sw.def"); - b.positionAtEnd(defBB); - foreach (case_statement; sw.defaultBlock) - genStmt(case_statement); - if (!defBB.terminated()) - b.buildBr(endBB); - b.positionAtEnd(oldBB); - } - else - defBB = endBB; - auto SI = b.buildSwitch(cond, defBB, sw.cases.length); - foreach (c; sw.cases) - { - BasicBlock prevBB; - foreach (i, val; c.values) - { - auto BB = Function.InsertBasicBlock(defBB, "sw.bb"); - SI.addCase(ConstantInt.GetS(cond.type, c.values_converted[i]), BB); - - if (i + 1 == c.values.length) - { - b.positionAtEnd(BB); - foreach (case_statement; c.stmts) - genStmt(case_statement); - if (!BB.terminated()) - b.buildBr(c.followedByDefault? defBB : endBB); - } - - if (prevBB !is null && !prevBB.terminated()) - { - b.positionAtEnd(prevBB); - b.buildBr(BB); - } - prevBB = BB; - } - } - b.positionAtEnd(endBB); - break; - } - } - - Value getPointer(Exp exp) - { - switch(exp.expType) - { - case ExpType.Identifier: - auto identifier = cast(Identifier)exp; - auto sym = exp.env.find(identifier); - return table.find(sym.id.get); - case ExpType.MemberLookup: - auto mem = cast(MemberLookup)exp; - switch(mem.target.expType) - { - case ExpType.Identifier: - auto identifier = cast(Identifier)mem.target; - auto child = mem.child; - auto sym = exp.env.find(identifier); - auto symChild = child.env.find(child); - Value v = table.find(sym.id.get); - DType t = sym.type; - auto st = cast(DStruct)t; - - int i = 0; - foreach(char[] name, DType type ; st.members) - if(name == child.get) - break; - else - i++; - - Value[] vals; - vals ~= ConstantInt.Get(IntegerType.Int32, 0, false); - vals ~= ConstantInt.Get(IntegerType.Int32, i, false); - - Value val = b.buildGEP(v, vals, sym.id.get~"."~child.get); - return val; - - default: - Value val = genExpression(exp); - auto AI = b.buildAlloca(val.type, ".s"); - return b.buildStore(val, AI); - } - default: - Value val = genExpression(exp); - auto AI = b.buildAlloca(val.type, ".s"); - return b.buildStore(val, AI); - } - assert(0, "Reached end of switch in getPointer"); - return null; - } - - private Value buildAssign(Exp target, Exp exp) - { - Value t = getPointer(target); - Value v = genExpression(exp); - - auto a = cast(PointerType)t.type; - - 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; - - 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( "from", "to", type_size, alignment (32 in clang) ); - b.buildCall(llvm_memcpy, [from, to, ConstantInt.GetS(Type.Int32, 8), ConstantInt.GetS(Type.Int32, 32)], null); - // return "to" - return t; - } - } - - 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); - } - - Error error(uint line, char[] msg) - { - return new Error(msg); - } - - /** - Get the LLVM Type corresponding to a DType. - - Currently using the built-in associative array - not sure if it works - well when the hashes are so uniform. - - Other possibilities would be to find a hash-function that works on - something as small as 4 bytes or to create a sparse array perhaps. - */ - Type llvm(DType t) - { - if (auto llvm_t = t in type_map) - return *llvm_t; - return llvmCreateNew(t); - } - - // Create an LLVM type and insert it into the type map, and return the - // result - Type llvmCreateNew(DType t) - { - if (auto i = cast(DInteger)t) - { - Type res = IntegerType.Get(i.byteSize() * 8); - type_map[t] = res; - return res; - } - assert(0, "Only integers are supported"); - } - - // Might as well insert all the basic types from the start - void createBasicTypes() - { - type_map[DType.Void] = Type.Void; - - type_map[DType.Bool] = Type.Int1; - type_map[DType.Byte] = Type.Int8; - type_map[DType.UByte] = Type.Int8; - type_map[DType.Short] = Type.Int16; - type_map[DType.UShort] = Type.Int16; - type_map[DType.Int] = Type.Int32; - type_map[DType.UInt] = Type.Int32; - type_map[DType.Long] = Type.Int64; - type_map[DType.ULong] = Type.Int64; - } - -private: - - // llvm stuff - Module m; - Builder b; - Function llvm_memcpy; - Type BytePtr; - Type[DType] type_map; - - FuncDecl[char[]] functions; - - SimpleSymbolTable table; - alias Value delegate(Value, Value, char[]) OpBuilder; - static OpBuilder[BinaryExp.Operator] opToLLVM; -} - -private class VisitFuncDecls : Visitor!(void) -{ - void delegate(FuncDecl) dg; - this(void delegate(FuncDecl funcDecl) dg) - { - this.dg = dg; - } - - override void visit(Decl[] decls) - { - foreach (decl; decls) - if (auto f = cast(FuncDecl)decl) - dg(f); - } -} - -private class SimpleSymbolTable -{ - Value[char[]][] namedValues; - - void enterScope() - { - namedValues ~= cast(Value[char[]])["__dollar":null]; - } - - void leaveScope() - { - namedValues.length = namedValues.length - 1; - } - - Value put(Value val, char[] key) - { - namedValues[$ - 1][key] = val; - return val; - } - - Value find(char[] key) - { - foreach_reverse (map; namedValues) - if(auto val_ptr = key in map) - return *val_ptr; - return null; - } - - alias find opIndex; - alias put opIndexAssign; -} - diff -r e24515bcd4ef -r c96cdcbdb9d6 parser/Action.d --- a/parser/Action.d Sat Apr 26 15:31:20 2008 +0200 +++ b/parser/Action.d Sat Apr 26 15:54:54 2008 +0200 @@ -2,15 +2,8 @@ import lexer.Token; -import ast.Exp, - ast.Stmt, - ast.Decl; - import misc.Error; -import tango.io.Stdout, - Integer = tango.text.convert.Integer; - /** Used to indicate what type of operator is used in a given binary expression (and unary expressions?) @@ -250,112 +243,3 @@ { } -/** - This class implements the default actions for Dang, by building up an AST - with the data needed in a compiler. - */ -class AstAction : Action -{ - // -- Declarations -- - override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init) - { - Exp exp = cast(Exp)init; - return new VarDecl(new Identifier(type.tok), new Identifier(id.tok), exp); - } - - override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name) - { - return new FuncDecl(new Identifier(type.tok), new Identifier(name.tok)); - } - - override void addFuncArg(DeclT func, Id type, Id name) - { - FuncDecl fd = cast(FuncDecl)func; - fd.addParam(new Identifier(type.tok), new Identifier(name.tok)); - } - - override DeclT actOnEndOfFunction(DeclT func, StmtT stmts) - { - FuncDecl fd = cast(FuncDecl)func; - fd.setBody(cast(CompoundStatement)stmts); - return fd; - } - - // -- Statements -- - override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts) - { - Stmt[] statements = cast(Stmt[])stmts; - return new CompoundStatement(statements.dup); - } - - override StmtT actOnExprStmt(ExprT exp) - { - return new ExpStmt(cast(Exp)exp); - } - - override StmtT actOnReturnStmt(ref Token loc, ExprT exp) - { - Exp e = cast(Exp)exp; - auto res = new ReturnStmt; - res.exp = e; - return res; - } - - override StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody, - ref Token elseTok, StmtT elseBody) - { - Exp c = cast(Exp)cond; - Stmt t = cast(Stmt)thenBody; - Stmt e = cast(Stmt)elseBody; - return new IfStmt(c, t, e); - } - - override StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody) - { - Exp c = cast(Exp)cond; - Stmt b = cast(Stmt)whileBody; - return new WhileStmt(c, b); - } - - override StmtT actOnDeclStmt(DeclT decl) - { - Decl d = cast(Decl)decl; - return new DeclStmt(d); - } - - // -- Expressions -- - override ExprT actOnNumericConstant(Token c) - { - return new IntegerLit(c); - } - - override ExprT actOnIdentifierExp(Id id) - { - return new Identifier(id.tok); - } - - override ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r) - { - Exp left = cast(Exp)l; - Exp right = cast(Exp)r; - if (op == Operator.Assign) - return new AssignExp(left, right); - else - return new BinaryExp(cast(BinaryExp.Operator)op, left, right); - } - - override ExprT actOnUnaryOp(Token op, ExprT operand) - { - Exp target = cast(Exp)operand; - // can only be -x for now - return new NegateExp(target); - } - - override ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token) - { - Exp f = cast(Exp)fn; - Exp[] arguments = cast(Exp[])args.dup; - return new CallExp(f, arguments); - } -} - diff -r e24515bcd4ef -r c96cdcbdb9d6 parser/Parser.d --- a/parser/Parser.d Sat Apr 26 15:31:20 2008 +0200 +++ b/parser/Parser.d Sat Apr 26 15:54:54 2008 +0200 @@ -20,11 +20,10 @@ alias Object Decl; public: - Decl[] parse(Lexer lexer) + Decl[] parse(Lexer lexer, Action act) { this.lexer = lexer; - action = new AstAction; - + action = act; Decl[] declarations; diff -r e24515bcd4ef -r c96cdcbdb9d6 sema/AstAction.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sema/AstAction.d Sat Apr 26 15:54:54 2008 +0200 @@ -0,0 +1,123 @@ +module sema.AstAction; + +import Integer = tango.text.convert.Integer; + +import lexer.Token; + +import misc.Error; + +import ast.Exp, + ast.Stmt, + ast.Decl; + +public +import parser.Action; + +/** + This class implements the default actions for Dang, by building up an AST + with the data needed in a compiler. + */ +class AstAction : Action +{ + // -- Declarations -- + override DeclT actOnDeclarator(ref Id type, ref Id id, ExprT init) + { + Exp exp = cast(Exp)init; + return new VarDecl(new Identifier(type.tok), new Identifier(id.tok), exp); + } + + override DeclT actOnStartOfFunctionDef(ref Id type, ref Id name) + { + return new FuncDecl(new Identifier(type.tok), new Identifier(name.tok)); + } + + override void addFuncArg(DeclT func, Id type, Id name) + { + FuncDecl fd = cast(FuncDecl)func; + fd.addParam(new Identifier(type.tok), new Identifier(name.tok)); + } + + override DeclT actOnEndOfFunction(DeclT func, StmtT stmts) + { + FuncDecl fd = cast(FuncDecl)func; + fd.setBody(cast(CompoundStatement)stmts); + return fd; + } + + // -- Statements -- + override StmtT actOnCompoundStmt(ref Token l, ref Token r, StmtT[] stmts) + { + Stmt[] statements = cast(Stmt[])stmts; + return new CompoundStatement(statements.dup); + } + + override StmtT actOnExprStmt(ExprT exp) + { + return new ExpStmt(cast(Exp)exp); + } + + override StmtT actOnReturnStmt(ref Token loc, ExprT exp) + { + Exp e = cast(Exp)exp; + auto res = new ReturnStmt; + res.exp = e; + return res; + } + + override StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody, + ref Token elseTok, StmtT elseBody) + { + Exp c = cast(Exp)cond; + Stmt t = cast(Stmt)thenBody; + Stmt e = cast(Stmt)elseBody; + return new IfStmt(c, t, e); + } + + override StmtT actOnWhileStmt(ref Token tok, ExprT cond, StmtT whileBody) + { + Exp c = cast(Exp)cond; + Stmt b = cast(Stmt)whileBody; + return new WhileStmt(c, b); + } + + override StmtT actOnDeclStmt(DeclT decl) + { + Decl d = cast(Decl)decl; + return new DeclStmt(d); + } + + // -- Expressions -- + override ExprT actOnNumericConstant(Token c) + { + return new IntegerLit(c); + } + + override ExprT actOnIdentifierExp(Id id) + { + return new Identifier(id.tok); + } + + override ExprT actOnBinaryOp(Operator op, ExprT l, ExprT r) + { + Exp left = cast(Exp)l; + Exp right = cast(Exp)r; + if (op == Operator.Assign) + return new AssignExp(left, right); + else + return new BinaryExp(cast(BinaryExp.Operator)op, left, right); + } + + override ExprT actOnUnaryOp(Token op, ExprT operand) + { + Exp target = cast(Exp)operand; + // can only be -x for now + return new NegateExp(target); + } + + override ExprT actOnCallExpr(ExprT fn, ref Token, ExprT[] args, ref Token) + { + Exp f = cast(Exp)fn; + Exp[] arguments = cast(Exp[])args.dup; + return new CallExp(f, arguments); + } +}