debuginfo: Support for tuple-style enums (WIP)

This commit is contained in:
Michael Woerister 2013-07-02 18:10:24 +02:00
parent 739f3eece9
commit f389bd8f2a
6 changed files with 268 additions and 97 deletions

View file

@ -2115,7 +2115,21 @@ pub mod llvm {
AlignInBits: c_ulonglong,
Elements: ValueRef,
ClassType: ValueRef) -> ValueRef;
}}
#[fast_ffi]
pub unsafe fn LLVMDIBuilderCreateUnionType(
Builder: DIBuilderRef,
Scope: ValueRef,
Name: *c_char,
File: ValueRef,
LineNumber: c_uint,
SizeInBits: c_ulonglong,
AlignInBits: c_ulonglong,
Flags: c_uint ,
Elements: ValueRef,
RunTimeLang : c_uint) -> ValueRef;
}
}
pub fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) {
unsafe {

View file

@ -501,9 +501,9 @@ fn create_struct(cx: &mut CrateContext,
fields: ~[ty::field],
span: span)
-> DICompositeType {
debug!("create_struct: %?", ty::get(struct_type));
let struct_name = ty_to_str(cx.tcx, struct_type);
debug!("create_struct: %s", struct_name);
let struct_llvm_type = type_of::type_of(cx, struct_type);
let field_llvm_types = fields.map(|field| type_of::type_of(cx, field.mt.ty));
@ -526,7 +526,7 @@ fn create_tuple(cx: &mut CrateContext,
span: span)
-> DICompositeType {
let tuple_name = "tuple"; // this should have a better name
let tuple_name = ty_to_str(cx.tcx, tuple_type);
let tuple_llvm_type = type_of::type_of(cx, tuple_type);
// Create a vec of empty strings. A vec::build_n() function would be nice for this.
let mut component_names : ~[~str] = vec::with_capacity(component_types.len());
@ -548,63 +548,119 @@ fn create_tuple(cx: &mut CrateContext,
fn create_enum_md(cx: &mut CrateContext,
enum_type: ty::t,
enum_def_id: ast::def_id,
span: span) -> DIType {
substs: &ty::substs,
span: span)
-> DIType {
let enum_name = ty_to_str(cx.tcx, enum_type);
let discriminator_llvm_type = Type::enum_discrim(cx);
let discriminator_size = machine::llsize_of_alloc(cx, discriminator_llvm_type);
let discriminator_align = machine::llalign_of_min(cx, discriminator_llvm_type);
assert!(Type::enum_discrim(cx) == cx.int_type);
let discriminator_type_md = get_or_create_type(cx, ty::mk_int(), span);
// For empty enums there is an early exit. Just describe it as an empty struct with the
// appropriate name
if ty::type_is_empty(cx.tcx, enum_type) {
// XXX: This should not "rename" the type to nil
return get_or_create_type(cx, ty::mk_nil(), span);
return create_composite_type(cx, Type::nil(), enum_name, &[], &[], &[], span);
}
// Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
// needed in all of the following cases.
let discriminant_llvm_type = Type::enum_discrim(cx);
let discriminant_size = machine::llsize_of_alloc(cx, discriminant_llvm_type);
let discriminant_align = machine::llalign_of_min(cx, discriminant_llvm_type);
assert!(Type::enum_discrim(cx) == cx.int_type);
let discriminant_type_md = get_or_create_type(cx, ty::mk_int(), span);
let variants : &[ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
let enumerators : ~[(~str, int)] = variants
.iter()
.transform(|v| (cx.sess.str_of(v.name).to_owned(), v.disr_val))
.collect();
let enumerators_md : ~[DIDescriptor] =
do enumerators.iter().transform |&(name,value)| {
do name.as_c_str |name| { unsafe {
llvm::LLVMDIBuilderCreateEnumerator(
DIB(cx),
name,
value as c_ulonglong)
}}
}.collect();
let loc = span_start(cx, span);
let file_metadata = get_or_create_file(cx, loc.file.name);
let discriminant_type_md = do enum_name.as_c_str |enum_name| { unsafe {
llvm::LLVMDIBuilderCreateEnumerationType(
DIB(cx),
file_metadata,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(discriminant_size),
bytes_to_bits(discriminant_align),
create_DIArray(DIB(cx), enumerators_md),
discriminant_type_md)
}};
if ty::type_is_c_like_enum(cx.tcx, enum_type) {
let variants : &[ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
let enumerators : ~[(~str, int)] = variants
.iter()
.transform(|v| (cx.sess.str_of(v.name).to_owned(), v.disr_val))
.collect();
let enumerators_md : ~[DIDescriptor] =
do enumerators.iter().transform |&(name,value)| {
do name.as_c_str |name| { unsafe {
llvm::LLVMDIBuilderCreateEnumerator(
DIB(cx),
name,
value as c_ulonglong)
}}
}.collect();
let loc = span_start(cx, span);
let file_metadata = get_or_create_file(cx, loc.file.name);
return do enum_name.as_c_str |enum_name| { unsafe {
llvm::LLVMDIBuilderCreateEnumerationType(
DIB(cx),
file_metadata,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(discriminator_size),
bytes_to_bits(discriminator_align),
create_DIArray(DIB(cx), enumerators_md),
discriminator_type_md)
}};
return discriminant_type_md;
}
cx.sess.bug("");
let variants_md = do variants.map |&vi| {
let raw_types : &[ty::t] = vi.args;
let arg_types = do raw_types.map |&raw_type| { ty::subst(cx.tcx, substs, raw_type) };
let arg_llvm_types = ~[discriminant_llvm_type] + do arg_types.map |&ty| { type_of::type_of(cx, ty) };
let arg_names = ~[~""] + arg_types.map(|_| ~"");
let arg_md = ~[discriminant_type_md] + do arg_types.map |&ty| { get_or_create_type(cx, ty, span) };
let variant_llvm_type = Type::struct_(arg_llvm_types, false);
let variant_type_size = machine::llsize_of_alloc(cx, variant_llvm_type);
let variant_type_align = machine::llalign_of_min(cx, variant_llvm_type);
let variant_type_md = create_composite_type(
cx,
variant_llvm_type,
&"",
arg_llvm_types,
arg_names,
arg_md,
span);
do "".as_c_str |name| { unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
file_metadata,
name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(variant_type_size),
bytes_to_bits(variant_type_align),
bytes_to_bits(0),
0,
variant_type_md)
}}
};
let enum_llvm_type = type_of::type_of(cx, enum_type);
let enum_type_size = machine::llsize_of_alloc(cx, enum_llvm_type);
let enum_type_align = machine::llalign_of_min(cx, enum_llvm_type);
return do "".as_c_str |enum_name| { unsafe { llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
file_metadata,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
0, // Flags
create_DIArray(DIB(cx), variants_md),
0) // RuntimeLang
}};
}
/// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
///
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
@ -899,10 +955,8 @@ fn get_or_create_type(cx: &mut CrateContext, t: ty::t, span: span) -> DIType {
}
}
},
ty::ty_enum(def_id, ref _substs) => {
//cx.sess.span_note(span, "debuginfo for enum NYI");
//create_unimpl_ty(cx, t)
create_enum_md(cx, t, def_id, span)
ty::ty_enum(def_id, ref substs) => {
create_enum_md(cx, t, def_id, substs, span)
},
ty::ty_box(ref mt) |
ty::ty_uniq(ref mt) => {

View file

@ -565,8 +565,8 @@ extern "C" bool LLVMRustStartMultithreading() {
typedef DIBuilder* DIBuilderRef;
template<typename DIT>
DIT unwrapDI(LLVMValueRef ref) {
return DIT(ref ? unwrap<MDNode>(ref) : NULL);
DIT unwrapDI(LLVMValueRef ref) {
return DIT(ref ? unwrap<MDNode>(ref) : NULL);
}
extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) {
@ -604,21 +604,21 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFile(
extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType(
DIBuilderRef Builder,
LLVMValueRef File,
LLVMValueRef File,
LLVMValueRef ParameterTypes) {
return wrap(Builder->createSubroutineType(
unwrapDI<DIFile>(File),
unwrapDI<DIFile>(File),
unwrapDI<DIArray>(ParameterTypes)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateFunction(
DIBuilderRef Builder,
LLVMValueRef Scope,
LLVMValueRef Scope,
const char* Name,
const char* LinkageName,
LLVMValueRef File,
LLVMValueRef File,
unsigned LineNo,
LLVMValueRef Ty,
LLVMValueRef Ty,
bool isLocalToUnit,
bool isDefinition,
unsigned ScopeLine,
@ -628,11 +628,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFunction(
LLVMValueRef TParam,
LLVMValueRef Decl) {
return wrap(Builder->createFunction(
unwrapDI<DIScope>(Scope), Name, LinkageName,
unwrapDI<DIFile>(File), LineNo,
unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
unwrapDI<DIScope>(Scope), Name, LinkageName,
unwrapDI<DIFile>(File), LineNo,
unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
Flags, isOptimized,
unwrap<Function>(Fn),
unwrap<Function>(Fn),
unwrapDI<MDNode*>(TParam),
unwrapDI<MDNode*>(Decl)));
}
@ -644,10 +644,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType(
uint64_t AlignInBits,
unsigned Encoding) {
return wrap(Builder->createBasicType(
Name, SizeInBits,
Name, SizeInBits,
AlignInBits, Encoding));
}
extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType(
DIBuilderRef Builder,
LLVMValueRef PointeeTy,
@ -672,11 +672,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateStructType(
unsigned RunTimeLang,
LLVMValueRef VTableHolder) {
return wrap(Builder->createStructType(
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File), LineNumber,
SizeInBits, AlignInBits, Flags,
unwrapDI<DIType>(DerivedFrom),
unwrapDI<DIArray>(Elements), RunTimeLang,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File), LineNumber,
SizeInBits, AlignInBits, Flags,
unwrapDI<DIType>(DerivedFrom),
unwrapDI<DIArray>(Elements), RunTimeLang,
unwrapDI<MDNode*>(VTableHolder)));
}
@ -692,12 +692,12 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType(
unsigned Flags,
LLVMValueRef Ty) {
return wrap(Builder->createMemberType(
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File), LineNo,
SizeInBits, AlignInBits, OffsetInBits, Flags,
SizeInBits, AlignInBits, OffsetInBits, Flags,
unwrapDI<DIType>(Ty)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock(
DIBuilderRef Builder,
LLVMValueRef Scope,
@ -705,10 +705,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock(
unsigned Line,
unsigned Col) {
return wrap(Builder->createLexicalBlock(
unwrapDI<DIDescriptor>(Scope),
unwrapDI<DIDescriptor>(Scope),
unwrapDI<DIFile>(File), Line, Col));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable(
DIBuilderRef Builder,
unsigned Tag,
@ -720,45 +720,45 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable(
bool AlwaysPreserve,
unsigned Flags,
unsigned ArgNo) {
return wrap(Builder->createLocalVariable(Tag,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File),
LineNo,
return wrap(Builder->createLocalVariable(Tag,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty), AlwaysPreserve, Flags, ArgNo));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType(
DIBuilderRef Builder,
uint64_t Size,
uint64_t AlignInBits,
LLVMValueRef Ty,
uint64_t Size,
uint64_t AlignInBits,
LLVMValueRef Ty,
LLVMValueRef Subscripts) {
return wrap(Builder->createArrayType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
unwrapDI<DIType>(Ty),
unwrapDI<DIArray>(Subscripts)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType(
DIBuilderRef Builder,
uint64_t Size,
uint64_t AlignInBits,
LLVMValueRef Ty,
uint64_t Size,
uint64_t AlignInBits,
LLVMValueRef Ty,
LLVMValueRef Subscripts) {
return wrap(Builder->createVectorType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
unwrapDI<DIType>(Ty),
unwrapDI<DIArray>(Subscripts)));
}
extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange(
DIBuilderRef Builder,
int64_t Lo,
DIBuilderRef Builder,
int64_t Lo,
int64_t Count) {
return wrap(Builder->getOrCreateSubrange(Lo, Count));
}
extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray(
DIBuilderRef Builder,
LLVMValueRef* Ptr,
LLVMValueRef* Ptr,
unsigned Count) {
return wrap(Builder->getOrCreateArray(
ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count)));
@ -770,8 +770,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
LLVMValueRef VarInfo,
LLVMBasicBlockRef InsertAtEnd) {
return wrap(Builder->insertDeclare(
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
unwrap(InsertAtEnd)));
}
@ -781,8 +781,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore(
LLVMValueRef VarInfo,
LLVMValueRef InsertBefore) {
return wrap(Builder->insertDeclare(
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
unwrap(Val),
unwrapDI<DIVariable>(VarInfo),
unwrap<Instruction>(InsertBefore)));
}
@ -814,4 +814,28 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType(
AlignInBits,
unwrapDI<DIArray>(Elements),
unwrapDI<DIType>(ClassType)));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType(
DIBuilderRef Builder,
LLVMValueRef Scope,
const char* Name,
LLVMValueRef File,
unsigned LineNumber,
uint64_t SizeInBits,
uint64_t AlignInBits,
unsigned Flags,
LLVMValueRef Elements,
unsigned RunTimeLang)
{
return wrap(Builder->createUnionType(
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNumber,
SizeInBits,
AlignInBits,
Flags,
unwrapDI<DIArray>(Elements),
RunTimeLang));
}

View file

@ -31,19 +31,25 @@
// debugger:print manual_one_million
// check:$6 = OneMillion
// debugger:print single_variant
// check:$7 = TheOnlyVariant
enum AutoDiscriminator {
enum AutoDiscriminant {
One,
Two,
Three
}
enum ManualDiscriminator {
enum ManualDiscriminant {
OneHundred = 100,
OneThousand = 1000,
OneMillion = 1000000
}
enum SingleVariant {
TheOnlyVariant
}
fn main() {
let auto_one = One;
@ -54,6 +60,8 @@ fn main() {
let manual_one_thousand = OneThousand;
let manual_one_million = OneMillion;
let single_variant = TheOnlyVariant;
zzz();
}

View file

@ -0,0 +1,38 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print first
// check:$1 = {<No data fields>}
// debugger:print second
// check:$2 = {<No data fields>}
enum ANilEnum {}
enum AnotherNilEnum {}
// I (mw) am not sure this test case makes much sense...
// Also, it relies on some implementation details:
// 1. That empty enums as well as '()' are represented as empty structs
// 2. That gdb prints the string "{<No data fields>}" for empty structs (which may change some time)
fn main() {
unsafe {
let first : ANilEnum = std::cast::transmute(());
let second : AnotherNilEnum = std::cast::transmute(());
zzz();
}
}
fn zzz() {()}

View file

@ -0,0 +1,33 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags:-Z extra-debug-info
// debugger:set print union on
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print case2
// check:$1 = {Case1, 0, 1}
enum Test {
Case1(i32, i64),
Case2(bool, i16, i32)
}
fn main() {
let case1 = Case1(110, 220);
let case2 = Case2(false, 2, 3);
zzz();
}
fn zzz() {()}