Dynamic dispatch.

This commit is contained in:
Christoffer Lerno
2023-05-25 13:46:44 +02:00
committed by Christoffer Lerno
parent 2e498a426e
commit b794c893d6
50 changed files with 529 additions and 261 deletions

View File

@@ -26,12 +26,8 @@ struct Object
}
}
static initialize
{
io::formatter_register_type(Object);
}
fn void! Object.to_format(Object* o, Formatter* formatter)
fn void! Object.to_format(Object* o, Formatter* formatter) @dynamic
{
switch (o.type)
{

View File

@@ -22,10 +22,11 @@ fault FormattingFault
}
def OutputFn = fn void!(char c, void* buffer);
def ToStringFunction = fn String(void* value, Allocator *using);
def ToFormatFunction = fn void!(void* value, Formatter* formatter);
def FloatType = double;
fn String any.to_string(void* value, Allocator *using) @interface;
fn void! any.to_format(void* value, Formatter* formatter) @interface;
fn usz! printf(String format, args...) @maydiscard
{
Formatter formatter;
@@ -102,41 +103,6 @@ fn void Formatter.init(Formatter* this, OutputFn out_fn, void* data = null)
*this = { .data = data, .out_fn = out_fn};
}
/**
* @require $checks($Type a, a.to_string()) || $checks($Type a, a.to_format(&&Formatter{})) "Expected a type with 'to_string' or 'to_format' defined"
* @require !$checks($Type a, a.to_string()) || $checks($Type a, a.to_string(&&Allocator{})) "Expected 'to_string' to take an allocator as argument."
* @require !$checks($Type a, a.to_format(&&Formatter{})) || $checks($Type a, Formatter b, a.to_format(&b)) "Expected 'to_format' to take a Formatter as argument."
*/
macro void formatter_register_type($Type)
{
$if $checks($Type a, a.to_format(&&Formatter {})):
if (!toformat_functions.table.len)
{
toformat_functions.init(64);
}
toformat_functions.set($Type.typeid, (ToFormatFunction)&$Type.to_format);
$else
if (!tostring_functions.table.len)
{
tostring_functions.init(64);
}
tostring_functions.set($Type.typeid, (ToStringFunction)&$Type.to_string);
$endif
}
static initialize @priority(101)
{
if (!toformat_functions.table.len)
{
toformat_functions.init(64);
}
if (!tostring_functions.table.len)
{
tostring_functions.init(64);
}
}
fn void! Formatter.out(Formatter* this, char c) @private
{
this.out_fn(c, this.data)!;
@@ -144,7 +110,7 @@ fn void! Formatter.out(Formatter* this, char c) @private
macro bool! Formatter.print_with_function(Formatter* this, any arg)
{
if (try to_format = toformat_functions.get(arg.type))
if (&arg.to_format)
{
PrintFlags old = this.flags;
uint old_width = this.width;
@@ -155,10 +121,10 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
this.width = old_width;
this.prec = old_prec;
}
to_format(arg.ptr, this)!;
arg.to_format(this)!;
return true;
}
if (try to_string = tostring_functions.get(arg.type))
}
if (&arg.to_string)
{
PrintFlags old = this.flags;
uint old_width = this.width;
@@ -171,7 +137,7 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
}
@pool()
{
this.out_substr(to_string(arg.ptr, mem::temp()))!;
this.out_substr(arg.to_string(mem::temp()))!;
return true;
};
}
@@ -277,21 +243,8 @@ fn void! Formatter.out_str(Formatter* this, any arg) @private
}
this.out(']')!;
case BOOL:
if (*(bool*)arg.ptr)
{
return this.out_substr("true");
}
else
{
return this.out_substr("false");
}
return this.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
switch (arg)
{
case Object:
arg.to_format(this)!;
return;
}
if (this.print_with_function(arg)!) return;
return this.out_substr("Invalid type");
}
@@ -472,8 +425,3 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
return this.idx;
}
def StringFunctionMap @private = HashMap<typeid, ToStringFunction>;
def FormatterFunctionMap @private = HashMap<typeid, ToFormatFunction>;
FormatterFunctionMap toformat_functions @private;
StringFunctionMap tostring_functions @private;

View File

@@ -37,12 +37,8 @@ struct InetAddress
}
}
static initialize
{
io::formatter_register_type(InetAddress);
}
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter)
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
{
if (addr.is_ipv6)
{
@@ -54,7 +50,7 @@ fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter)
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
}
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap())
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
{
if (addr.is_ipv6)
{

View File

@@ -3,6 +3,7 @@
## 0.5.0 Change List
### Changes / improvements
- `@dynamic` and `@interface` for dynamic dispatch.
- `$if` now uses `$if <expr>:` syntax.
- `$assert` now uses `$assert <expr> : <optional message>`
- `$error` is syntax sugar for `$assert false : "Some message"`
@@ -22,7 +23,7 @@
- Allow getting the underlying type of anyfault.
- De-duplicate string constants.
- Change @extname => @extern.
- `define Type = int` is replaced by `typedef Type = int`.
- `define` is replaced by `def`.
- LLVM "wrapper" library compilation is exception free.
- `private` is replaced by attribute `@private`.
- Addition of `@local` for file local visibility.

View File

@@ -3,10 +3,11 @@
enum IntrospectIndex
{
INTROSPECT_INDEX_KIND = 0,
INTROSPECT_INDEX_SIZEOF = 1,
INTROSPECT_INDEX_INNER = 2,
INTROSPECT_INDEX_LEN = 3,
INTROSPECT_INDEX_ADDITIONAL = 4,
INTROSPECT_INDEX_DTABLE = 1,
INTROSPECT_INDEX_SIZEOF = 2,
INTROSPECT_INDEX_INNER = 3,
INTROSPECT_INDEX_LEN = 4,
INTROSPECT_INDEX_ADDITIONAL = 5,
INTROSPECT_INDEX_TOTAL,
};

View File

@@ -558,8 +558,10 @@ typedef struct
bool attr_naked : 1;
bool attr_test : 1;
bool attr_winmain : 1;
bool has_faults : 1;
Decl** generated_lambda;
bool attr_dynamic : 1;
bool attr_interface : 1;
DeclId any_prototype;
Decl **generated_lambda;
};
struct
{
@@ -650,7 +652,6 @@ typedef struct
} InitializerDecl;
typedef struct Decl_
{
const char *name;
@@ -793,6 +794,7 @@ typedef struct
bool attr_pure : 1;
bool result_unused : 1;
bool no_return : 1;
bool is_dynamic_dispatch : 1;
AstId body;
union
{

View File

@@ -762,10 +762,12 @@ typedef enum
ATTRIBUTE_BUILTIN,
ATTRIBUTE_CDECL,
ATTRIBUTE_DEPRECATED,
ATTRIBUTE_DYNAMIC,
ATTRIBUTE_EXPORT,
ATTRIBUTE_EXTERN,
ATTRIBUTE_EXTNAME,
ATTRIBUTE_INLINE,
ATTRIBUTE_INTERFACE,
ATTRIBUTE_LITTLEENDIAN,
ATTRIBUTE_LOCAL,
ATTRIBUTE_MAYDISCARD,

View File

@@ -1044,6 +1044,17 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
llvm_add_global_decl(c, decl);
return decl->backend_ref;
case DECL_FUNC:
if (decl->func_decl.attr_interface)
{
size_t name_len = strlen(decl->name);
LLVMTypeRef char_array_type = LLVMArrayType(c->byte_type, name_len + 1);
LLVMValueRef selector = llvm_add_global_raw(c, decl_get_extname(decl), char_array_type, 0);
LLVMSetGlobalConstant(selector, 1);
LLVMSetInitializer(selector, llvm_get_zstring(c, decl->name, name_len));
LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage);
llvm_set_comdat(c, selector);
return decl->backend_ref = selector;
}
backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type));
llvm_append_function_attributes(c, decl);
if (decl_is_local(decl))
@@ -1301,6 +1312,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
llvm_emit_function_decl(gen_context, func);
FOREACH_END();
FOREACH_BEGIN(Decl *func, unit->lambdas)
if (only_used && !func->is_live) continue;
has_elements = true;
@@ -1367,6 +1379,8 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
FOREACH_END();
llvm_emit_dynamic_functions(gen_context, gen_context->dynamic_functions);
llvm_emit_constructors_and_destructors(gen_context);
// EmitDeferred()

View File

@@ -116,7 +116,7 @@ INLINE void llvm_emit_compare_exchange(GenContext *c, BEValue *result_value, Exp
llvm_value_set(result_value, llvm_emit_extract_value(c, result, 0), type);
}
INLINE void llvm_emit_unreachable(GenContext *c, BEValue *result_value, Expr *expr)
INLINE void llvm_emit_unreachable_stmt(GenContext *c, BEValue *result_value, Expr *expr)
{
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
c->current_block = NULL;
@@ -622,7 +622,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
switch (func)
{
case BUILTIN_UNREACHABLE:
llvm_emit_unreachable(c, result_value, expr);
llvm_emit_unreachable_stmt(c, result_value, expr);
return;
case BUILTIN_SWIZZLE:
llvm_emit_swizzle(c, result_value, expr, false);

View File

@@ -13,7 +13,7 @@ static inline LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr);
static inline LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id);
static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index);
static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr);
static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id_ptr, LLVMValueRef selector);
static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member);
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
@@ -35,6 +35,7 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp
static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *value, Expr *expr);
static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_value, Decl *member, Decl *parent_decl);
static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value);
static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLVMValueRef val, Type *vector_type,
bool is_equals);
static void llvm_emit_any_pointer(GenContext *c, BEValue *any, BEValue *pointer);
@@ -2446,6 +2447,19 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
llvm_emit_inc_dec_change(c, &addr, NULL, value, expr, diff);
}
static void llvm_emit_dynamic_method_addr(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->access_expr.parent);
llvm_emit_type_from_any(c, value);
llvm_value_rvalue(c, value);
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, value->value, c->ptr_type, "");
AlignSize align;
Decl *dyn_fn = expr->access_expr.ref;
LLVMValueRef func = llvm_emit_dynamic_search(c, introspect, llvm_get_ref(c, dyn_fn));
llvm_value_set(value, func, type_get_ptr(dyn_fn->type));
}
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{
@@ -2553,8 +2567,14 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
}
value->value = LLVMBuildNeg(c->builder, value->value, "neg");
return;
case UNARYOP_TADDR:
case UNARYOP_ADDR:
if (inner->expr_kind == EXPR_ACCESS && inner->access_expr.ref->decl_kind == DECL_FUNC)
{
llvm_emit_dynamic_method_addr(c, value, inner);
return;
}
FALLTHROUGH;
case UNARYOP_TADDR:
llvm_emit_expr(c, value, inner);
// Create an addr
llvm_value_addr(c, value);
@@ -4158,9 +4178,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
llvm_emit_any_from_value(c, &fault_arg, type_anyfault);
vec_add(varargs, fault_arg);
llvm_emit_panic(c, "Force unwrap failed!", loc, "Unexpected fault '%s' was unwrapped!", varargs);
LLVMBuildUnreachable(c->builder);
c->current_block = NULL;
c->current_block_is_target = false;
llvm_emit_unreachable(c);
}
llvm_emit_block(c, no_err_block);
@@ -5255,6 +5273,107 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype
// 17i. The simple case here is where there is a normal return.
// In this case be_value already holds the result
}
static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id_ptr, LLVMValueRef selector)
{
LLVMTypeRef type = c->dyn_find_function_type;
LLVMValueRef func = c->dyn_find_function;
if (!c->dyn_find_function)
{
LLVMTypeRef types[2] = { c->ptr_type, c->ptr_type };
type = c->dyn_find_function_type = LLVMFunctionType(c->ptr_type, types, 2, false);
func = c->dyn_find_function = LLVMAddFunction(c->module, ".dyn_seach", c->dyn_find_function_type);
LLVMSetUnnamedAddress(func, LLVMGlobalUnnamedAddr);
LLVMSetFunctionCallConv(func, LLVMFastCallConv);
LLVMSetLinkage(func, LLVMWeakODRLinkage);
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry");
LLVMPositionBuilderAtEnd(builder, entry);
AlignSize align;
LLVMValueRef dtable_ptr_in = LLVMGetParam(func, 0);
LLVMValueRef func_ref = LLVMGetParam(func, 1);
LLVMBasicBlockRef check = llvm_basic_block_new(c, "check");
LLVMBasicBlockRef missing_function = llvm_basic_block_new(c, "missing_function");
LLVMBasicBlockRef compare = llvm_basic_block_new(c, "compare");
LLVMBasicBlockRef match = llvm_basic_block_new(c, "match");
LLVMBasicBlockRef no_match = llvm_basic_block_new(c, "no_match");
LLVMBuildBr(builder, check);
// check: dtable_ptr = phi
LLVMAppendExistingBasicBlock(func, check);
LLVMPositionBuilderAtEnd(builder, check);
LLVMValueRef dtable_ptr = LLVMBuildPhi(builder, c->ptr_type, "");
// dtable_ptr == null
LLVMValueRef cmp = LLVMBuildICmp(builder, LLVMIntEQ, dtable_ptr, LLVMConstNull(c->ptr_type), "");
// if (cmp) goto missing_function else compare
LLVMBuildCondBr(builder, cmp, missing_function, compare);
// missing_function: return null
LLVMAppendExistingBasicBlock(func, missing_function);
LLVMPositionBuilderAtEnd(builder, missing_function);
LLVMBuildRet(builder, LLVMConstNull(c->ptr_type));
// function_type = dtable_ptr.function_type
LLVMAppendExistingBasicBlock(func, compare);
LLVMPositionBuilderAtEnd(builder, compare);
LLVMValueRef function_type = LLVMBuildStructGEP2(builder, c->dtable_type, dtable_ptr, 1, "");
function_type = LLVMBuildLoad2(builder, c->ptr_type, function_type, "");
LLVMSetAlignment(function_type, llvm_abi_alignment(c, c->ptr_type));
// function_type == func_ref
cmp = LLVMBuildICmp(builder, LLVMIntEQ, function_type, func_ref, "");
// if (cmp) goto match else no_match
LLVMBuildCondBr(builder, cmp, match, no_match);
// match: function_ptr = dtable_ptr.function_ptr
LLVMAppendExistingBasicBlock(func, match);
LLVMPositionBuilderAtEnd(builder, match);
// Offset = 0
LLVMValueRef function_ptr = LLVMBuildLoad2(builder, c->ptr_type, dtable_ptr, "");
LLVMSetAlignment(function_ptr, llvm_abi_alignment(c, c->ptr_type));
LLVMBuildRet(builder, function_ptr);
// no match: next = dtable_ptr.next
LLVMAppendExistingBasicBlock(func, no_match);
LLVMPositionBuilderAtEnd(builder, no_match);
LLVMValueRef next = LLVMBuildStructGEP2(builder, c->dtable_type, dtable_ptr, 2, "");
next = LLVMBuildLoad2(builder, c->ptr_type, next, "");
LLVMSetAlignment(next, llvm_abi_alignment(c, c->ptr_type));
// goto check
LLVMBuildBr(builder, check);
LLVMBasicBlockRef block_in[2] = { entry, no_match };
LLVMValueRef value_in[2] = { dtable_ptr_in, next };
LLVMAddIncoming(dtable_ptr, value_in, block_in, 2);
LLVMDisposeBuilder(builder);
}
AlignSize align;
LLVMValueRef dtable_ref = llvm_emit_struct_gep_raw(c,
type_id_ptr,
c->introspect_type,
INTROSPECT_INDEX_DTABLE,
llvm_abi_alignment(c, c->introspect_type),
&align);
LLVMValueRef dtable_ptr = llvm_load(c, c->ptr_type, dtable_ref, align, "");
LLVMValueRef params[2] = { dtable_ptr, selector };
LLVMValueRef call = LLVMBuildCall2(c->builder, type, func, params, 2, "");
LLVMSetFunctionCallConv(call, LLVMFastCallConv);
return call;
}
static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr, BEValue *target)
{
if (expr->call_expr.is_builtin)
@@ -5278,9 +5397,46 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
bool always_inline = false;
FunctionPrototype *prototype;
// 1. Call through a pointer.
if (!expr->call_expr.is_func_ref)
Expr **args = expr->call_expr.arguments;
BEValue arg0_pointer = { .value = NULL };
// 1. Dynamic dispatch.
if (expr->call_expr.is_dynamic_dispatch)
{
assert(vec_size(args));
Expr *any_val = args[0];
assert(any_val->expr_kind == EXPR_CAST);
any_val = exprptr(any_val->cast_expr.expr)->unary_expr.expr;
BEValue result;
llvm_emit_expr(c, &result, any_val);
BEValue typeid = result;
llvm_emit_type_from_any(c, &typeid);
llvm_value_rvalue(c, &typeid);
llvm_emit_any_pointer(c, &result, &arg0_pointer);
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, typeid.value, c->ptr_type, "");
LLVMBasicBlockRef missing_function = llvm_basic_block_new(c, "missing_function");
LLVMBasicBlockRef match = llvm_basic_block_new(c, "match");
AlignSize align;
Decl *dyn_fn = declptr(expr->call_expr.func_ref);
func = llvm_emit_dynamic_search(c, introspect, llvm_get_ref(c, dyn_fn));
LLVMValueRef cmp = LLVMBuildICmp(c->builder, LLVMIntEQ, func, LLVMConstNull(c->ptr_type), "");
llvm_emit_cond_br_raw(c, cmp, missing_function, match);
llvm_emit_block(c, missing_function);
scratch_buffer_clear();
scratch_buffer_printf("No method '%s' could be found on target", dyn_fn->name);
llvm_emit_panic(c, scratch_buffer_to_string(), expr->span, NULL, NULL);
llvm_emit_unreachable(c);
llvm_emit_block(c, match);
prototype = type_get_resolved_prototype(dyn_fn->type);
func_type = llvm_get_type(c, dyn_fn->type);
}
else if (!expr->call_expr.is_func_ref)
{
// Call through a pointer.
Expr *function = exprptr(expr->call_expr.function);
// 1a. Find the pointee type for the function pointer:
@@ -5312,13 +5468,11 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
assert(func);
func_type = llvm_get_type(c, function_decl->type);
}
LLVMValueRef arg_values[512];
unsigned arg_count = 0;
Type **params = prototype->param_types;
ABIArgInfo **abi_args = prototype->abi_args;
unsigned param_count = vec_size(params);
Expr **args = expr->call_expr.arguments;
Expr **varargs = NULL;
Expr *vararg_splat = NULL;
if (expr->call_expr.splat_vararg)
@@ -5428,7 +5582,14 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
if (arg_expr)
{
llvm_emit_expr(c, &temp_value, arg_expr);
if (i == 0 && arg0_pointer.value)
{
temp_value = arg0_pointer;
}
else
{
llvm_emit_expr(c, &temp_value, arg_expr);
}
}
else
{
@@ -5931,9 +6092,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'inner' on non composite type", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -5962,9 +6121,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'names' on non enum/fault type.", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -5997,9 +6154,7 @@ static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *ex
llvm_emit_block(c, next);
}
llvm_emit_panic(c, "Attempted to access 'len' on non array type", expr->span, NULL, NULL);
c->current_block = NULL;
c->current_block_is_target = false;
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
llvm_emit_block(c, exit);
}
{
@@ -6101,6 +6256,25 @@ static inline void llvm_emit_any(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, var, type_any);
}
static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value)
{
if (llvm_value_is_addr(be_value))
{
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
be_value->value,
llvm_get_type(c, type_any),
1,
be_value->alignment,
&alignment);
llvm_value_set_address(be_value, pointer_addr, type_typeid, alignment);
}
else
{
llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid);
}
}
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr *inner = exprptr(expr->builtin_access_expr.inner);
@@ -6204,21 +6378,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
return;
}
case ACCESS_TYPEOFANY:
if (llvm_value_is_addr(be_value))
{
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
be_value->value,
llvm_get_type(c, type_any),
1,
be_value->alignment,
&alignment);
llvm_value_set_address(be_value, pointer_addr, type_typeid, alignment);
}
else
{
llvm_value_set(be_value, llvm_emit_extract_value(c, be_value->value, 1), type_typeid);
}
llvm_emit_type_from_any(c, be_value);
return;
}
UNREACHABLE

View File

@@ -5,6 +5,7 @@
#include "llvm_codegen_internal.h"
static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_finalizer);
static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index);
static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef value);
static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment);
@@ -404,6 +405,7 @@ void llvm_emit_return_implicit(GenContext *c)
void llvm_emit_function_body(GenContext *c, Decl *decl)
{
DEBUG_LOG("Generating function %s.", decl->extname);
if (decl->func_decl.attr_dynamic) vec_add(c->dynamic_functions, decl);
assert(decl->backend_ref);
llvm_emit_body(c,
decl->backend_ref,
@@ -568,6 +570,18 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam
c->function = prev_function;
}
static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_initializer)
{
LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false);
LLVMValueRef **array_ref = is_initializer ? &c->constructors : &c->destructors;
scratch_buffer_clear();
scratch_buffer_printf(is_initializer ? ".static_initialize.%u" : ".static_finalize.%u", vec_size(*array_ref));
LLVMValueRef function = LLVMAddFunction(c->module, scratch_buffer_to_string(), initializer_type);
LLVMSetLinkage(function, LLVMInternalLinkage);
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) };
vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false));
return function;
}
void llvm_emit_xxlizer(GenContext *c, Decl *decl)
{
@@ -577,13 +591,8 @@ void llvm_emit_xxlizer(GenContext *c, Decl *decl)
// Skip if it doesn't have a body.
return;
}
LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false);
bool is_finalizer = decl->decl_kind == DECL_FINALIZE;
LLVMValueRef **array_ref = is_finalizer ? &c->destructors : &c->constructors;
scratch_buffer_clear();
scratch_buffer_printf(is_finalizer ? ".static_finalize.%u" : ".static_initialize.%u", vec_size(*array_ref));
LLVMValueRef function = LLVMAddFunction(c->module, scratch_buffer_to_string(), initializer_type);
LLVMSetLinkage(function, LLVMInternalLinkage);
bool is_initializer = decl->decl_kind == DECL_INITIALIZE;
LLVMValueRef function = llvm_add_xxlizer(c, decl->xxlizer.priority, is_initializer);
if (llvm_use_debug(c))
{
uint32_t row = decl->span.row;
@@ -607,16 +616,67 @@ void llvm_emit_xxlizer(GenContext *c, Decl *decl)
llvm_emit_body(c,
function,
decl->unit->module->name->module,
is_finalizer ? "[static finalizer]" : "[static initializer]",
is_initializer ? "[static initializer]" : "[static finalizer]",
decl->span.file_id,
NULL,
NULL,
body);
unsigned priority = decl->xxlizer.priority;
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) };
vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false));
}
static void llvm_generate_dyn_proto(GenContext *c, LLVMValueRef proto_ref)
{
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, proto_ref, "never");
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuildUnreachable(builder);
LLVMDisposeBuilder(builder);
}
void llvm_emit_dynamic_functions(GenContext *c, Decl **funcs)
{
if (!vec_size(funcs)) return;
LLVMValueRef initializer = llvm_add_xxlizer(c, 1, true);
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, initializer, "entry");
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBasicBlockRef last_block = entry;
FOREACH_BEGIN(Decl *decl, funcs)
Type *type = typeinfotype(decl->func_decl.type_parent);
scratch_buffer_clear();
scratch_buffer_append("$ct.dyn.");
scratch_buffer_append(decl_get_extname(decl));
LLVMValueRef global = llvm_add_global_raw(c, scratch_buffer_to_string(), c->dtable_type, 0);
Decl *proto = declptr(decl->func_decl.any_prototype);
LLVMValueRef proto_ref = llvm_get_ref(c, proto);
LLVMValueRef vals[3] = { llvm_get_ref(c, decl), proto_ref, LLVMConstNull(c->ptr_type) };
LLVMSetInitializer(global, LLVMConstNamedStruct(c->dtable_type, vals, 3));
LLVMValueRef type_id_ptr = LLVMBuildIntToPtr(builder, llvm_get_typeid(c, type), c->ptr_type, "");
LLVMValueRef dtable_ref = LLVMBuildStructGEP2(builder, c->introspect_type, type_id_ptr, INTROSPECT_INDEX_DTABLE, "");
LLVMBasicBlockRef check = LLVMAppendBasicBlockInContext(c->context, initializer, "dtable_check");
LLVMBuildBr(builder, check);
LLVMPositionBuilderAtEnd(builder, check);
LLVMValueRef phi = LLVMBuildPhi(builder, c->ptr_type, "dtable_ref");
LLVMValueRef load_dtable = LLVMBuildLoad2(builder, c->ptr_type, phi, "dtable_ptr");
LLVMValueRef is_not_null = LLVMBuildICmp(builder, LLVMIntEQ, load_dtable, LLVMConstNull(c->ptr_type), "");
LLVMBasicBlockRef after_check = llvm_basic_block_new(c, "dtable_found");
LLVMBasicBlockRef next = llvm_basic_block_new(c, "dtable_next");
LLVMBuildCondBr(builder, is_not_null, after_check, next);
LLVMAppendExistingBasicBlock(initializer, next);
LLVMPositionBuilderAtEnd(builder, next);
LLVMValueRef next_ptr = LLVMBuildStructGEP2(builder, c->dtable_type, load_dtable, 2, "next_dtable_ref");
LLVMValueRef phi_in[2] = { dtable_ref, next_ptr };
LLVMBasicBlockRef phi_in_block[2] = { last_block, next };
LLVMAddIncoming(phi, phi_in, phi_in_block, 2);
LLVMBuildBr(builder, check);
LLVMAppendExistingBasicBlock(initializer, after_check);
LLVMPositionBuilderAtEnd(builder, after_check);
LLVMBuildStore(builder, global, phi);
last_block = after_check;
FOREACH_END();
LLVMBuildRet(builder, NULL);
LLVMDisposeBuilder(builder);
}
void llvm_emit_function_decl(GenContext *c, Decl *decl)
{
assert(decl->decl_kind == DECL_FUNC);

View File

@@ -102,6 +102,7 @@ typedef struct GenContext_
LLVMTypeRef fault_type;
LLVMTypeRef size_type;
LLVMTypeRef typeid_type;
LLVMTypeRef dtable_type;
LLVMTypeRef char_ptr_type;
LLVMTypeRef ptr_type;
LLVMTypeRef chars_type;
@@ -128,6 +129,9 @@ typedef struct GenContext_
bool current_block_is_target : 1;
LLVMTypeRef type_data_definitions[TYPE_KINDS];
SourceSpan last_emitted_loc;
Decl **dynamic_functions;
LLVMValueRef dyn_find_function;
LLVMTypeRef dyn_find_function_type;
} GenContext;
// LLVM Intrinsics
@@ -462,6 +466,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani
void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc, const char *fmt, BEValue *value_1,
BEValue *value_2);
void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *args);
void llvm_emit_unreachable(GenContext *c);
void llvm_emit_any_from_value(GenContext *c, BEValue *value, Type *type);
void llvm_emit_subarray_len(GenContext *context, BEValue *subarray, BEValue *len);
@@ -469,6 +474,7 @@ void llvm_emit_subarray_pointer(GenContext *context, BEValue *subarray, BEValue
void llvm_emit_compound_stmt(GenContext *c, Ast *ast);
LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer);
void llvm_emit_function_body(GenContext *context, Decl *decl);
void llvm_emit_dynamic_functions(GenContext *context, Decl **funcs);
BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValueRef optional);
INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr);
INLINE void llvm_emit_statement_chain(GenContext *c, AstId current);

View File

@@ -11,6 +11,7 @@ static inline LLVMTypeRef create_introspection_type(GenContext *c)
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".introspect");
LLVMTypeRef introspect_type[INTROSPECT_INDEX_TOTAL] = {
[INTROSPECT_INDEX_KIND] = c->byte_type,
[INTROSPECT_INDEX_DTABLE] = c->ptr_type,
[INTROSPECT_INDEX_SIZEOF] = c->size_type,
[INTROSPECT_INDEX_INNER] = c->typeid_type,
[INTROSPECT_INDEX_LEN] = c->size_type,
@@ -113,6 +114,8 @@ void gencontext_begin_module(GenContext *c)
c->ptr_type = LLVMPointerType(c->byte_type, 0);
c->size_type = llvm_get_type(c, type_usz);
c->typeid_type = llvm_get_type(c, type_typeid);
LLVMTypeRef dtable_type[3] = { c->ptr_type, c->ptr_type, c->ptr_type };
c->dtable_type = LLVMStructTypeInContext(c->context, dtable_type, 3, false);
c->chars_type = llvm_get_type(c, type_chars);
c->introspect_type = create_introspection_type(c);
c->fault_type = create_fault_type(c);

View File

@@ -470,10 +470,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast)
SourceSpan loc = ast->span;
llvm_emit_panic(c, "Infinite loop found", loc, NULL, NULL);
LLVMBuildUnreachable(c->builder);
llvm_emit_unreachable(c);
LLVMBasicBlockRef block = llvm_basic_block_new(c, "unreachable_block");
c->current_block = NULL;
c->current_block_is_target = false;
llvm_emit_block(c, block);
return;
}
@@ -1274,6 +1272,12 @@ LLVMValueRef llvm_emit_zstring_named(GenContext *c, const char *str, const char
return string;
}
void llvm_emit_unreachable(GenContext *c)
{
LLVMBuildUnreachable(c->builder);
c->current_block = NULL;
c->current_block_is_target = false;
}
void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const char *fmt, BEValue *varargs)
{

View File

@@ -439,6 +439,7 @@ static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLV
}
LLVMValueRef values[INTROSPECT_INDEX_TOTAL] = {
[INTROSPECT_INDEX_KIND] = LLVMConstInt(c->byte_type, introspect_type, false),
[INTROSPECT_INDEX_DTABLE] = LLVMConstNull(c->ptr_type),
[INTROSPECT_INDEX_SIZEOF] = LLVMConstInt(c->size_type, type_size(type), false),
[INTROSPECT_INDEX_INNER] = inner ? llvm_get_typeid(c, inner) : llvm_get_zero(c, type_typeid),
[INTROSPECT_INDEX_LEN] = LLVMConstInt(c->size_type,len, false),
@@ -461,7 +462,7 @@ static inline LLVMValueRef llvm_generate_introspection_global(GenContext *c, LLV
LLVMSetInitializer(global_name, strukt);
}
LLVMSetAlignment(global_name, llvm_abi_alignment(c, c->introspect_type));
LLVMSetGlobalConstant(global_name, 1);
LLVMSetGlobalConstant(global_name, 0);
if (is_external)
{
LLVMSetLinkage(global_name, LLVMExternalLinkage);

View File

@@ -2306,10 +2306,9 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool
return func;
}
if (tok_is(c, TOKEN_EOS))
if (try_consume(c, TOKEN_EOS))
{
SEMA_ERROR_HERE("Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file.");
return poisoned_decl;
return func;
}
if (tok_is(c, TOKEN_IMPLIES))

View File

@@ -13,7 +13,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count);
static inline bool sema_analyse_method(SemaContext *context, Decl *decl);
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type);
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic, bool is_interface);
static inline bool sema_analyse_macro_method(SemaContext *context, Decl *decl);
static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like);
static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type, Decl *method_like);
@@ -701,6 +701,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
return false;
}
// Check parameters
for (unsigned i = 0; i < param_count; i++)
{
@@ -1417,13 +1418,15 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
if (!sema_resolve_type_info(context, parent_type)) return false;
Type *type = parent_type->type->canonical;
Decl **params = decl->func_decl.signature.params;
if (!vec_size(params))
bool is_dynamic = decl->func_decl.attr_dynamic;
bool is_interface = decl->func_decl.attr_interface;
if (is_interface && type != type_any) RETURN_SEMA_ERROR(decl, "Only 'any' methods may use '@interface'.");
if (!sema_is_valid_method_param(context, params[0], type, is_dynamic, is_interface)) return false;
if (is_dynamic)
{
SEMA_ERROR(decl, "A method must start with a parameter of type %s or %s.",
type_quoted_error_string(parent_type->type), type_quoted_error_string(type_get_ptr(parent_type->type)));
return false;
if (is_interface) RETURN_SEMA_ERROR(decl, "An interface method cannot be '@dynamic'.");
}
if (!sema_is_valid_method_param(context, params[0], type)) return false;
return unit_add_method_like(context->unit, type, decl);
}
@@ -1484,6 +1487,8 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC,
[ATTRIBUTE_CDECL] = ATTR_FUNC,
[ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER,
[ATTRIBUTE_DYNAMIC] = ATTR_FUNC,
[ATTRIBUTE_INTERFACE] = ATTR_FUNC,
[ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
[ATTRIBUTE_NOSTRIP] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
@@ -1579,6 +1584,12 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
case ATTRIBUTE_TEST:
decl->func_decl.attr_test = true;
break;
case ATTRIBUTE_INTERFACE:
decl->func_decl.attr_interface = true;
break;
case ATTRIBUTE_DYNAMIC:
decl->func_decl.attr_dynamic = true;
break;
case ATTRIBUTE_STDCALL:
assert(decl->decl_kind == DECL_FUNC);
if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB)
@@ -2377,6 +2388,16 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
}
else
{
if (decl->func_decl.attr_dynamic)
{
SEMA_ERROR(decl, "Only methods may be annotated '@dynamic'.");
return decl_poison(decl);
}
if (decl->func_decl.attr_interface)
{
SEMA_ERROR(decl, "Only methods to 'any' may be annotated '@interface'.");
return decl_poison(decl);
}
if (decl->name == kw_main)
{
if (is_test) SEMA_ERROR(decl, "Main functions may not be annotated @test.");
@@ -2385,6 +2406,15 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
decl_set_external_name(decl);
}
bool is_any_interface = decl->func_decl.attr_interface && decl->func_decl.type_parent && typeinfotype(decl->func_decl.type_parent) == type_any;
// Do we have fn void any.foo(void*) { ... }?
if (decl->func_decl.body && is_any_interface) RETURN_SEMA_ERROR(decl, "Interface methods declarations may not have a body.");
if (!decl->func_decl.body && !decl->is_extern && !decl->unit->is_interface_file && !is_any_interface)
{
SEMA_ERROR(decl, "Expected a function body, if you want to declare an extern function use 'extern' or place it in an .c3i file.");
return false;
}
bool pure = false;
if (!sema_analyse_doc_header(decl->func_decl.docs, decl->func_decl.signature.params, NULL, &pure)) return decl_poison(decl);
decl->func_decl.signature.attrs.is_pure = pure;
@@ -2393,15 +2423,32 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
return true;
}
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type)
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic, bool is_interface)
{
assert(parent_type->canonical == parent_type && "Expected already the canonical version.");
Type *param_type = param->type;
if (!param_type) goto ERROR;
param_type = param_type->canonical;
if (is_interface)
{
if (param_type != type_voidptr) RETURN_SEMA_ERROR(param, "The first parameter of an interface must be of type 'void*'.");
return true;
}
if (is_dynamic)
{
if (param_type->type_kind != TYPE_POINTER || param_type->pointer != parent_type)
{
RETURN_SEMA_ERROR(param, "The fist parameter must be of type %s", type_quoted_error_string(type_get_ptr(parent_type)));
}
return true;
}
// 1. Same type ok!
if (param_type == parent_type) return true;
// 2. A pointer is ok!
if (param_type->type_kind == TYPE_POINTER && param_type->pointer == parent_type) return true;
ERROR:
@@ -2433,7 +2480,7 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
SEMA_ERROR(decl, "The first parameter to this method must be of type '%s'.", type_to_error_string(parent_type));
return false;
}
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical)) return false;
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical, false, false)) return false;
if (first_param->var.kind != VARDECL_PARAM_REF && first_param->var.kind != VARDECL_PARAM)
{

View File

@@ -1660,6 +1660,9 @@ static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr,
}
sema_display_deprecated_warning_on_use(context, decl, expr->span);
// Tag dynamic dispatch.
if (struct_var && decl->func_decl.attr_interface) expr->call_expr.is_dynamic_dispatch = true;
return sema_call_analyse_func_invocation(context,
decl->type,
expr,
@@ -5466,11 +5469,15 @@ static const char *sema_addr_check_may_take(Expr *inner)
if (inner->unary_expr.operator == UNARYOP_DEREF) return NULL;
break;
case EXPR_ACCESS:
if (inner->access_expr.ref->decl_kind == DECL_FUNC)
{
Decl *decl = inner->access_expr.ref;
if (decl->decl_kind == DECL_FUNC)
{
if (decl->func_decl.attr_interface) return NULL;
return "Taking the address of a method should be done through the type e.g. '&Foo.method' not through the value.";
}
return sema_addr_check_may_take(inner->access_expr.parent);
}
case EXPR_GROUP:
return sema_addr_check_may_take(inner->inner_expr);
case EXPR_SUBSCRIPT:

View File

@@ -2916,6 +2916,19 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, So
bool sema_analyse_function_body(SemaContext *context, Decl *func)
{
if (!decl_ok(func)) return false;
if (func->func_decl.attr_dynamic)
{
Decl *ambiguous = NULL;
Decl *private = NULL;
Decl *any = sema_resolve_type_method(context->unit, type_any, func->name, &ambiguous, &private);
if (!any)
{
SEMA_ERROR(func, "To define a '@dynamic' method, the prototype method 'any.%s(...)' must exist. Did you spell the method name right?",
func->name);
return false;
}
func->func_decl.any_prototype = declid(any);
}
Signature *signature = &func->func_decl.signature;
FunctionPrototype *prototype = func->type->function.prototype;
context->call_env = (CallEnv) {

View File

@@ -297,10 +297,12 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_BUILTIN] = KW_DEF("@builtin");
attribute_list[ATTRIBUTE_CDECL] = KW_DEF("@cdecl");
attribute_list[ATTRIBUTE_DEPRECATED] = KW_DEF("@deprecated");
attribute_list[ATTRIBUTE_DYNAMIC] = KW_DEF("@dynamic");
attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export");
attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern");
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");
attribute_list[ATTRIBUTE_INTERFACE] = KW_DEF("@interface");
attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian");
attribute_list[ATTRIBUTE_LOCAL] = KW_DEF("@local");
attribute_list[ATTRIBUTE_MAYDISCARD] = KW_DEF("@maydiscard");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.513"
#define COMPILER_VERSION "0.4.514"

View File

@@ -20,10 +20,10 @@ fn Foo getFoo(Foo f)
/* #expect: test.ll
%.introspect = type { i8, i64, i64, i64, [0 x i64] }
%.introspect = type { i8, ptr, i64, i64, i64, [0 x i64] }
%Foo = type { i8, i8, i8 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 3, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
; Function Attrs: nounwind
define i32 @test.testing() #0 {

View File

@@ -15,7 +15,7 @@ Connection[3] link @private
/* #expect: test.ll
@"$ct.test.Connection" = linkonce constant %.introspect { i8 10, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Connection" = linkonce global %.introspect { i8 10, ptr null, i64 24, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [6 x i8] c"link1\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"link2\00", align 1
@.str.2 = private unnamed_addr constant [6 x i8] c"link3\00", align 1

View File

@@ -32,7 +32,7 @@ fn void main() @TestZero
/* #expect: test.ll
%Foo = type { i32, [1020 x i8], i32, [1020 x i8] }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 2048, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@test.f = local_unnamed_addr global %Foo zeroinitializer, align 1024
define weak void @test.testme2() #0 {

View File

@@ -24,26 +24,27 @@ fn void main()
/* #expect: test.ll
%.introspect = type { i8, i64, i64, i64, [0 x i64] }
%.introspect = type { i8, ptr, i64, i64, i64, [0 x i64] }
%Foo = type { i32, i32 }
%"int[]" = type { ptr, i64 }
%any = type { ptr, i64 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [9 x i8] c"%s %s %s\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$int" = linkonce constant %.introspect { i8 15, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$int" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.v2$int" = linkonce constant %.introspect { i8 17, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$int" = linkonce global %.introspect { i8 15, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$int" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.v2$int" = linkonce global %.introspect { i8 17, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant [1 x %Foo] [%Foo { i32 1, i32 2 }], align 4
@.__const.1 = private unnamed_addr constant %Foo { i32 1, i32 2 }, align 4
@.__const.2 = private unnamed_addr constant [1 x [2 x i32]] [[2 x i32] [i32 1, i32 2]], align 4
@.__const.3 = private unnamed_addr constant [1 x [2 x double]] [[2 x double] [double 1.000000e+00, double 2.000000e+00]], align 16
@.str.4 = private unnamed_addr constant [15 x i8] c"%s %s {%s, %s}\00", align 1
@"$ct.a1$a2$int" = linkonce constant %.introspect { i8 15, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$double" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$double" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$int" = linkonce global %.introspect { i8 15, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.a2$int" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$double" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.double" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a1$a2$double" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.a2$double" to i64), i64 1, [0 x i64] zeroinitializer }, align 8
; Function Attrs: nounwind
define void @test.test(i64 %0, ptr %1, i64 %2, double %3) #0 {

View File

@@ -22,7 +22,7 @@ fn void main()
/* #expect: qnametest.ll
@"$ct.qnametest.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.qnametest.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@qnametest.x = local_unnamed_addr global i32 0, align 4
@.str = private unnamed_addr constant [12 x i8] c"printf: %s\0A\00", align 1
@.str.1 = private unnamed_addr constant [7 x i8] c"printf\00", align 1

View File

@@ -18,8 +18,8 @@ fn void main()
/* #expect: test.ll
@"$ct.uint" = linkonce constant %.introspect { i8 3, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.uint" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 1 }, %"char[]" { ptr @.enum.1, i64 1 }] }, align 8
@"$ct.uint" = linkonce global %.introspect { i8 3, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.uint" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 1 }, %"char[]" { ptr @.enum.1, i64 1 }] }, align 8
@"test.Foo$val" = linkonce constant [2 x i32] [i32 123, i32 333], align 4
@.str = private unnamed_addr constant [9 x i8] c"Number A\00", align 1
@.str.1 = private unnamed_addr constant [9 x i8] c"Number B\00", align 1

View File

@@ -24,11 +24,11 @@ enum Foo : int(String val)
/* #expect: abc.ll
@"$ct.abc.Abc" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Abc" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.enum.0 = internal constant [4 x i8] c"ABC\00", align 1
@.enum.1 = internal constant [4 x i8] c"DEF\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"world\00", align 1
@"abc.Foo$val" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str, i64 5 }, %"char[]" { ptr @.str.1, i64 5 }], align 8
@@ -37,18 +37,19 @@ enum Foo : int(String val)
// #expect: test.ll
@"$ct.abc.Abc" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Abc" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@abc.dabc = external global i32, align 4
@.enum.0 = internal constant [4 x i8] c"ABC\00", align 1
@.enum.1 = internal constant [4 x i8] c"DEF\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce constant { i8, i64, i64, i64, [2 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.abc.Foo" = linkonce global { i8, ptr, i64, i64, i64, [2 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 2, [2 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 3 }, %"char[]" { ptr @.enum.1, i64 3 }] }, align 8
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
@.str.1 = private unnamed_addr constant [6 x i8] c"world\00", align 1
@"abc.Foo$val" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str, i64 5 }, %"char[]" { ptr @.str.1, i64 5 }], align 8
@.str.2 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.main(ptr %0, i64 %1) #0 {
entry:

View File

@@ -22,18 +22,18 @@ fn void main()
@.fault = internal constant [4 x i8] c"BAR\00", align 1
@"foo.Foo$BAZ" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault.1, i64 3 }, i64 2 }, align 8
@.fault.1 = internal constant [4 x i8] c"BAZ\00", align 1
@"$ct.foo.Foo" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Foo" = linkonce global %.introspect { i8 9, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [4 x i8] c"BAR\00", align 1
@.str.2 = private unnamed_addr constant [4 x i8] c"BAZ\00", align 1
@.str.3 = private unnamed_addr constant [14 x i8] c"Foo.names: %s\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce constant %.introspect { i8 18, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$String" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.String" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce global %.introspect { i8 18, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$String" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.String" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@.str.4 = private unnamed_addr constant [15 x i8] c"Foo.values: %s\00", align 1
@"$ct.a2$foo.Foo" = linkonce constant %.introspect { i8 15, i64 16, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.a2$foo.Foo" = linkonce global %.introspect { i8 15, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), i64 2, [0 x i64] zeroinitializer }, align 8
@.str.5 = private unnamed_addr constant [17 x i8] c"Foo.elements: %s\00", align 1
@"$ct.long" = linkonce constant %.introspect { i8 2, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.long" = linkonce global %.introspect { i8 2, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
entry:
%x = alloca %"char[][]", align 8

View File

@@ -27,9 +27,10 @@ fn void main()
%Foo = type { i32, i32 }
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"test.MyErr$FOO" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.test.MyErr" to i64), %"char[]" { ptr @.fault, i64 3 }, i64 1 }, align 8
@"$ct.test.MyErr" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.fault = internal constant [4 x i8] c"FOO\00", align 1
@"$ct.test.MyErr" = linkonce global %.introspect { i8 9, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
@.str.1 = private unnamed_addr constant [17 x i8] c"Not visible: %d\0A\00", align 1

View File

@@ -42,10 +42,10 @@ fn void testSimple()
%.anon = type { i32, i32 }
%.anon.0 = type { double }
@"$ct.pointer_access.c" = linkonce constant %.introspect { i8 10, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon.4" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.ExtraSimple" = linkonce constant %.introspect { i8 10, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.c" = linkonce global %.introspect { i8 10, ptr null, i64 40, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.$anon.4" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.pointer_access.ExtraSimple" = linkonce global %.introspect { i8 10, ptr null, i64 72, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [71 x i8] c"a = %d, c.e = %f, c.f = %f, c.j = %f, g = %d, o0 = %f, r = %d, s = %d\0A\00", align 1
define void @pointer_access.testSimple() #0 {

View File

@@ -32,14 +32,14 @@ fn void main()
/* #expect: test.ll
@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@.str.1 = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@.str.2 = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@.str.3 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.4 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1
@"$ct.char" = linkonce constant %.introspect { i8 3, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce constant %.introspect { i8 16, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce constant %.introspect { i8 18, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.char" = linkonce global %.introspect { i8 3, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.sa$char" = linkonce global %.introspect { i8 16, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.String" = linkonce global %.introspect { i8 18, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@.str.5 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.6 = private unnamed_addr constant [13 x i8] c"fn int(int)*\00", align 1
@.str.7 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@@ -48,8 +48,9 @@ fn void main()
@.str.10 = private unnamed_addr constant [7 x i8] c"test2*\00", align 1
@.str.11 = private unnamed_addr constant [3 x i8] c"%s\00", align 1
@.str.12 = private unnamed_addr constant [14 x i8] c"fn int!(int)*\00", align 1
@"$ct.fn$int$int$" = linkonce constant %.introspect { i8 13, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$fn$int$int$" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"$ct.fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.fn$int$int$" = linkonce global %.introspect { i8 13, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$fn$int$int$" = linkonce global %.introspect { i8 19, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.fn$int$int$" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.main() #0 {
entry:

View File

@@ -243,13 +243,13 @@ fn Type getValue(Blob blob)
%List = type { i64, i64, ptr, ptr }
%Foo = type { i32, i32 }
@"$ct.test.Bobo" = linkonce constant %.introspect { i8 10, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foor" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo2" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foor" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.MyEnum" = linkonce constant { i8, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.test.MyEnum" = linkonce global { i8, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, align 8
@"test_static$x" = internal unnamed_addr global i32 1, align 4
define void @test.Foo2.printme(ptr %0) #0 {

View File

@@ -259,13 +259,13 @@ $"$ct.int" = comdat any
$"$ct.test.MyEnum" = comdat any
@"$ct.test.Bobo" = linkonce constant %.introspect { i8 10, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Blob" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foor" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo2" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.MyEnum" = linkonce constant { i8, i64, i64, i64, [3 x %"char[]"] } { i8 8, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, comdat, align 8
@"$ct.test.Bobo" = linkonce global %.introspect { i8 10, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Blob" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foor" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo2" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, comdat, align 8
@"$ct.test.MyEnum" = linkonce global { i8, ptr, i64, i64, i64, [3 x %"char[]"] } { i8 8, ptr null, i64 4, i64 ptrtoint (ptr @"$ct.int" to i64), i64 3, [3 x %"char[]"] [%"char[]" { ptr @.enum.0, i64 4 }, %"char[]" { ptr @.enum.1, i64 5 }, %"char[]" { ptr @.enum.2, i64 3 }] }, comdat, align 8
@.str = private unnamed_addr constant [13 x i8] c"helloWorld!\0A\00", align 1
@"test_static$x" = internal unnamed_addr global i32 1, align 4
@.str.1 = private unnamed_addr constant [16 x i8] c"Test static %d\0A\00", align 1

View File

@@ -22,7 +22,8 @@ fn int main()
/* #expect: test.ll
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.retest(ptr %0, i64 %1) #0 {
entry:

View File

@@ -37,8 +37,8 @@ fn int test()
%"int[]" = type { ptr, i64 }
%"Bar[]" = type { ptr, i64 }
@"$ct.general_tests.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.general_tests.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8
@"test$foo1" = internal unnamed_addr global i32 22, align 4
@.str = private unnamed_addr constant [7 x i8] c"Hello!\00", align 1

View File

@@ -35,8 +35,8 @@ fn int main()
%Bar = type { i32, i32 }
%"Bar[]" = type { ptr, i64 }
@"$ct.statics.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.statics.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.taddr = private global [1 x %Bar] [%Bar { i32 1, i32 2 }], align 8
@"test$c" = internal unnamed_addr global %"Bar[]" { ptr @.taddr, i64 1 }, align 8
@.str = private unnamed_addr constant [7 x i8] c"%d %d\0A\00", align 1

View File

@@ -52,8 +52,8 @@ fn int main()
%File = type { ptr }
%Baz = type { double }
@"$ct.subarrays.Baz" = linkonce constant %.introspect { i8 11, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Bar" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Baz" = linkonce global %.introspect { i8 11, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.subarrays.Bar" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.taddr = private global [2 x %Bar] [%Bar { i32 3, i32 4 }, %Bar { i32 8, i32 9 }], align 8
@subarrays.arrbar = local_unnamed_addr global %"Bar[]" { ptr @.taddr, i64 2 }, align 8
@.taddr.3 = private global [2 x i32] [i32 1, i32 2], align 4
@@ -68,6 +68,7 @@ fn int main()
@.__const = private unnamed_addr constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8
@.str.9 = private unnamed_addr constant [3 x i8] c"Ok\00", align 1
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%w = alloca %Bar, align 4

View File

@@ -79,7 +79,7 @@ fn void main()
%Foo = type { i16, i8, i8, i16, i16 }
@"$ct.userland_bitcast.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@"$ct.userland_bitcast.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 5, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [16 x i8] c"%f => %d => %f\0A\00", align 1
@.str.1 = private unnamed_addr constant [18 x i8] c"%e => %llu => %e\0A\00", align 1

View File

@@ -29,7 +29,7 @@ fn void main()
%any = type { ptr, i64 }
%"int[]" = type { ptr, i64 }
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @foo.test1(i64 %0, ptr %1) #0 {
entry:

View File

@@ -85,7 +85,7 @@ fn void main()
%Foo = type { [3 x i32] }
@"$ct.foo.Foo" = linkonce constant %.introspect { i8 10, i64 12, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 12, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [11 x i8] c"getFields\0A\00", align 1
@.str.1 = private unnamed_addr constant [11 x i8] c"Call made\0A\00", align 1
@.__const = private unnamed_addr constant %Foo { [3 x i32] [i32 1, i32 5, i32 7] }, align 4

View File

@@ -35,7 +35,7 @@ extern fn int printf(char *fmt, ...);
%Foo = type { %"int[]" }
%"int[]" = type { ptr, i64 }
@"$ct.foo.Foo" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant [3 x i32] [i32 1, i32 3, i32 10], align 4
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1

View File

@@ -9,17 +9,14 @@ struct Foo { int x; void* bar; }
typedef IntFooMap = HashMap<int, Foo>;
typedef IntDoubleMap = HashMap<int, double>;
fn char[] Foo.to_string(Foo* foo, Allocator* allocator = mem::heap())
fn String Foo.to_string(Foo* foo, Allocator* allocator = mem::heap()) @dynamic
{
DString s = dstring::new_with_capacity(128, allocator);
s.printf("{%s, %p}", foo.x, foo.bar);
return s.str();
}
static initialize
{
io::formatter_register_type(Foo);
}
fn void main()
{
@@ -55,23 +52,7 @@ fn void main()
/* #expect: test.ll
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @.static_initialize.0, ptr null }]
define internal void @.static_initialize.0() {
entry:
%0 = load i64, ptr getelementptr inbounds (%"Entry*[]", ptr @std.io.tostring_functions, i32 0, i32 1), align 8
%not = icmp eq i64 %0, 0
br i1 %not, label %if.then, label %if.exit
if.then: ; preds = %entry
%1 = load ptr, ptr @std.core.mem.thread_allocator, align 8
call void @"std.collections.map$typeid$p$std.io$ToStringFunction$.HashMap.init"(ptr @std.io.tostring_functions, i32 64, float 7.500000e-01, ptr %1)
br label %if.exit
if.exit: ; preds = %if.then, %entry
%2 = call i8 @"std.collections.map$typeid$p$std.io$ToStringFunction$.HashMap.set"(ptr @std.io.tostring_functions, i64 ptrtoint (ptr @"$ct.test.Foo" to i64), ptr @test.Foo.to_string)
ret void
}
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.static_initialize.0, ptr null }]
define { ptr, i64 } @test.Foo.to_string(ptr %0, ptr %1) #0 {
entry:
@@ -102,7 +83,7 @@ entry:
; Function Attrs: nounwind
define void @test.main() #0 {
entry:
%map = alloca %HashMap.0, align 8
%map = alloca %HashMap, align 8
%retparam = alloca i64, align 8
%varargslots = alloca [1 x %any], align 16
%literal = alloca %Foo, align 8
@@ -124,7 +105,7 @@ entry:
%retparam25 = alloca i64, align 8
%varargslots26 = alloca [1 x %any], align 16
%result = alloca %"Foo[]", align 8
%map2 = alloca %HashMap.2, align 8
%map2 = alloca %HashMap.0, align 8
%retparam29 = alloca i64, align 8
%varargslots30 = alloca [1 x %any], align 16
%taddr31 = alloca i8, align 1
@@ -143,14 +124,14 @@ entry:
%varargslots52 = alloca [1 x %any], align 16
%indirectarg = alloca %"any[]", align 8
%mark = alloca i64, align 8
%map3 = alloca %HashMap.2, align 8
%map3 = alloca %HashMap.0, align 8
%retparam53 = alloca i64, align 8
%varargslots54 = alloca [1 x %any], align 16
%result55 = alloca %"int[]", align 8
call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false)
%0 = load ptr, ptr @std.core.mem.thread_allocator, align 8
call void @"std.collections.map$int$test.Foo$.HashMap.init"(ptr %map, i32 16, float 7.500000e-01, ptr %0)
%1 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2
%1 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
%2 = insertvalue %any undef, ptr %1, 0
%3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
%4 = getelementptr inbounds [1 x %any], ptr %varargslots, i64 0, i64 0
@@ -165,7 +146,7 @@ entry:
%9 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1
%hi = load ptr, ptr %9, align 8
%10 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo, ptr %hi)
%11 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2
%11 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
%12 = insertvalue %any undef, ptr %11, 0
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
%14 = getelementptr inbounds [1 x %any], ptr %varargslots2, i64 0, i64 0
@@ -180,7 +161,7 @@ entry:
%19 = getelementptr inbounds { i64, ptr }, ptr %literal3, i32 0, i32 1
%hi5 = load ptr, ptr %19, align 8
%20 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo4, ptr %hi5)
%21 = getelementptr inbounds %HashMap.0, ptr %map, i32 0, i32 2
%21 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
%22 = insertvalue %any undef, ptr %21, 0
%23 = insertvalue %any %22, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
%24 = getelementptr inbounds [1 x %any], ptr %varargslots7, i64 0, i64 0
@@ -329,3 +310,22 @@ if.exit: ; preds = %noerr_block, %after
call void @std.core.mem.allocator.Allocator.reset(ptr %104, i64 %105)
ret void
}
define internal void @.static_initialize.0() {
entry:
br label %dtable_check
dtable_check: ; preds = %dtable_next, %entry
%dtable_ref = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.test.Foo", i32 0, i32 1), %entry ], [ %next_dtable_ref, %dtable_next ]
%dtable_ptr = load ptr, ptr %dtable_ref, align 8
%0 = icmp eq ptr %dtable_ptr, null
br i1 %0, label %dtable_found, label %dtable_next
dtable_next: ; preds = %dtable_check
%next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2
br label %dtable_check
dtable_found: ; preds = %dtable_check
store ptr @"$ct.dyn.test.Foo.to_string", ptr %dtable_ref, align 8
ret void
}

View File

@@ -38,12 +38,12 @@ fn void main()
%Matrix2x2_b = type { %.anon.1 }
%.anon.1 = type { [4 x float] }
@"$ct.foo.$anon" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.3" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Matrix2x2" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.6" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.7" = linkonce constant %.introspect { i8 11, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Matrix2x2_b" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.3" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Matrix2x2" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.6" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 4, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.$anon.7" = linkonce global %.introspect { i8 11, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.foo.Matrix2x2_b" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant %Matrix2x2 { %.anon { %.anon.0 { float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00 } } }, align 4
@.__const.8 = private unnamed_addr constant %Matrix2x2_b { %.anon.1 { [4 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00] } }, align 4
@.str = private unnamed_addr constant [13 x i8] c"%f %f %f %f\0A\00", align 1

View File

@@ -16,7 +16,7 @@ fn Event test(int x)
/* #expect: test.ll
%Event = type { i32 }
@"$ct.test.Event" = linkonce constant %.introspect { i8 10, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Event" = linkonce global %.introspect { i8 10, ptr null, i64 4, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant %Event { i32 1 }, align 4
@.__const.1 = private unnamed_addr constant %Event { i32 2 }, align 4

View File

@@ -16,7 +16,7 @@ fn void test1()
%Point = type { i32, i32 }
@"$ct.test.Point" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.test.Point" = linkonce global %.introspect { i8 10, ptr null, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@.__const = private unnamed_addr constant %Point { i32 5, i32 6 }, align 4
define void @test.test1() #0 {
@@ -24,4 +24,4 @@ entry:
%p = alloca %Point, align 4
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %p, ptr align 4 @.__const, i32 8, i1 false)
ret void
}
}

View File

@@ -20,7 +20,7 @@ Foo foo8 @private = FOO7;
/* #expect: structo.ll
@"$ct.structo.Foo" = linkonce constant %.introspect { i8 10, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@"$ct.structo.Foo" = linkonce global %.introspect { i8 10, ptr null, i64 16, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
@structo.x = protected unnamed_addr global i64 16, align 8
@structo.foo1 = protected unnamed_addr global %Foo { i32 1, i64 2 }, align 8
@structo.foo2 = protected unnamed_addr global %Foo { i32 2, i64 0 }, align 8

View File

@@ -58,9 +58,9 @@ fn int main()
/* #expect: foo.ll
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce constant %.introspect { i8 1, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce global %.introspect { i8 1, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @foo.test(i64 %0, ptr %1) #0 {
entry:

View File

@@ -30,9 +30,9 @@ fn int main()
/* #expect: foo.ll
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce constant %.introspect { i8 1, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce global %.introspect { i8 1, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @foo.test(i64 %0, ptr %1) #0 {
entry:

View File

@@ -66,11 +66,11 @@ fn void main()
%any = type { ptr, i64 }
%"any[]" = type { ptr, i64 }
@"$ct.int" = linkonce constant %.introspect { i8 2, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce constant %.introspect { i8 4, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.any" = linkonce constant %.introspect { i8 7, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$int" = linkonce constant %.introspect { i8 19, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce constant %.introspect { i8 1, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.int" = linkonce global %.introspect { i8 2, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.double" = linkonce global %.introspect { i8 4, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.any" = linkonce global %.introspect { i8 7, ptr null, i64 16, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.p$int" = linkonce global %.introspect { i8 19, ptr null, i64 8, i64 ptrtoint (ptr @"$ct.int" to i64), i64 0, [0 x i64] zeroinitializer }, align 8
@"$ct.bool" = linkonce global %.introspect { i8 1, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @foo.test(i64 %0, ptr %1) #0 {
entry: