diff --git a/src/comp/back/abi.rs b/src/comp/back/abi.rs index 1a349a7b8db..ad4c066e361 100644 --- a/src/comp/back/abi.rs +++ b/src/comp/back/abi.rs @@ -36,6 +36,18 @@ const int worst_case_glue_call_args = 7; const int n_upcall_glues = 7; +fn upcall_glue_name(int n) -> str { + ret "rust_upcall_" + util.common.istr(n); +} + +fn activate_glue_name() -> str { + ret "rust_activate_glue"; +} + +fn yield_glue_name() -> str { + ret "rust_yield_glue"; +} + // // Local Variables: // mode: rust diff --git a/src/comp/back/x86.rs b/src/comp/back/x86.rs index bfe502009c7..b3edcae6f0a 100644 --- a/src/comp/back/x86.rs +++ b/src/comp/back/x86.rs @@ -121,7 +121,7 @@ fn decl_glue(int align, str prefix, str name, vec[str] insns) -> str { fn decl_upcall_glue(int align, str prefix, uint n) -> str { let int i = n as int; ret decl_glue(align, prefix, - "rust_upcall_" + istr(i), + abi.upcall_glue_name(i), upcall_glue(i)); } @@ -131,11 +131,11 @@ fn get_module_asm() -> str { auto glues = vec(decl_glue(align, prefix, - "rust_activate_glue", + abi.activate_glue_name(), rust_activate_glue()), decl_glue(align, prefix, - "rust_yield_glue", + abi.yield_glue_name(), rust_yield_glue())) + _vec.init_fn[str](bind decl_upcall_glue(align, prefix, _), diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 704c6092db5..ac8dd76f3d9 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -41,7 +41,6 @@ const uint LLVMColdCallConv = 9u; const uint LLVMX86StdcallCallConv = 64u; const uint LLVMX86FastcallCallConv = 65u; - native mod llvm = llvm_lib { type ModuleRef; @@ -96,6 +95,14 @@ native mod llvm = llvm_lib { /** See Module::setModuleInlineAsm. */ fn LLVMSetModuleInlineAsm(ModuleRef M, sbuf Asm); + /** See llvm::LLVMTypeKind::getTypeID. */ + + // FIXME: returning int rather than TypeKind because + // we directly inspect the values, and casting from + // a native doesn't work yet (only *to* a native). + + fn LLVMGetTypeKind(TypeRef Ty) -> int; + /** See llvm::LLVMType::getContext. */ fn LLVMGetTypeContext(TypeRef Ty) -> ContextRef; @@ -213,7 +220,9 @@ native mod llvm = llvm_lib { /* Operations on scalar constants */ fn LLVMConstInt(TypeRef IntTy, ULongLong N, Bool SignExtend) -> ValueRef; - fn LLVMConstIntOfString(TypeRef IntTy, sbuf Text, u8 Radix) -> ValueRef; + // FIXME: radix is actually u8, but our native layer can't handle this + // yet. lucky for us we're little-endian. Small miracles. + fn LLVMConstIntOfString(TypeRef IntTy, sbuf Text, int Radix) -> ValueRef; fn LLVMConstIntOfStringAndSize(TypeRef IntTy, sbuf Text, uint SLen, u8 Radix) -> ValueRef; fn LLVMConstReal(TypeRef RealTy, f64 N) -> ValueRef; @@ -1041,6 +1050,82 @@ obj builder(BuilderRef B) { } } +fn type_to_str(TypeRef ty) -> str { + let int kind = llvm.LLVMGetTypeKind(ty); + + fn tys_str(vec[TypeRef] tys) -> str { + let str s = ""; + let bool first = true; + for (TypeRef t in tys) { + if (first) { + first = false; + } else { + s += ", "; + } + s += type_to_str(t); + } + ret s; + } + + alt (kind) { + + // FIXME: more enum-as-int constants determined from Core.h; + // horrible, horrible. Complete as needed. + + case (0) { ret "Void"; } + case (1) { ret "Float"; } + case (2) { ret "Double"; } + case (3) { ret "X86_FP80"; } + case (4) { ret "FP128"; } + case (5) { ret "PPC_FP128"; } + case (6) { ret "Label"; } + + case (7) { + ret "i" + util.common.istr(llvm.LLVMGetIntTypeWidth(ty) as int); + } + + case (8) { + auto s = "fn("; + let TypeRef out_ty = llvm.LLVMGetReturnType(ty); + let uint n_args = llvm.LLVMCountParamTypes(ty); + let vec[TypeRef] args = + _vec.init_elt[TypeRef](0 as TypeRef, n_args); + llvm.LLVMGetParamTypes(ty, _vec.buf[TypeRef](args)); + s += tys_str(args); + s += ") -> "; + s += type_to_str(out_ty); + ret s; + } + + case (9) { + let str s = "{"; + let uint n_elts = llvm.LLVMCountStructElementTypes(ty); + let vec[TypeRef] elts = + _vec.init_elt[TypeRef](0 as TypeRef, n_elts); + llvm.LLVMGetStructElementTypes(ty, _vec.buf[TypeRef](elts)); + s += tys_str(elts); + s += "}"; + ret s; + } + + case (10) { ret "Array"; } + + case (11) { + ret "*" + type_to_str(llvm.LLVMGetElementType(ty)); + } + + case (12) { ret "Opaque"; } + case (13) { ret "Vector"; } + case (14) { ret "Metadata"; } + case (15) { ret "Union"; } + case (_) { + log "unknown TypeKind" + util.common.istr(kind as int); + fail; + } + } +} + + // // Local Variables: // mode: rust diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 30d721044a6..e2dfc7c1b29 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -33,6 +33,21 @@ type trans_ctxt = rec(session.session sess, @glue_fns glues, str path); +type fn_ctxt = rec(ValueRef llfn, + ValueRef lloutptr, + ValueRef lltaskptr, + @trans_ctxt tcx); + +type terminator = fn(@fn_ctxt cx, builder build); + +type block_ctxt = rec(BasicBlockRef llbb, + builder build, + terminator term, + @fn_ctxt fcx); + + +// LLVM type constructors. + fn T_nil() -> TypeRef { ret llvm.LLVMVoidType(); } @@ -67,9 +82,38 @@ fn T_task() -> TypeRef { T_opaque())); // Rest is opaque for now } + +// LLVM constant constructors. + +fn C_null(TypeRef t) -> ValueRef { + ret llvm.LLVMConstNull(t); +} + +fn C_int(int i) -> ValueRef { + // FIXME. We can't use LLVM.ULongLong with our existing minimal native + // API, which only knows word-sized args. Lucky for us LLVM has a "take a + // string encoding" version. Hilarious. Please fix to handle: + // + // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False); + // + ret llvm.LLVMConstIntOfString(T_int(), + _str.buf(istr(i)), 10); +} + +fn C_str(str s) -> ValueRef { + ret llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False); +} + +fn C_struct(vec[ValueRef] elts) -> ValueRef { + ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts), + _vec.len[ValueRef](elts), + False); +} + fn decl_cdecl_fn(ModuleRef llmod, str name, vec[TypeRef] inputs, TypeRef output) -> ValueRef { let TypeRef llty = T_fn(inputs, output); + log "declaring " + name + " with type " + lib.llvm.type_to_str(llty); let ValueRef llfn = llvm.LLVMAddFunction(llmod, _str.buf(name), llty); llvm.LLVMSetFunctionCallConv(llfn, lib.llvm.LLVMCCallConv); @@ -82,7 +126,7 @@ fn decl_glue(ModuleRef llmod, str s) -> ValueRef { fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef { let int n = _n as int; - let str s = "rust_upcall_" + istr(n); + let str s = abi.upcall_glue_name(n); let vec[TypeRef] args = vec(T_ptr(T_task()), // taskptr T_int()) // callee @@ -91,9 +135,7 @@ fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef { ret decl_cdecl_fn(llmod, s, args, T_int()); } -type terminator = fn(&trans_ctxt cx, builder b); - -fn get_upcall(&trans_ctxt cx, str name, int n_args) -> ValueRef { +fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef { if (cx.upcalls.contains_key(name)) { ret cx.upcalls.get(name); } @@ -105,61 +147,87 @@ fn get_upcall(&trans_ctxt cx, str name, int n_args) -> ValueRef { ret f; } -fn trans_log(&trans_ctxt cx, builder b, &ast.atom a) { +fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef { + let int n = _vec.len[ValueRef](args) as int; + let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n); + llupcall = llvm.LLVMConstPointerCast(llupcall, T_int()); + + let ValueRef llglue = cx.fcx.tcx.glues.upcall_glues.(n); + let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall) + args; + log "emitting indirect-upcall via " + abi.upcall_glue_name(n); + for (ValueRef v in call_args) { + log "arg: " + lib.llvm.type_to_str(llvm.LLVMTypeOf(v)); + } + log "emitting call to callee of type: " + + lib.llvm.type_to_str(llvm.LLVMTypeOf(llglue)); + ret cx.build.Call(llglue, call_args); +} + +fn trans_log(@block_ctxt cx, &ast.atom a) { alt (a) { case (ast.atom_lit(?lit)) { alt (*lit) { case (ast.lit_int(?i)) { - cx.sess.unimpl("log int"); + trans_upcall(cx, "upcall_log_int", vec(C_int(i))); } case (_) { - cx.sess.unimpl("literal variant in trans_log"); + cx.fcx.tcx.sess.unimpl("literal variant in trans_log"); } } } case (_) { - cx.sess.unimpl("atom variant in trans_log"); + cx.fcx.tcx.sess.unimpl("atom variant in trans_log"); } } } -fn trans_stmt(&trans_ctxt cx, builder b, &ast.stmt s, terminator t) { +fn trans_stmt(@block_ctxt cx, &ast.stmt s) { alt (s) { case (ast.stmt_log(?a)) { - trans_log(cx, b, *a); + trans_log(cx, *a); } case (_) { - cx.sess.unimpl("stmt variant"); + cx.fcx.tcx.sess.unimpl("stmt variant"); } } } -fn default_terminate(&trans_ctxt cx, builder b) { - b.RetVoid(); +fn default_terminate(@fn_ctxt cx, builder build) { + build.RetVoid(); } -fn trans_block(&trans_ctxt cx, ValueRef llfn, &ast.block b, terminator t) { +fn trans_block(@fn_ctxt cx, &ast.block b, terminator term) { let BasicBlockRef llbb = - llvm.LLVMAppendBasicBlock(llfn, _str.buf("")); + llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf("")); let BuilderRef llbuild = llvm.LLVMCreateBuilder(); llvm.LLVMPositionBuilderAtEnd(llbuild, llbb); - auto bld = builder(llbuild); + auto bcx = @rec(llbb=llbb, + build=builder(llbuild), + term=term, + fcx=cx); for (@ast.stmt s in b) { - trans_stmt(cx, bld, *s, t); + trans_stmt(bcx, *s); } - t(cx, bld); + bcx.term(cx, bcx.build); } -fn trans_fn(&trans_ctxt cx, &ast._fn f) { - let vec[TypeRef] args = vec(); +fn trans_fn(@trans_ctxt cx, &ast._fn f) { + let vec[TypeRef] args = vec(T_ptr(T_int()), // outptr. + T_ptr(T_task()) // taskptr + ); let ValueRef llfn = decl_cdecl_fn(cx.llmod, cx.path, args, T_nil()); + let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u); + let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u); + auto fcx = @rec(llfn=llfn, + lloutptr=lloutptr, + lltaskptr=lltaskptr, + tcx=cx); auto term = default_terminate; - - trans_block(cx, llfn, f.body, term); + trans_block(fcx, f.body, term); } -fn trans_item(&trans_ctxt cx, &str name, &ast.item item) { - auto sub_cx = rec(path=cx.path + "." + name with cx); +fn trans_item(@trans_ctxt cx, &str name, &ast.item item) { + auto sub_cx = @rec(path=cx.path + "." + name with *cx); alt (item) { case (ast.item_fn(?f)) { trans_fn(sub_cx, *f); @@ -170,7 +238,7 @@ fn trans_item(&trans_ctxt cx, &str name, &ast.item item) { } } -fn trans_mod(&trans_ctxt cx, &ast._mod m) { +fn trans_mod(@trans_ctxt cx, &ast._mod m) { for each (tup(str, ast.item) pair in m.items()) { trans_item(cx, pair._0, pair._1); } @@ -183,17 +251,18 @@ fn trans_crate(session.session sess, ast.crate crate) { llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm())); - auto glues = @rec(activate_glue = decl_glue(llmod, "rust_activate_glue"), - yield_glue = decl_glue(llmod, "rust_yield_glue"), + auto glues = @rec(activate_glue = decl_glue(llmod, + abi.activate_glue_name()), + yield_glue = decl_glue(llmod, abi.yield_glue_name()), upcall_glues = _vec.init_fn[ValueRef](bind decl_upcall(llmod, _), abi.n_upcall_glues as uint)); - auto cx = rec(sess = sess, - llmod = llmod, - upcalls = new_str_hash[ValueRef](), - glues = glues, - path = ""); + auto cx = @rec(sess = sess, + llmod = llmod, + upcalls = new_str_hash[ValueRef](), + glues = glues, + path = ""); trans_mod(cx, crate.module); diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index cf2c25ae8c2..76b8fd624bc 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -30,6 +30,7 @@ mod util { auth driver.rustc.main = state; auth middle.trans = unsafe; +auth lib.llvm = unsafe; mod lib {