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 */
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;

View File

@ -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<T> = {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<int, [debug_metadata]>;
@ -62,18 +84,31 @@ tag debug_metadata {
file_metadata(@metadata<file_md>);
compile_unit_metadata(@metadata<compile_unit_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 {
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<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) {
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<file_md> {
let cache = cx.llmetadata;
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::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<file_md> {
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,
llfndecl: ValueRef) -> @metadata<subprogram_md> {
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;
}

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
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<str, ValueRef> {
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) {
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);

View File

@ -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;
}
//

View File

@ -385,7 +385,8 @@ type block_ctxt =
mutable lpad_dirty: bool,
mutable lpad: option::t<BasicBlockRef>,
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
// 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);
}

View File

@ -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