Add debug info for local vars, basic fundamental types, and lexical blocks, along with source line information generation for individual instructions.

This commit is contained in:
Josh Matthews 2011-11-15 21:11:22 -05:00
parent 10030a37d5
commit e383004985
6 changed files with 561 additions and 153 deletions

View file

@ -234,9 +234,11 @@ native mod llvm {
/* Operations on other types */ /* Operations on other types */
fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef;
fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef;
fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef;
fn LLVMVoidType() -> TypeRef; fn LLVMVoidType() -> TypeRef;
fn LLVMLabelType() -> TypeRef; fn LLVMLabelType() -> TypeRef;
fn LLVMMetadataType() -> TypeRef;
/* Operations on all values */ /* Operations on all values */
fn LLVMTypeOf(Val: ValueRef) -> TypeRef; fn LLVMTypeOf(Val: ValueRef) -> TypeRef;

View file

@ -1,12 +1,13 @@
import std::{vec, str, map, option, unsafe}; import std::{vec, str, option, unsafe, fs};
import std::vec::to_ptr;
import std::map::hashmap; import std::map::hashmap;
import lib::llvm::llvm; import lib::llvm::llvm;
import lib::llvm::llvm::{ModuleRef, ValueRef}; import lib::llvm::llvm::ValueRef;
import middle::trans_common::*; import middle::trans_common::*;
import middle::ty;
import ast::ty;
import syntax::{ast, codemap}; import syntax::{ast, codemap};
const LLVMDebugVersion: int = 0x80000; const LLVMDebugVersion: int = (9 << 16); //& 0xffff0000; // 0x80000 ?
const DW_LANG_RUST: int = 0x9000; const DW_LANG_RUST: int = 0x9000;
const DW_VIRTUALITY_none: int = 0; const DW_VIRTUALITY_none: int = 0;
@ -14,6 +15,18 @@ const DW_VIRTUALITY_none: int = 0;
const CompileUnitTag: int = 17; const CompileUnitTag: int = 17;
const FileDescriptorTag: int = 41; const FileDescriptorTag: int = 41;
const SubprogramTag: int = 46; 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 { fn as_buf(s: str) -> str::sbuf {
str::as_buf(s, {|sbuf| sbuf}) str::as_buf(s, {|sbuf| sbuf})
@ -23,11 +36,14 @@ fn llstr(s: str) -> ValueRef {
} }
fn lltag(lltag: int) -> ValueRef { fn lltag(lltag: int) -> ValueRef {
lli32(0x80000 + lltag) lli32(LLVMDebugVersion | lltag)
} }
fn lli32(val: int) -> ValueRef { fn lli32(val: int) -> ValueRef {
C_i32(val as i32) C_i32(val as i32)
} }
fn lli64(val: int) -> ValueRef {
C_i64(val as i64)
}
fn lli1(bval: bool) -> ValueRef { fn lli1(bval: bool) -> ValueRef {
C_bool(bval) C_bool(bval)
} }
@ -38,6 +54,9 @@ fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe {
fn llunused() -> ValueRef { fn llunused() -> ValueRef {
lli32(0x0) lli32(0x0)
} }
fn llnull() -> ValueRef {
C_null(T_ptr(T_nil()))
}
fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) { fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) {
let existing = if cache.contains_key(mdtag) { let existing = if cache.contains_key(mdtag) {
@ -55,6 +74,9 @@ type metadata<T> = {node: ValueRef, data: T};
type file_md = {path: str}; type file_md = {path: str};
type compile_unit_md = {path: str}; type compile_unit_md = {path: str};
type subprogram_md = {name: str, file: 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<int, [debug_metadata]>; type metadata_cache = hashmap<int, [debug_metadata]>;
@ -62,18 +84,31 @@ tag debug_metadata {
file_metadata(@metadata<file_md>); file_metadata(@metadata<file_md>);
compile_unit_metadata(@metadata<compile_unit_md>); compile_unit_metadata(@metadata<compile_unit_md>);
subprogram_metadata(@metadata<subprogram_md>); subprogram_metadata(@metadata<subprogram_md>);
local_var_metadata(@metadata<local_var_md>);
tydesc_metadata(@metadata<tydesc_md>);
block_metadata(@metadata<block_md>);
}
fn cast_safely<T, U>(val: T) -> U unsafe {
let val2 = val;
let val3 = unsafe::reinterpret_cast(val2);
unsafe::leak(val2);
ret val3;
} }
fn md_from_metadata<T>(val: debug_metadata) -> T unsafe { fn md_from_metadata<T>(val: debug_metadata) -> T unsafe {
alt val { alt val {
file_metadata(md) { unsafe::reinterpret_cast(md) } file_metadata(md) { cast_safely(md) }
compile_unit_metadata(md) { unsafe::reinterpret_cast(md) } compile_unit_metadata(md) { cast_safely(md) }
subprogram_metadata(md) { unsafe::reinterpret_cast(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<T>(cache: metadata_cache, mdtag: int, fn cached_metadata<T>(cache: metadata_cache, mdtag: int,
eq: block(md: T) -> bool) -> option::t<T> { eq: block(md: T) -> bool) -> option::t<T> unsafe {
if cache.contains_key(mdtag) { if cache.contains_key(mdtag) {
let items = cache.get(mdtag); let items = cache.get(mdtag);
for item in items { 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::some(md) { ret md; }
option::none. {} option::none. {}
} }
let sep = str::rindex(full_path, '/' as u8) as uint; let fname = fs::basename(full_path);
let fname = str::slice(full_path, sep + 1u, let path = fs::dirname(full_path);
str::byte_len(full_path));
let path = str::slice(full_path, 0u, sep + 1u);
let unit_metadata = [lltag(CompileUnitTag), let unit_metadata = [lltag(CompileUnitTag),
llunused(), llunused(),
lli32(DW_LANG_RUST), lli32(DW_LANG_RUST),
@ -122,22 +155,18 @@ fn get_compile_unit_metadata(cx: @crate_ctxt, full_path: str)
ret mdval; 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<file_md> { fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata<file_md> {
let cache = cx.llmetadata; let cache = cx.llmetadata;
alt cached_metadata::<@metadata<file_md>>( alt cached_metadata::<@metadata<file_md>>(
cache, FileDescriptorTag, {|md| md.data.path == full_path}) { cache, FileDescriptorTag,
{|md|
md.data.path == full_path}) {
option::some(md) { ret md; } option::some(md) { ret md; }
option::none. {} option::none. {}
} }
let sep = str::rindex(full_path, '/' as u8) as uint; let fname = fs::basename(full_path);
let fname = str::slice(full_path, sep + 1u, let path = fs::dirname(full_path);
str::byte_len(full_path)); let unit_node = get_compile_unit_metadata(cx, full_path).node;
let path = str::slice(full_path, 0u, sep + 1u);
let unit_node = get_compile_unit_metadata(cx, path).node;
let file_md = [lltag(FileDescriptorTag), let file_md = [lltag(FileDescriptorTag),
llstr(fname), llstr(fname),
llstr(path), llstr(path),
@ -148,6 +177,162 @@ fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata<file_md> {
ret mdval; ret mdval;
} }
fn get_block_metadata(cx: @block_ctxt) -> @metadata<block_md> {
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<block_md>>(
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<tydesc_md> {
let cache = cx.llmetadata;
alt cached_metadata::<@metadata<tydesc_md>>(
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<local_var_md> unsafe {
let cx = bcx_ccx(bcx);
let cache = cx.llmetadata;
alt cached_metadata::<@metadata<local_var_md>>(
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<T>(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, fn get_function_metadata(cx: @crate_ctxt, item: @ast::item,
llfndecl: ValueRef) -> @metadata<subprogram_md> { llfndecl: ValueRef) -> @metadata<subprogram_md> {
let cache = cx.llmetadata; 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(), let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
item.span.lo); item.span.lo);
let file_node = get_file_metadata(cx, loc.filename).node; let file_node = get_file_metadata(cx, loc.filename).node;
let fn_metadata = [lltag(SubprogramTag), let mangled = cx.item_symbols.get(item.id);
llunused(), let ret_ty = alt item.node {
file_node, ast::item_fn(f, _) { f.decl.output }
llstr(item.ident), };
llstr(item.ident), //XXX fully-qualified C++ name let ty_node = alt ret_ty.node {
llstr(item.ident), //XXX MIPS name????? ast::ty_nil. { llnull() }
file_node, _ { get_ty_metadata(cx, ty::node_id_to_type(ccx_tcx(cx), item.id),
lli32(loc.line as int), ret_ty).node }
C_null(T_ptr(T_nil())), // XXX reference to tydesc };
lli1(false), //XXX static let fn_metadata = [lltag(SubprogramTag),
lli1(true), // not extern llunused(),
lli32(DW_VIRTUALITY_none), // virtual-ness file_node,
lli32(0i), //index into virt func llstr(item.ident),
C_null(T_ptr(T_nil())), // base type with vtbl llstr(item.ident), //XXX fully-qualified C++ name
lli1(false), // artificial llstr(mangled), //XXX MIPS name?????
lli1(cx.sess.get_opts().optimize != 0u), file_node,
llfndecl lli32(loc.line as int),
//list of template params ty_node,
//func decl descriptor lli1(false), //XXX static (check export)
//list of func vars lli1(true), // not extern
]; lli32(DW_VIRTUALITY_none), // virtual-ness
let val = llmdnode(fn_metadata); lli32(0i), //index into virt func
llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.sp"), llnull(), // base type with vtbl
str::byte_len("llvm.dbg.sp"), lli1(false), // artificial
val); lli1(cx.sess.get_opts().optimize != 0u),
let mdval = @{node: val, data: {name: item.ident, llfndecl
file: loc.filename}}; //list of template params
update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); //func decl descriptor
ret mdval; //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;
} }

View file

@ -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 // - exprs with non-immediate type never get dest=by_val
fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt { fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
let tcx = bcx_tcx(bcx); let tcx = bcx_tcx(bcx);
debuginfo::update_source_pos(bcx, e);
if expr_is_lval(bcx, e) { if expr_is_lval(bcx, e) {
ret lval_to_dps(bcx, e, dest); 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; let bcx = cx;
debuginfo::update_source_pos(cx, s);
alt s.node { alt s.node {
ast::stmt_expr(e, _) { bcx = trans_expr(cx, e, ignore); } ast::stmt_expr(e, _) { bcx = trans_expr(cx, e, ignore); }
ast::stmt_decl(d, _) { ast::stmt_decl(d, _) {
@ -4023,6 +4027,9 @@ fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
} else { } else {
bcx = init_ref_local(bcx, local); 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); } 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"); } _ { bcx_ccx(cx).sess.unimpl("stmt variant"); }
} }
debuginfo::reset_source_pos(cx);
ret bcx; 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_dirty: true,
mutable lpad: option::none, mutable lpad: option::none,
sp: cx.sp, sp: cx.sp,
fcx: cx}; fcx: cx,
mutable source_pos: option::none};
alt parent { alt parent {
parent_some(cx) { parent_some(cx) {
if cx.unreachable { Unreachable(bcx); } 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_dirty: true,
mutable lpad: option::none, mutable lpad: option::none,
sp: fcx.sp, 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_dirty: true,
mutable lpad: option::none, mutable lpad: option::none,
sp: fcx.sp, sp: fcx.sp,
fcx: fcx}; fcx: fcx,
mutable source_pos: option::none};
} }
fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { 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_dirty: true,
mutable lpad: option::none, mutable lpad: option::none,
sp: fcx.sp, 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) fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest)
-> @block_ctxt { -> @block_ctxt {
let bcx = bcx; let bcx = bcx;
debuginfo::update_source_pos(bcx, b);
block_locals(b) {|local| bcx = alloc_local(bcx, local); }; block_locals(b) {|local| bcx = alloc_local(bcx, local); };
for s: @ast::stmt in b.node.stmts { for s: @ast::stmt in b.node.stmts {
bcx = trans_stmt(bcx, *s); 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; } _ { 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 { fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt {
@ -5465,6 +5481,18 @@ fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
ret intrinsics; ret intrinsics;
} }
fn declare_dbg_intrinsics(llmod: ModuleRef,
intrinsics: hashmap<str, ValueRef>) {
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) { fn trap(bcx: @block_ctxt) {
let v: [ValueRef] = []; let v: [ValueRef] = [];
alt bcx_ccx(bcx).intrinsics.find("llvm.trap") { 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 td = mk_target_data(sess.get_targ_cfg().target_strs.data_layout);
let tn = mk_type_names(); let tn = mk_type_names();
let intrinsics = declare_intrinsics(llmod); let intrinsics = declare_intrinsics(llmod);
if sess.get_opts().debuginfo {
declare_dbg_intrinsics(llmod, intrinsics);
}
let int_type = T_int(targ_cfg); let int_type = T_int(targ_cfg);
let float_type = T_float(targ_cfg); let float_type = T_float(targ_cfg);
let task_type = T_task(targ_cfg); let task_type = T_task(targ_cfg);

View file

@ -25,14 +25,16 @@ fn RetVoid(cx: @block_ctxt) {
if cx.unreachable { ret; } if cx.unreachable { ret; }
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; 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) { fn Ret(cx: @block_ctxt, V: ValueRef) {
if cx.unreachable { ret; } if cx.unreachable { ret; }
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; 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]) { fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) {
@ -40,8 +42,9 @@ fn AggregateRet(cx: @block_ctxt, RetVals: [ValueRef]) {
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; cx.terminated = true;
unsafe { unsafe {
llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals), let instr = llvm::LLVMBuildAggregateRet(B(cx), vec::to_ptr(RetVals),
vec::len(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; } if cx.unreachable { ret; }
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; 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, 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; } if cx.unreachable { ret; }
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; 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) 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); } if cx.unreachable { ret _Undef(V); }
assert !cx.terminated; assert !cx.terminated;
cx.terminated = true; 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) { 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; } if cx.unreachable { ret; }
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; 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 // 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); assert (!cx.terminated);
cx.terminated = true; cx.terminated = true;
unsafe { unsafe {
llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args), let instr = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args), Then, Catch, noname()); 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), let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args), Then, Catch, noname()); vec::len(Args), Then, Catch, noname());
llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv);
debuginfo::add_line_info(cx, v);
} }
} }
@ -123,183 +134,254 @@ fn _Undef(val: ValueRef) -> ValueRef {
/* Arithmetic */ /* Arithmetic */
fn Add(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef { fn Add(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NSWAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NUWAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn FAdd(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Sub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NSWSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NUWSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn FSub(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Mul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NSWMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn NUWMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn FMul(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn UDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn SDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn ExactSDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn FDiv(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn URem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn SRem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn FRem(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Shl(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn LShr(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn AShr(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn And(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Or(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Xor(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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) -> fn BinOp(cx: @block_ctxt, Op: Opcode, LHS: ValueRef, RHS: ValueRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret _Undef(LHS); } 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 { fn Neg(cx: @block_ctxt, V: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(V); } 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 { fn NSWNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(V); } 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 { fn NUWNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(V); } 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 { fn FNeg(cx: @block_ctxt, V: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(V); } 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 { fn Not(cx: @block_ctxt, V: ValueRef) -> ValueRef {
if cx.unreachable { ret _Undef(V); } 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 */ /* Memory */
fn Malloc(cx: @block_ctxt, Ty: TypeRef) -> ValueRef { fn Malloc(cx: @block_ctxt, Ty: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } 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 { fn ArrayMalloc(cx: @block_ctxt, Ty: TypeRef, Val: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } 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 { fn Alloca(cx: @block_ctxt, Ty: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } 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 { fn ArrayAlloca(cx: @block_ctxt, Ty: TypeRef, Val: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(Ty)); } 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) { fn Free(cx: @block_ctxt, PointerVal: ValueRef) {
if cx.unreachable { ret; } 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 { 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 }; llvm::LLVMGetElementType(ty) } else { ccx.int_type };
ret llvm::LLVMGetUndef(eltty); 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) { fn Store(cx: @block_ctxt, Val: ValueRef, Ptr: ValueRef) {
if cx.unreachable { ret; } 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 { fn GEP(cx: @block_ctxt, Pointer: ValueRef, Indices: [ValueRef]) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); }
unsafe { unsafe {
ret llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices), let instr = llvm::LLVMBuildGEP(B(cx), Pointer, vec::to_ptr(Indices),
vec::len(Indices), noname()); 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 { ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); }
unsafe { unsafe {
ret llvm::LLVMBuildInBoundsGEP(B(cx), Pointer, vec::to_ptr(Indices), let v = llvm::LLVMBuildInBoundsGEP(B(cx), Pointer,
vec::len(Indices), noname()); 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 { fn StructGEP(cx: @block_ctxt, Pointer: ValueRef, Idx: uint) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_nil())); } 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 { fn GlobalString(cx: @block_ctxt, _Str: sbuf) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } 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 { fn GlobalStringPtr(cx: @block_ctxt, _Str: sbuf) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_ptr(T_i8())); } 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 */ /* Casts */
fn Trunc(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef { fn Trunc(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn ZExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn SExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn FPToUI(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn FPToSI(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn UIToFP(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn SIToFP(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn FPTrunc(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn FPExt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn PtrToInt(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn IntToPtr(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn BitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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) -> fn ZExtOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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) -> fn SExtOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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) -> fn TruncOrBitCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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, fn Cast(cx: @block_ctxt, Op: Opcode, Val: ValueRef, DestTy: TypeRef,
_Name: sbuf) -> ValueRef { _Name: sbuf) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn PointerCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn IntCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 { fn FPCast(cx: @block_ctxt, Val: ValueRef, DestTy: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(DestTy); } 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 */ /* Comparisons */
fn ICmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef { fn ICmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } 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 { fn FCmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } 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 */ /* Miscellaneous instructions */
fn EmptyPhi(cx: @block_ctxt, Ty: TypeRef) -> ValueRef { fn EmptyPhi(cx: @block_ctxt, Ty: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } 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]) 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 { fn Call(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef]) -> ValueRef {
if cx.unreachable { ret _UndefReturn(cx, Fn); } if cx.unreachable { ret _UndefReturn(cx, Fn); }
unsafe { unsafe {
ret llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args), let instr = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args), noname()); 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), let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args), noname()); vec::len(Args), noname());
llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv); llvm::LLVMSetInstructionCallConv(v, lib::llvm::LLVMFastCallConv);
debuginfo::add_line_info(cx, v);
ret 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), let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args), noname()); vec::len(Args), noname());
llvm::LLVMSetInstructionCallConv(v, Conv); llvm::LLVMSetInstructionCallConv(v, Conv);
debuginfo::add_line_info(cx, v);
ret 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) -> fn Select(cx: @block_ctxt, If: ValueRef, Then: ValueRef, Else: ValueRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret _Undef(Then); } 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 { fn VAArg(cx: @block_ctxt, list: ValueRef, Ty: TypeRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(Ty); } 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) -> fn ExtractElement(cx: @block_ctxt, VecVal: ValueRef, Index: ValueRef) ->
ValueRef { ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } 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, fn InsertElement(cx: @block_ctxt, VecVal: ValueRef, EltVal: ValueRef,
Index: ValueRef) { Index: ValueRef) {
if cx.unreachable { ret; } 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, fn ShuffleVector(cx: @block_ctxt, V1: ValueRef, V2: ValueRef,
Mask: ValueRef) { Mask: ValueRef) {
if cx.unreachable { ret; } 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 { fn ExtractValue(cx: @block_ctxt, AggVal: ValueRef, Index: uint) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_nil()); } 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, fn InsertValue(cx: @block_ctxt, AggVal: ValueRef, EltVal: ValueRef,
Index: uint) { Index: uint) {
if cx.unreachable { ret; } 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 { fn IsNull(cx: @block_ctxt, Val: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } 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 { fn IsNotNull(cx: @block_ctxt, Val: ValueRef) -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); } 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 { fn PtrDiff(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
let ccx = cx.fcx.lcx.ccx; let ccx = cx.fcx.lcx.ccx;
if cx.unreachable { ret llvm::LLVMGetUndef(ccx.int_type); } 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) { fn Trap(cx: @block_ctxt) {
@ -622,15 +785,19 @@ fn Trap(cx: @block_ctxt) {
assert (T as int != 0); assert (T as int != 0);
let Args: [ValueRef] = []; let Args: [ValueRef] = [];
unsafe { unsafe {
llvm::LLVMBuildCall(b, T, vec::to_ptr(Args), let instr = llvm::LLVMBuildCall(b, T, vec::to_ptr(Args),
vec::len(Args), noname()); vec::len(Args), noname());
debuginfo::add_line_info(cx, instr);
} }
} }
fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef, fn LandingPad(cx: @block_ctxt, Ty: TypeRef, PersFn: ValueRef,
NumClauses: uint) -> ValueRef { NumClauses: uint) -> ValueRef {
assert !cx.terminated && !cx.unreachable; 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) { 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 { fn Resume(cx: @block_ctxt, Exn: ValueRef) -> ValueRef {
assert (!cx.terminated); assert (!cx.terminated);
cx.terminated = true; cx.terminated = true;
ret llvm::LLVMBuildResume(B(cx), Exn); let instr = llvm::LLVMBuildResume(B(cx), Exn);
debuginfo::add_line_info(cx, instr);
ret instr;
} }
// //

View file

@ -385,7 +385,8 @@ type block_ctxt =
mutable lpad_dirty: bool, mutable lpad_dirty: bool,
mutable lpad: option::t<BasicBlockRef>, mutable lpad: option::t<BasicBlockRef>,
sp: span, sp: span,
fcx: @fn_ctxt}; fcx: @fn_ctxt,
mutable source_pos: option::t<syntax::codemap::loc>};
// FIXME: we should be able to use option::t<@block_parent> here but // FIXME: we should be able to use option::t<@block_parent> here but
// the infinite-tag check in rustboot gets upset. // the infinite-tag check in rustboot gets upset.
@ -464,6 +465,8 @@ fn T_nil() -> TypeRef {
ret llvm::LLVMInt1Type(); ret llvm::LLVMInt1Type();
} }
fn T_metadata() -> TypeRef { ret llvm::LLVMMetadataType(); }
fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); } fn T_i1() -> TypeRef { ret llvm::LLVMInt1Type(); }
fn T_i8() -> TypeRef { ret llvm::LLVMInt8Type(); } 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); 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 { fn C_int(cx: @crate_ctxt, i: int) -> ValueRef {
ret C_integral(cx.int_type, i as u64, True); ret C_integral(cx.int_type, i as u64, True);
} }

View file

@ -60,6 +60,7 @@ LLVMAddLoopRotatePass
LLVMAddLoopUnrollPass LLVMAddLoopUnrollPass
LLVMAddLoopUnswitchPass LLVMAddLoopUnswitchPass
LLVMAddMemCpyOptPass LLVMAddMemCpyOptPass
LLVMAddNamedMetadataOperand
LLVMAddPromoteMemoryToRegisterPass LLVMAddPromoteMemoryToRegisterPass
LLVMAddPruneEHPass LLVMAddPruneEHPass
LLVMAddReassociatePass LLVMAddReassociatePass
@ -483,11 +484,15 @@ LLVMIsThreadLocal
LLVMIsUndef LLVMIsUndef
LLVMLabelType LLVMLabelType
LLVMLabelTypeInContext LLVMLabelTypeInContext
LLVMLinkInInterpreter
LLVMLinkInJIT
LLVMLinkInMCJIT
LLVMMDNode LLVMMDNode
LLVMMDNodeInContext LLVMMDNodeInContext
LLVMMDString LLVMMDString
LLVMMDStringInContext LLVMMDStringInContext
LLVMAddNamedMetadataOperand LLVMMetadataType
LLVMMetadataTypeInContext
LLVMModuleCreateWithName LLVMModuleCreateWithName
LLVMModuleCreateWithNameInContext LLVMModuleCreateWithNameInContext
LLVMMoveBasicBlockAfter LLVMMoveBasicBlockAfter