diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index b090fb74644..c0fe027f39b 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -234,9 +234,11 @@ native mod llvm { /* Operations on other types */ fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; + fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef; fn LLVMVoidType() -> TypeRef; fn LLVMLabelType() -> TypeRef; + fn LLVMMetadataType() -> TypeRef; /* Operations on all values */ fn LLVMTypeOf(Val: ValueRef) -> TypeRef; diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs index 72390a23383..9379c42623c 100644 --- a/src/comp/middle/debuginfo.rs +++ b/src/comp/middle/debuginfo.rs @@ -1,12 +1,13 @@ -import std::{vec, str, map, option, unsafe}; -import std::vec::to_ptr; +import std::{vec, str, option, unsafe, fs}; import std::map::hashmap; import lib::llvm::llvm; -import lib::llvm::llvm::{ModuleRef, ValueRef}; +import lib::llvm::llvm::ValueRef; import middle::trans_common::*; +import middle::ty; +import ast::ty; import syntax::{ast, codemap}; -const LLVMDebugVersion: int = 0x80000; +const LLVMDebugVersion: int = (9 << 16); //& 0xffff0000; // 0x80000 ? const DW_LANG_RUST: int = 0x9000; const DW_VIRTUALITY_none: int = 0; @@ -14,6 +15,18 @@ const DW_VIRTUALITY_none: int = 0; const CompileUnitTag: int = 17; const FileDescriptorTag: int = 41; const SubprogramTag: int = 46; +const BasicTypeDescriptorTag: int = 36; +const AutoVariableTag: int = 256; +const ArgVariableTag: int = 257; +const ReturnVariableTag: int = 258; +const LexicalBlockTag: int = 11; + +const DW_ATE_boolean: int = 0x02; +const DW_ATE_float: int = 0x04; +const DW_ATE_signed: int = 0x05; +const DW_ATE_signed_char: int = 0x06; +const DW_ATE_unsigned: int = 0x07; +const DW_ATE_unsigned_char: int = 0x08; fn as_buf(s: str) -> str::sbuf { str::as_buf(s, {|sbuf| sbuf}) @@ -23,11 +36,14 @@ fn llstr(s: str) -> ValueRef { } fn lltag(lltag: int) -> ValueRef { - lli32(0x80000 + lltag) + lli32(LLVMDebugVersion | lltag) } fn lli32(val: int) -> ValueRef { C_i32(val as i32) } +fn lli64(val: int) -> ValueRef { + C_i64(val as i64) +} fn lli1(bval: bool) -> ValueRef { C_bool(bval) } @@ -38,6 +54,9 @@ fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe { fn llunused() -> ValueRef { lli32(0x0) } +fn llnull() -> ValueRef { + C_null(T_ptr(T_nil())) +} fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) { let existing = if cache.contains_key(mdtag) { @@ -55,6 +74,9 @@ type metadata = {node: ValueRef, data: T}; type file_md = {path: str}; type compile_unit_md = {path: str}; type subprogram_md = {name: str, file: str}; +type local_var_md = {id: ast::node_id}; +type tydesc_md = {hash: uint}; +type block_md = {start: codemap::loc, end: codemap::loc}; type metadata_cache = hashmap; @@ -62,18 +84,31 @@ tag debug_metadata { file_metadata(@metadata); compile_unit_metadata(@metadata); subprogram_metadata(@metadata); + local_var_metadata(@metadata); + tydesc_metadata(@metadata); + block_metadata(@metadata); +} + +fn cast_safely(val: T) -> U unsafe { + let val2 = val; + let val3 = unsafe::reinterpret_cast(val2); + unsafe::leak(val2); + ret val3; } fn md_from_metadata(val: debug_metadata) -> T unsafe { alt val { - file_metadata(md) { unsafe::reinterpret_cast(md) } - compile_unit_metadata(md) { unsafe::reinterpret_cast(md) } - subprogram_metadata(md) { unsafe::reinterpret_cast(md) } + file_metadata(md) { cast_safely(md) } + compile_unit_metadata(md) { cast_safely(md) } + subprogram_metadata(md) { cast_safely(md) } + local_var_metadata(md) { cast_safely(md) } + tydesc_metadata(md) { cast_safely(md) } + block_metadata(md) { cast_safely(md) } } } fn cached_metadata(cache: metadata_cache, mdtag: int, - eq: block(md: T) -> bool) -> option::t { + eq: block(md: T) -> bool) -> option::t unsafe { if cache.contains_key(mdtag) { let items = cache.get(mdtag); for item in items { @@ -94,10 +129,8 @@ fn get_compile_unit_metadata(cx: @crate_ctxt, full_path: str) option::some(md) { ret md; } option::none. {} } - let sep = str::rindex(full_path, '/' as u8) as uint; - let fname = str::slice(full_path, sep + 1u, - str::byte_len(full_path)); - let path = str::slice(full_path, 0u, sep + 1u); + let fname = fs::basename(full_path); + let path = fs::dirname(full_path); let unit_metadata = [lltag(CompileUnitTag), llunused(), lli32(DW_LANG_RUST), @@ -122,22 +155,18 @@ fn get_compile_unit_metadata(cx: @crate_ctxt, full_path: str) ret mdval; } -// let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"), -// str::byte_len("dbg")); - - fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata { let cache = cx.llmetadata; alt cached_metadata::<@metadata>( - cache, FileDescriptorTag, {|md| md.data.path == full_path}) { + cache, FileDescriptorTag, + {|md| + md.data.path == full_path}) { option::some(md) { ret md; } option::none. {} } - let sep = str::rindex(full_path, '/' as u8) as uint; - let fname = str::slice(full_path, sep + 1u, - str::byte_len(full_path)); - let path = str::slice(full_path, 0u, sep + 1u); - let unit_node = get_compile_unit_metadata(cx, path).node; + let fname = fs::basename(full_path); + let path = fs::dirname(full_path); + let unit_node = get_compile_unit_metadata(cx, full_path).node; let file_md = [lltag(FileDescriptorTag), llstr(fname), llstr(path), @@ -148,6 +177,162 @@ fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata { ret mdval; } +fn get_block_metadata(cx: @block_ctxt) -> @metadata { + let cache = bcx_ccx(cx).llmetadata; + let start = codemap::lookup_char_pos(bcx_ccx(cx).sess.get_codemap(), + cx.sp.lo); + let fname = start.filename; + let end = codemap::lookup_char_pos(bcx_ccx(cx).sess.get_codemap(), + cx.sp.hi); + alt cached_metadata::<@metadata>( + cache, LexicalBlockTag, + {|md| start == md.data.start && end == md.data.end}) { + option::some(md) { ret md; } + option::none. {} + } + let parent = alt cx.parent { + trans_common::parent_none. { llnull() } + trans_common::parent_some(bcx) { + get_block_metadata(bcx).node + } + }; + let file_node = get_file_metadata(bcx_ccx(cx), fname); + let unique_id = alt cache.find(LexicalBlockTag) { + option::some(v) { vec::len(v) as int } + option::none. { 0 } + }; + let lldata = [lltag(LexicalBlockTag), + parent, + lli32(start.line as int), + lli32(start.col as int), + file_node.node, + lli32(unique_id) + ]; + let val = llmdnode(lldata); + let mdval = @{node: val, data: {start: start, end: end}}; + update_cache(cache, LexicalBlockTag, block_metadata(mdval)); + ret mdval; +} + +fn get_ty_metadata(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) -> @metadata { + let cache = cx.llmetadata; + alt cached_metadata::<@metadata>( + cache, BasicTypeDescriptorTag, + {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) { + option::some(md) { ret md; } + option::none. {} + } + let (name, size, flags) = alt ty.node { + ast::ty_bool. { ("bool", 1, DW_ATE_boolean) } + ast::ty_int. { ("int", 32, DW_ATE_signed) } //XXX machine-dependent? + ast::ty_uint. { ("uint", 32, DW_ATE_unsigned) } //XXX machine-dependent? + ast::ty_float. { ("float", 32, DW_ATE_float) } //XXX machine-dependent? + ast::ty_machine(m) { alt m { + ast::ty_i8. { ("i8", 1, DW_ATE_signed_char) } + ast::ty_i16. { ("i16", 16, DW_ATE_signed) } + ast::ty_i32. { ("i32", 32, DW_ATE_signed) } + ast::ty_i64. { ("i64", 64, DW_ATE_signed) } + ast::ty_u8. { ("u8", 8, DW_ATE_unsigned_char) } + ast::ty_u16. { ("u16", 16, DW_ATE_unsigned) } + ast::ty_u32. { ("u32", 32, DW_ATE_unsigned) } + ast::ty_u64. { ("u64", 64, DW_ATE_unsigned) } + ast::ty_f32. { ("f32", 32, DW_ATE_float) } + ast::ty_f64. { ("f64", 64, DW_ATE_float) } + } } + ast::ty_char. { ("char", 32, DW_ATE_unsigned) } + }; + let lldata = [lltag(BasicTypeDescriptorTag), + llunused(), //XXX scope context + llstr(name), + llnull(), //XXX basic types only + lli32(0), //XXX basic types only + lli64(size), + lli64(32), //XXX alignment? + lli64(0), //XXX offset? + lli32(flags)]; + let llnode = llmdnode(lldata); + let mdval = @{node: llnode, data: {hash: ty::hash_ty(t)}}; + update_cache(cache, BasicTypeDescriptorTag, tydesc_metadata(mdval)); + ret mdval; +} + +fn get_local_var_metadata(bcx: @block_ctxt, local: @ast::local) + -> @metadata unsafe { + let cx = bcx_ccx(bcx); + let cache = cx.llmetadata; + alt cached_metadata::<@metadata>( + cache, AutoVariableTag, {|md| md.data.id == local.node.id}) { + option::some(md) { ret md; } + option::none. {} + } + let name = alt local.node.pat.node { + ast::pat_bind(ident) { ident } + }; + let loc = codemap::lookup_char_pos(cx.sess.get_codemap(), + local.span.lo); + let ty = trans::node_id_type(cx, local.node.id); + let tymd = get_ty_metadata(cx, ty, local.node.ty); + let filemd = get_file_metadata(cx, loc.filename); + let blockmd = get_block_metadata(bcx); + let lldata = [lltag(AutoVariableTag), + blockmd.node, //XXX block context (maybe subprogram if possible?) + llstr(name), // name + filemd.node, + lli32(loc.line as int), // line + tymd.node, + lli32(0), //XXX flags + llnull() // inline loc reference + ]; + let mdnode = llmdnode(lldata); + let mdval = @{node: mdnode, data: {id: local.node.id}}; + update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); + let llptr = alt bcx.fcx.lllocals.find(local.node.id) { + option::some(local_mem(v)) { v } + option::none. { + alt bcx.fcx.lllocals.get(local.node.pat.id) { + local_imm(v) { v } + } + } + }; + let declargs = [llmdnode([llptr]), mdnode]; + let instr = trans_build::Call(bcx, cx.intrinsics.get("llvm.dbg.declare"), + declargs); + llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.vars"), + str::byte_len("llvm.dbg.vars"), + mdnode); + ret mdval; +} + +fn update_source_pos(cx: @block_ctxt, s: T) { + if !bcx_ccx(cx).sess.get_opts().debuginfo { + ret; + } + cx.source_pos = option::some( + codemap::lookup_char_pos(bcx_ccx(cx).sess.get_codemap(), + s.span.lo)); //XXX maybe hi + +} + +fn reset_source_pos(cx: @block_ctxt) { + cx.source_pos = option::none; +} + +fn add_line_info(cx: @block_ctxt, llinstr: ValueRef) { + if !bcx_ccx(cx).sess.get_opts().debuginfo || + option::is_none(cx.source_pos) { + ret; + } + let loc = option::get(cx.source_pos); + let blockmd = get_block_metadata(cx); + let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"), str::byte_len("dbg")); + let scopedata = [lli32(loc.line as int), + lli32(loc.col as int), + blockmd.node, + llnull()]; + let dbgscope = llmdnode(scopedata); + llvm::LLVMSetMetadata(llinstr, kind_id, dbgscope); +} + fn get_function_metadata(cx: @crate_ctxt, item: @ast::item, llfndecl: ValueRef) -> @metadata { let cache = cx.llmetadata; @@ -159,34 +344,43 @@ fn get_function_metadata(cx: @crate_ctxt, item: @ast::item, } let loc = codemap::lookup_char_pos(cx.sess.get_codemap(), item.span.lo); - let file_node = get_file_metadata(cx, loc.filename).node; - let fn_metadata = [lltag(SubprogramTag), - llunused(), - file_node, - llstr(item.ident), - llstr(item.ident), //XXX fully-qualified C++ name - llstr(item.ident), //XXX MIPS name????? - file_node, - lli32(loc.line as int), - C_null(T_ptr(T_nil())), // XXX reference to tydesc - lli1(false), //XXX static - lli1(true), // not extern - lli32(DW_VIRTUALITY_none), // virtual-ness - lli32(0i), //index into virt func - C_null(T_ptr(T_nil())), // base type with vtbl - lli1(false), // artificial - lli1(cx.sess.get_opts().optimize != 0u), - llfndecl - //list of template params - //func decl descriptor - //list of func vars - ]; - let val = llmdnode(fn_metadata); - llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.sp"), - str::byte_len("llvm.dbg.sp"), - val); - let mdval = @{node: val, data: {name: item.ident, - file: loc.filename}}; - update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); - ret mdval; + let file_node = get_file_metadata(cx, loc.filename).node; + let mangled = cx.item_symbols.get(item.id); + let ret_ty = alt item.node { + ast::item_fn(f, _) { f.decl.output } + }; + let ty_node = alt ret_ty.node { + ast::ty_nil. { llnull() } + _ { get_ty_metadata(cx, ty::node_id_to_type(ccx_tcx(cx), item.id), + ret_ty).node } + }; + let fn_metadata = [lltag(SubprogramTag), + llunused(), + file_node, + llstr(item.ident), + llstr(item.ident), //XXX fully-qualified C++ name + llstr(mangled), //XXX MIPS name????? + file_node, + lli32(loc.line as int), + ty_node, + lli1(false), //XXX static (check export) + lli1(true), // not extern + lli32(DW_VIRTUALITY_none), // virtual-ness + lli32(0i), //index into virt func + llnull(), // base type with vtbl + lli1(false), // artificial + lli1(cx.sess.get_opts().optimize != 0u), + llfndecl + //list of template params + //func decl descriptor + //list of func vars + ]; + let val = llmdnode(fn_metadata); + llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.sp"), + str::byte_len("llvm.dbg.sp"), + val); + let mdval = @{node: val, data: {name: item.ident, + file: loc.filename}}; + update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); + ret mdval; } \ No newline at end of file diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6985ef974e6..551ac18a1b2 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3519,6 +3519,8 @@ fn trans_temp_expr(bcx: @block_ctxt, e: @ast::expr) -> result { // - exprs with non-immediate type never get dest=by_val fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { let tcx = bcx_tcx(bcx); + debuginfo::update_source_pos(bcx, e); + if expr_is_lval(bcx, e) { ret lval_to_dps(bcx, e, dest); } @@ -4012,6 +4014,8 @@ fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt { } let bcx = cx; + debuginfo::update_source_pos(cx, s); + alt s.node { ast::stmt_expr(e, _) { bcx = trans_expr(cx, e, ignore); } ast::stmt_decl(d, _) { @@ -4023,6 +4027,9 @@ fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt { } else { bcx = init_ref_local(bcx, local); } + if bcx_ccx(cx).sess.get_opts().debuginfo { + debuginfo::get_local_var_metadata(bcx, local); + } } } ast::decl_item(i) { trans_item(cx.fcx.lcx, *i); } @@ -4030,6 +4037,8 @@ fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt { } _ { bcx_ccx(cx).sess.unimpl("stmt variant"); } } + + debuginfo::reset_source_pos(cx); ret bcx; } @@ -4053,7 +4062,8 @@ fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind, mutable lpad_dirty: true, mutable lpad: option::none, sp: cx.sp, - fcx: cx}; + fcx: cx, + mutable source_pos: option::none}; alt parent { parent_some(cx) { if cx.unreachable { Unreachable(bcx); } @@ -4097,7 +4107,8 @@ fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt { mutable lpad_dirty: true, mutable lpad: option::none, sp: fcx.sp, - fcx: fcx}; + fcx: fcx, + mutable source_pos: option::none}; } @@ -4164,7 +4175,8 @@ fn llstaticallocas_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { mutable lpad_dirty: true, mutable lpad: option::none, sp: fcx.sp, - fcx: fcx}; + fcx: fcx, + mutable source_pos: option::none}; } fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { @@ -4177,7 +4189,8 @@ fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { mutable lpad_dirty: true, mutable lpad: option::none, sp: fcx.sp, - fcx: fcx}; + fcx: fcx, + mutable source_pos: option::none}; } @@ -4250,6 +4263,7 @@ fn trans_block(bcx: @block_ctxt, b: ast::blk) -> @block_ctxt { fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest) -> @block_ctxt { let bcx = bcx; + debuginfo::update_source_pos(bcx, b); block_locals(b) {|local| bcx = alloc_local(bcx, local); }; for s: @ast::stmt in b.node.stmts { bcx = trans_stmt(bcx, *s); @@ -4261,7 +4275,9 @@ fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest) } _ { assert dest == ignore || bcx.unreachable; } } - ret trans_block_cleanups(bcx, find_scope_cx(bcx)); + let rv = trans_block_cleanups(bcx, find_scope_cx(bcx)); + debuginfo::reset_source_pos(bcx); + ret rv; } fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt { @@ -5465,6 +5481,18 @@ fn declare_intrinsics(llmod: ModuleRef) -> hashmap { ret intrinsics; } +fn declare_dbg_intrinsics(llmod: ModuleRef, + intrinsics: hashmap) { + let declare = + decl_cdecl_fn(llmod, "llvm.dbg.declare", + T_fn([T_metadata(), T_metadata()], T_void())); + let value = + decl_cdecl_fn(llmod, "llvm.dbg.value", + T_fn([T_metadata(), T_i64(), T_metadata()], T_void())); + intrinsics.insert("llvm.dbg.declare", declare); + intrinsics.insert("llvm.dbg.value", value); +} + fn trap(bcx: @block_ctxt) { let v: [ValueRef] = []; alt bcx_ccx(bcx).intrinsics.find("llvm.trap") { @@ -5601,6 +5629,9 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, let td = mk_target_data(sess.get_targ_cfg().target_strs.data_layout); let tn = mk_type_names(); let intrinsics = declare_intrinsics(llmod); + if sess.get_opts().debuginfo { + declare_dbg_intrinsics(llmod, intrinsics); + } let int_type = T_int(targ_cfg); let float_type = T_float(targ_cfg); let task_type = T_task(targ_cfg); diff --git a/src/comp/middle/trans_build.rs b/src/comp/middle/trans_build.rs index 210626deffb..26c63290405 100644 --- a/src/comp/middle/trans_build.rs +++ b/src/comp/middle/trans_build.rs @@ -25,14 +25,16 @@ fn RetVoid(cx: @block_ctxt) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildRetVoid(B(cx)); + let instr = llvm::LLVMBuildRetVoid(B(cx)); + debuginfo::add_line_info(cx, instr); } fn Ret(cx: @block_ctxt, V: ValueRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildRet(B(cx), V); + let instr = llvm::LLVMBuildRet(B(cx), V); + debuginfo::add_line_info(cx, instr); } fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) { @@ -40,8 +42,9 @@ fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) { assert (!cx.terminated); cx.terminated = true; unsafe { - llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), - vec::len(RetVals)); + let instr = llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), + vec::len(RetVals)); + debuginfo::add_line_info(cx, instr); } } @@ -49,7 +52,8 @@ fn Br(cx: @block_ctxt, Dest: BasicBlockRef) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildBr(B(cx), Dest); + let instr = llvm::LLVMBuildBr(B(cx), Dest); + debuginfo::add_line_info(cx, instr); } fn CondBr(cx: @block_ctxt, If: ValueRef, Then: BasicBlockRef, @@ -57,7 +61,8 @@ fn CondBr(cx: @block_ctxt, If: ValueRef, Then: BasicBlockRef, if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildCondBr(B(cx), If, Then, Else); + let instr = llvm::LLVMBuildCondBr(B(cx), If, Then, Else); + debuginfo::add_line_info(cx, instr); } fn Switch(cx: @block_ctxt, V: ValueRef, Else: BasicBlockRef, NumCases: uint) @@ -65,7 +70,9 @@ fn Switch(cx: @block_ctxt, V: ValueRef, Else: BasicBlockRef, NumCases: uint) if cx.unreachable { ret _Undef(V); } assert !cx.terminated; cx.terminated = true; - ret llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases); + let instr = llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases); + debuginfo::add_line_info(cx, instr); + ret instr; } fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) { @@ -77,7 +84,8 @@ fn IndirectBr(cx: @block_ctxt, Addr: ValueRef, NumDests: uint) { if cx.unreachable { ret; } assert (!cx.terminated); cx.terminated = true; - llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests); + let instr = llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests); + debuginfo::add_line_info(cx, instr); } // This is a really awful way to get a zero-length c-string, but better (and a @@ -93,8 +101,10 @@ fn Invoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], assert (!cx.terminated); cx.terminated = true; unsafe { - llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), Then, Catch, noname()); + let instr = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), Then, Catch, + noname()); + debuginfo::add_line_info(cx, instr); } } @@ -107,6 +117,7 @@ fn FastInvoke(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), Then, Catch, noname()); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + debuginfo::add_line_info(cx, v); } } @@ -123,183 +134,254 @@ fn _Undef(val: ValueRef) -> ValueRef { /* Arithmetic */ fn Add(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NSWAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NUWAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Sub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSub(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildSub(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NSWSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NUWSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Mul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildMul(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildMul(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NSWMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NUWMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn UDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ExactSDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn URem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildURem(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildURem(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SRem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FRem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Shl(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildShl(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildShl(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn LShr(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn AShr(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn And(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Or(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildOr(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildOr(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Xor(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildXor(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildXor(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn BinOp(cx: @block_ctxt, Op: Opcode, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(LHS); } - ret llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname()); + let instr = llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Neg(cx: @block_ctxt, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNeg(B(cx), V, noname()); + let instr = llvm::LLVMBuildNeg(B(cx), V, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NSWNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNSWNeg(B(cx), V, noname()); + let instr = llvm::LLVMBuildNSWNeg(B(cx), V, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn NUWNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNUWNeg(B(cx), V, noname()); + let instr = llvm::LLVMBuildNUWNeg(B(cx), V, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildFNeg(B(cx), V, noname()); + let instr = llvm::LLVMBuildFNeg(B(cx), V, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Not(cx: @block_ctxt, V: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(V); } - ret llvm::LLVMBuildNot(B(cx), V, noname()); + let instr = llvm::LLVMBuildNot(B(cx), V, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } /* Memory */ fn Malloc(cx: @block_ctxt, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildMalloc(B(cx), Ty, noname()); + let instr = llvm::LLVMBuildMalloc(B(cx), Ty, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ArrayMalloc(cx: @block_ctxt, Ty: TypeRef, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname()); + let instr = llvm::LLVMBuildArrayMalloc(B(cx), Ty, Val, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Alloca(cx: @block_ctxt, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } - ret llvm::LLVMBuildAlloca(B(cx), Ty, noname()); + let instr = llvm::LLVMBuildAlloca(B(cx), Ty, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ArrayAlloca(cx: @block_ctxt, Ty: TypeRef, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } - ret llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname()); + let instr = llvm::LLVMBuildArrayAlloca(B(cx), Ty, Val, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Free(cx: @block_ctxt, PointerVal: ValueRef) { if cx.unreachable { ret; } - llvm::LLVMBuildFree(B(cx), PointerVal); + let instr = llvm::LLVMBuildFree(B(cx), PointerVal); + debuginfo::add_line_info(cx, instr); } fn Load(cx: @block_ctxt, PointerVal: ValueRef) -> ValueRef { @@ -310,19 +392,24 @@ fn Load(cx: @block_ctxt, PointerVal: ValueRef) -> ValueRef { llvm::LLVMGetElementType(ty) } else { ccx.int_type }; ret llvm::LLVMGetUndef(eltty); } - ret llvm::LLVMBuildLoad(B(cx), PointerVal, noname()); + let instr = llvm::LLVMBuildLoad(B(cx), PointerVal, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Store(cx: @block_ctxt, Val: ValueRef, Ptr: ValueRef) { if cx.unreachable { ret; } - llvm::LLVMBuildStore(B(cx), Val, Ptr); + let instr = llvm::LLVMBuildStore(B(cx), Val, Ptr); + debuginfo::add_line_info(cx, instr); } fn GEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } unsafe { - ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + let instr = llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), + vec::len(Indices), noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } } @@ -338,142 +425,195 @@ fn InBoundsGEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } unsafe { - ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), - vec::len(Indices), noname()); + let v = llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, + vec::to_ptr(Indices), + vec::len(Indices), noname()); + debuginfo::add_line_info(cx, v); + ret v; } } fn StructGEP(cx: @block_ctxt, Pointer: ValueRef, Idx: uint) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } - ret llvm::LLVMBuildStructGEP(B(cx), Pointer, Idx, noname()); + let instr = llvm::LLVMBuildStructGEP(B(cx), Pointer, Idx, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn GlobalString(cx: @block_ctxt, _Str: sbuf) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildGlobalString(B(cx), _Str, noname()); + let instr = llvm::LLVMBuildGlobalString(B(cx), _Str, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn GlobalStringPtr(cx: @block_ctxt, _Str: sbuf) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } - ret llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname()); + let instr = llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } /* Casts */ fn Trunc(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildTrunc(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ZExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildZExt(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildSExt(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FPToUI(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildFPToUI(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FPToSI(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildFPToSI(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn UIToFP(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildUIToFP(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SIToFP(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildSIToFP(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FPTrunc(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FPExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildFPExt(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn PtrToInt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn IntToPtr(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn BitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildBitCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ZExtOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SExtOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn TruncOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Cast(cx: @block_ctxt, Op: Opcode, Val: ValueRef, DestTy: TypeRef, _Name: sbuf) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname()); + let instr = llvm::LLVMBuildCast(B(cx), Op, Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn PointerCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildPointerCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn IntCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildIntCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FPCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } - ret llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname()); + let instr = llvm::LLVMBuildFPCast(B(cx), Val, DestTy, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } /* Comparisons */ fn ICmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildICmp(B(cx), Op, LHS, RHS, noname()); + let instr = llvm::LLVMBuildICmp(B(cx), Op, LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn FCmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildFCmp(B(cx), Op, LHS, RHS, noname()); + let instr = llvm::LLVMBuildFCmp(B(cx), Op, LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } /* Miscellaneous instructions */ fn EmptyPhi(cx: @block_ctxt, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } - ret llvm::LLVMBuildPhi(B(cx), Ty, noname()); + let instr = llvm::LLVMBuildPhi(B(cx), Ty, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Phi(cx: @block_ctxt, Ty: TypeRef, vals: [ValueRef], bbs: [BasicBlockRef]) @@ -528,8 +668,10 @@ fn add_comment(bcx: @block_ctxt, text: str) { fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { if cx.unreachable { ret _UndefReturn(cx, Fn); } unsafe { - ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), - vec::len(Args), noname()); + let instr = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), + vec::len(Args), noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } } @@ -539,6 +681,7 @@ fn FastCall(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef { let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); + debuginfo::add_line_info(cx, v); ret v; } } @@ -550,6 +693,7 @@ fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), vec::len(Args), noname()); llvm::LLVMSetInstructionCallConv(v, Conv); + debuginfo::add_line_info(cx, v); ret v; } } @@ -557,57 +701,76 @@ fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef], Conv: uint) fn Select(cx: @block_ctxt, If: ValueRef, Then: ValueRef, Else: ValueRef) -> ValueRef { if cx.unreachable { ret _Undef(Then); } - ret llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname()); + let instr = llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn VAArg(cx: @block_ctxt, list: ValueRef, Ty: TypeRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } - ret llvm::LLVMBuildVAArg(B(cx), list, Ty, noname()); + let instr = llvm::LLVMBuildVAArg(B(cx), list, Ty, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn ExtractElement(cx: @block_ctxt, VecVal: ValueRef, Index: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } - ret llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname()); + let instr = llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn InsertElement(cx: @block_ctxt, VecVal: ValueRef, EltVal: ValueRef, Index: ValueRef) { if cx.unreachable { ret; } - llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname()); + let instr = llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, + noname()); + debuginfo::add_line_info(cx, instr); } fn ShuffleVector(cx: @block_ctxt, V1: ValueRef, V2: ValueRef, Mask: ValueRef) { if cx.unreachable { ret; } - llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()); + let instr = llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname()); + debuginfo::add_line_info(cx, instr); } fn ExtractValue(cx: @block_ctxt, AggVal: ValueRef, Index: uint) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } - ret llvm::LLVMBuildExtractValue(B(cx), AggVal, Index, noname()); + let instr = llvm::LLVMBuildExtractValue(B(cx), AggVal, Index, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn InsertValue(cx: @block_ctxt, AggVal: ValueRef, EltVal: ValueRef, Index: uint) { if cx.unreachable { ret; } - llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index, noname()); + let instr = llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index, + noname()); + debuginfo::add_line_info(cx, instr); } fn IsNull(cx: @block_ctxt, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildIsNull(B(cx), Val, noname()); + let instr = llvm::LLVMBuildIsNull(B(cx), Val, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn IsNotNull(cx: @block_ctxt, Val: ValueRef) -> ValueRef { if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } - ret llvm::LLVMBuildIsNotNull(B(cx), Val, noname()); + let instr = llvm::LLVMBuildIsNotNull(B(cx), Val, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn PtrDiff(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { let ccx = cx.fcx.lcx.ccx; if cx.unreachable { ret llvm::LLVMGetUndef(ccx.int_type); } - ret llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname()); + let instr = llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn Trap(cx: @block_ctxt) { @@ -622,15 +785,19 @@ fn Trap(cx: @block_ctxt) { assert (T as int != 0); let Args: [ValueRef] = []; unsafe { - llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), - vec::len(Args), noname()); + let instr = llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), + vec::len(Args), noname()); + debuginfo::add_line_info(cx, instr); } } fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef, NumClauses: uint) -> ValueRef { assert !cx.terminated && !cx.unreachable; - ret llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn, NumClauses, noname()); + let instr = llvm::LLVMBuildLandingPad(B(cx), Ty, PersFn, NumClauses, + noname()); + debuginfo::add_line_info(cx, instr); + ret instr; } fn SetCleanup(_cx: @block_ctxt, LandingPad: ValueRef) { @@ -640,7 +807,9 @@ fn SetCleanup(_cx: @block_ctxt, LandingPad: ValueRef) { fn Resume(cx: @block_ctxt, Exn: ValueRef) -> ValueRef { assert (!cx.terminated); cx.terminated = true; - ret llvm::LLVMBuildResume(B(cx), Exn); + let instr = llvm::LLVMBuildResume(B(cx), Exn); + debuginfo::add_line_info(cx, instr); + ret instr; } // diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index a4f0a6dfe3d..98c4b497ab5 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -385,7 +385,8 @@ type block_ctxt = mutable lpad_dirty: bool, mutable lpad: option::t, sp: span, - fcx: @fn_ctxt}; + fcx: @fn_ctxt, + mutable source_pos: option::t}; // FIXME: we should be able to use option::t<@block_parent> here but // the infinite-tag check in rustboot gets upset. @@ -464,6 +465,8 @@ fn T_nil() -> TypeRef { ret llvm::LLVMInt1Type(); } +fn T_metadata() -> TypeRef { ret llvm::LLVMMetadataType(); } + fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); } fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); } @@ -801,6 +804,10 @@ fn C_i32(i: i32) -> ValueRef { ret C_integral(T_i32(), i as u64, True); } +fn C_i64(i: i64) -> ValueRef { + ret C_integral(T_i64(), i as uint, True); +} + fn C_int(cx: @crate_ctxt, i: int) -> ValueRef { ret C_integral(cx.int_type, i as u64, True); } diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 1a34f62f7a0..8c5c2385c9b 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -60,6 +60,7 @@ LLVMAddLoopRotatePass LLVMAddLoopUnrollPass LLVMAddLoopUnswitchPass LLVMAddMemCpyOptPass +LLVMAddNamedMetadataOperand LLVMAddPromoteMemoryToRegisterPass LLVMAddPruneEHPass LLVMAddReassociatePass @@ -483,11 +484,15 @@ LLVMIsThreadLocal LLVMIsUndef LLVMLabelType LLVMLabelTypeInContext +LLVMLinkInInterpreter +LLVMLinkInJIT +LLVMLinkInMCJIT LLVMMDNode LLVMMDNodeInContext LLVMMDString LLVMMDStringInContext -LLVMAddNamedMetadataOperand +LLVMMetadataType +LLVMMetadataTypeInContext LLVMModuleCreateWithName LLVMModuleCreateWithNameInContext LLVMMoveBasicBlockAfter