mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix alignment on all indirect. Fixed incorrect preferred alignment. Added mingw regression tests.
This commit is contained in:
@@ -23,9 +23,9 @@ ABIArgInfo *abi_arg_new_direct_coerce(AbiType *target_type);
|
||||
ABIArgInfo *abi_arg_new_expand_coerce(AbiType *target_type, unsigned offset);
|
||||
ABIArgInfo *abi_arg_new_expand_coerce_pair(AbiType *first_element, unsigned initial_offset, AbiType *second_element, unsigned padding, bool is_packed);
|
||||
ABIArgInfo *abi_arg_new_expand_padded(Type *padding);
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(unsigned alignment, Type *by_val_type);
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(AlignSize alignment, Type *by_val_type);
|
||||
ABIArgInfo *abi_arg_new_indirect_by_val(Type *by_val_type);
|
||||
ABIArgInfo *abi_arg_new_indirect_not_by_val(void);
|
||||
ABIArgInfo *abi_arg_new_indirect_not_by_val(Type *type);
|
||||
|
||||
ByteSize abi_type_abi_alignment(AbiType *type);
|
||||
bool abi_type_is_integer(AbiType *type);
|
||||
|
||||
@@ -1416,6 +1416,7 @@ typedef struct ABIArgInfo_
|
||||
bool by_reg : 1;
|
||||
bool zeroext : 1;
|
||||
bool signext : 1;
|
||||
bool realign : 1;
|
||||
} attributes;
|
||||
union
|
||||
{
|
||||
@@ -1453,7 +1454,7 @@ typedef struct ABIArgInfo_
|
||||
struct
|
||||
{
|
||||
// We may request a certain alignment of the parameters.
|
||||
AlignSize realignment;
|
||||
AlignSize alignment;
|
||||
Type *by_val_type;
|
||||
} indirect;
|
||||
};
|
||||
|
||||
@@ -84,11 +84,13 @@ bool abi_arg_is_indirect(ABIArgInfo *info)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(unsigned alignment, Type *by_val_type)
|
||||
ABIArgInfo *abi_arg_new_indirect_realigned(AlignSize alignment, Type *by_val_type)
|
||||
{
|
||||
assert(alignment > 0);
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_INDIRECT);
|
||||
info->indirect.realignment = alignment;
|
||||
info->indirect.alignment = alignment;
|
||||
assert(info->indirect.alignment);
|
||||
info->attributes.realign = true;
|
||||
info->indirect.by_val_type = by_val_type;
|
||||
return info;
|
||||
}
|
||||
@@ -96,13 +98,17 @@ ABIArgInfo *abi_arg_new_indirect_realigned(unsigned alignment, Type *by_val_type
|
||||
ABIArgInfo *abi_arg_new_indirect_by_val(Type *by_val_type)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_INDIRECT);
|
||||
info->indirect.alignment = type_abi_alignment(by_val_type);
|
||||
info->indirect.by_val_type = by_val_type;
|
||||
assert(info->indirect.alignment);
|
||||
return info;
|
||||
}
|
||||
|
||||
ABIArgInfo *abi_arg_new_indirect_not_by_val(void)
|
||||
ABIArgInfo *abi_arg_new_indirect_not_by_val(Type *type)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new(ABI_ARG_INDIRECT);
|
||||
info->indirect.alignment = type_abi_alignment(type);
|
||||
assert(info->indirect.alignment);
|
||||
info->indirect.by_val_type = NULL;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ ABIArgInfo *aarch64_classify_argument_type(Type *type)
|
||||
return info;
|
||||
}
|
||||
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
|
||||
ABIArgInfo *aarch64_classify_return_type(Type *type, bool variadic)
|
||||
|
||||
@@ -215,7 +215,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig
|
||||
}
|
||||
if (size > 16 || (size > 8 && !platform_target.int128))
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
@@ -238,7 +238,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig
|
||||
info->direct_coerce.elements = 2;
|
||||
return info;
|
||||
}
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
|
||||
static ABIArgInfo *riscv_classify_return(Type *return_type)
|
||||
|
||||
@@ -14,7 +14,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
// Variable array has to be passed indirectly.
|
||||
if (type_is_structlike(type) && type->decl->has_variable_array)
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
|
||||
Type *base = NULL;
|
||||
@@ -35,7 +35,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
return abi_arg_new_expand();
|
||||
}
|
||||
// Otherwise use indirect
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
if (is_vector)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
// HVAs are handled later.
|
||||
if (is_return || (!type_is_builtin(type->type_kind) && type->type_kind != TYPE_VECTOR))
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
// => to main handling.
|
||||
}
|
||||
@@ -60,7 +60,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
// Not 1, 2, 4, 8? Pass indirect.
|
||||
if (size > 8 || !is_power_of_two(size))
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
// Coerce to integer.
|
||||
return abi_arg_new_direct_coerce(abi_type_new_int_bits(size * 8));
|
||||
@@ -74,7 +74,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
case TYPE_U128:
|
||||
case TYPE_I128:
|
||||
// Pass by val since greater than 8 bytes.
|
||||
if (!is_return) return abi_arg_new_indirect_not_by_val();
|
||||
if (!is_return) return abi_arg_new_indirect_not_by_val(type);
|
||||
// Make i128 return in XMM0
|
||||
return abi_arg_new_direct_coerce(abi_type_new_plain(type_get_vector(type_long, 2)));
|
||||
default:
|
||||
@@ -83,7 +83,7 @@ ABIArgInfo *win64_classify(Regs *regs, Type *type, bool is_return, bool is_vecto
|
||||
}
|
||||
if (size > 8)
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ ABIArgInfo *x64_indirect_return_result(Type *type)
|
||||
{
|
||||
if (type_is_abi_aggregate(type))
|
||||
{
|
||||
return abi_arg_new_indirect_not_by_val();
|
||||
return abi_arg_new_indirect_not_by_val(type);
|
||||
}
|
||||
type = type_lowering(type);
|
||||
if (type_is_promotable_integer(type))
|
||||
|
||||
@@ -50,7 +50,7 @@ static ABIArgInfo *x86_create_indirect_result(Regs *regs, Type *type, ByVal by_v
|
||||
{
|
||||
if (by_val != BY_VAL)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new_indirect_not_by_val();
|
||||
ABIArgInfo *info = abi_arg_new_indirect_not_by_val(type);
|
||||
|
||||
if (regs->int_regs)
|
||||
{
|
||||
@@ -79,9 +79,9 @@ static ABIArgInfo *x86_create_indirect_result(Regs *regs, Type *type, ByVal by_v
|
||||
}
|
||||
|
||||
|
||||
ABIArgInfo *create_indirect_return_x86(Regs *regs)
|
||||
static ABIArgInfo *create_indirect_return_x86(Type *type, Regs *regs)
|
||||
{
|
||||
ABIArgInfo *info = abi_arg_new_indirect_not_by_val();
|
||||
ABIArgInfo *info = abi_arg_new_indirect_not_by_val(type);
|
||||
if (!regs->int_regs) return info;
|
||||
// Consume a register for the return.
|
||||
regs->int_regs--;
|
||||
@@ -191,7 +191,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type)
|
||||
{
|
||||
return abi_arg_new_direct_coerce(abi_type_new_int_bits(size * 8));
|
||||
}
|
||||
return create_indirect_return_x86(regs);
|
||||
return create_indirect_return_x86(type, regs);
|
||||
}
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
@@ -201,7 +201,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type)
|
||||
// Structs with variable arrays are always indirect.
|
||||
if (type_is_structlike(type) && type->decl->has_variable_array)
|
||||
{
|
||||
return create_indirect_return_x86(regs);
|
||||
return create_indirect_return_x86(type, regs);
|
||||
}
|
||||
// Ignore empty struct/unions
|
||||
if (type_is_empty_record(type, true))
|
||||
@@ -229,7 +229,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type)
|
||||
// This is not a single field struct, so we wrap it in an int.
|
||||
return abi_arg_new_direct_coerce(abi_type_new_int_bits(size * 8));
|
||||
}
|
||||
return create_indirect_return_x86(regs);
|
||||
return create_indirect_return_x86(type, regs);
|
||||
}
|
||||
|
||||
// Is this small enough to need to be extended?
|
||||
@@ -239,7 +239,7 @@ ABIArgInfo *x86_classify_return(CallConvention call, Regs *regs, Type *type)
|
||||
}
|
||||
|
||||
// If we support something like int128, then this is an indirect return.
|
||||
if (type_is_integer(type) && type_size(type) > 8) return create_indirect_return_x86(regs);
|
||||
if (type_is_integer(type) && type_size(type) > 8) return create_indirect_return_x86(type, regs);
|
||||
|
||||
// Otherwise we expect to just pass this nicely in the return.
|
||||
return abi_arg_new_direct();
|
||||
|
||||
@@ -2399,12 +2399,12 @@ void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, B
|
||||
case ABI_ARG_INDIRECT:
|
||||
{
|
||||
// If we want we could optimize for structs by doing it by reference here.
|
||||
unsigned alignment = info->indirect.realignment ?: type_abi_alignment(type);
|
||||
assert(info->indirect.alignment == type_abi_alignment(type) || info->attributes.realign);
|
||||
LLVMValueRef indirect = llvm_emit_alloca(c,
|
||||
llvm_get_type(c, type),
|
||||
alignment,
|
||||
info->indirect.alignment,
|
||||
"indirectarg");
|
||||
llvm_store_bevalue_aligned(c, indirect, be_value, alignment);
|
||||
llvm_store_bevalue_aligned(c, indirect, be_value, info->indirect.alignment);
|
||||
vec_add(*args, indirect);
|
||||
return;
|
||||
}
|
||||
@@ -2610,14 +2610,15 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
case ABI_ARG_INDIRECT:
|
||||
// 6a. We can use the stored error var if there is no redirect.
|
||||
if (signature->failable && c->error_var && type_abi_alignment(return_type) < ret_info->indirect.realignment)
|
||||
if (signature->failable && c->error_var && ret_info->attributes.realign)
|
||||
{
|
||||
error_var = c->error_var;
|
||||
vec_add(values, error_var);
|
||||
break;
|
||||
}
|
||||
// 6b. Return true is indirect, in this case we allocate a local, using the desired alignment on the caller side.
|
||||
AlignSize alignment = ret_info->indirect.realignment ? ret_info->indirect.realignment : type_abi_alignment(return_type);
|
||||
assert(ret_info->attributes.realign || ret_info->indirect.alignment == type_abi_alignment(return_type));
|
||||
AlignSize alignment = ret_info->indirect.alignment;
|
||||
llvm_value_set_address_align(be_value, llvm_emit_alloca(c, llvm_get_type(c, return_type), alignment, "sretparam"), return_type, alignment);
|
||||
|
||||
// 6c. Add the pointer to the list of arguments.
|
||||
|
||||
@@ -131,7 +131,7 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig
|
||||
{
|
||||
// A simple memcopy, with alignment respected.
|
||||
LLVMValueRef pointer = llvm_get_next_param(c, index);
|
||||
llvm_emit_memcpy_to_decl(c, decl, pointer, info->indirect.realignment);
|
||||
llvm_emit_memcpy_to_decl(c, decl, pointer, info->indirect.alignment);
|
||||
return;
|
||||
}
|
||||
case ABI_ARG_EXPAND_COERCE:
|
||||
@@ -274,7 +274,7 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
|
||||
switch (info->kind)
|
||||
{
|
||||
case ABI_ARG_INDIRECT:
|
||||
llvm_store_bevalue_aligned(c, return_out, return_value, info->indirect.realignment);
|
||||
llvm_store_bevalue_aligned(c, return_out, return_value, info->indirect.alignment);
|
||||
llvm_emit_return_value(c, NULL);
|
||||
return;
|
||||
case ABI_ARG_IGNORE:
|
||||
@@ -496,24 +496,17 @@ static void llvm_emit_param_attributes(GenContext *context, LLVMValueRef functio
|
||||
case ABI_ARG_EXPAND_COERCE:
|
||||
break;
|
||||
case ABI_ARG_INDIRECT:
|
||||
if (info->indirect.realignment)
|
||||
{
|
||||
llvm_attribute_add_int(context, function, attribute_align, info->indirect.realignment, index);
|
||||
}
|
||||
if (is_return)
|
||||
{
|
||||
llvm_attribute_add_int(context, function, attribute_align, type_abi_alignment(type_voidptr), 1);
|
||||
// TODO then type attributes are added to LLVM-C, use that for sret.
|
||||
llvm_attribute_add(context, function, attribute_sret, 1);
|
||||
llvm_attribute_add_int(context, function, attribute_align, info->indirect.alignment, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO then type attributes are added to LLVM-C, use that for byval.
|
||||
if (info->indirect.by_val_type) llvm_attribute_add(context, function, attribute_byval, index);
|
||||
if (!info->indirect.realignment)
|
||||
{
|
||||
llvm_attribute_add_int(context, function, attribute_align, type_abi_alignment(info->indirect.by_val_type), index);
|
||||
}
|
||||
llvm_attribute_add_int(context, function, attribute_align, info->indirect.alignment, index);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -984,7 +984,7 @@ static void type_create(const char *name, Type *location, TypeKind kind, unsigne
|
||||
.builtin.bytesize = (bitsize + 7) / 8,
|
||||
.builtin.bitsize = bitsize,
|
||||
.builtin.abi_alignment = align,
|
||||
.builtin.pref_alignment = pref_align,
|
||||
.builtin.pref_alignment = pref_align ?: align,
|
||||
.name = name,
|
||||
.canonical = location,
|
||||
};
|
||||
@@ -1138,13 +1138,13 @@ type_create(#name_, &(shortname_), type_, bits_, target->align_ ## aligned_, tar
|
||||
#undef DEF_TYPE
|
||||
|
||||
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 0, 0, 0);
|
||||
type_create("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pref_pointer, target->align_pointer);
|
||||
type_create("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pref_pointer, target->align_pointer);
|
||||
type_create("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer, target->align_pref_pointer);
|
||||
type_create("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer, target->align_pref_pointer);
|
||||
create_type_cache(type_void);
|
||||
type_void->type_cache[0] = &t.voidstar;
|
||||
t.voidstar.pointer = type_void;
|
||||
type_create("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pref_pointer, target->align_pointer);
|
||||
type_create("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pref_pointer, target->align_pointer);
|
||||
type_create("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer, target->align_pref_pointer);
|
||||
type_create("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer, target->align_pref_pointer);
|
||||
|
||||
type_create("compint", &t.ixx, TYPE_IXX, 0, 0, 0);
|
||||
type_create("compfloat", &t.fxx, TYPE_FXX, 0, 0, 0);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: x64_windows
|
||||
|
||||
func int foo()
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: x64_darwin
|
||||
|
||||
func void! test()
|
||||
{
|
||||
|
||||
44
test/test_suite/errors/rethrow_mingw.c3t
Normal file
44
test/test_suite/errors/rethrow_mingw.c3t
Normal file
@@ -0,0 +1,44 @@
|
||||
// #target: x64_mingw
|
||||
|
||||
module rethrow;
|
||||
|
||||
func void! test()
|
||||
{
|
||||
int! i;
|
||||
i!!;
|
||||
}
|
||||
|
||||
// #expect: rethrow.ll
|
||||
|
||||
define void @rethrow.test(%error_union* sret align 8 %0)
|
||||
entry:
|
||||
%i = alloca i32, align 4
|
||||
%i1 = alloca %error_union, align 8
|
||||
%error_var = alloca %error_union, align 8
|
||||
store %error_union zeroinitializer, %error_union* %i1, align 8
|
||||
store i32 0, i32* %i, align 4
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %i1, i32 0, i32 0
|
||||
%1 = load i64, i64* %err_domain, align 8
|
||||
%not_err = icmp eq i64 %1, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error:
|
||||
%2 = bitcast %error_union* %error_var to i8*
|
||||
%3 = bitcast %error_union* %i1 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %2, i8* align 8 %3, i32 16, i1 false)
|
||||
br label %guard_block
|
||||
|
||||
after_check:
|
||||
%4 = load i32, i32* %i, align 4
|
||||
br label %noerr_block
|
||||
|
||||
guard_block:
|
||||
%5 = bitcast %error_union* %0 to i8*
|
||||
%6 = bitcast %error_union* %error_var to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %5, i8* align 8 %6, i32 16, i1 false)
|
||||
ret void
|
||||
|
||||
noerr_block:
|
||||
store %error_union zeroinitializer, %error_union* %0, align 8
|
||||
ret void
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// #target: x64_darwin
|
||||
|
||||
module test;
|
||||
import test2;
|
||||
import std::array::list;
|
||||
|
||||
721
test/test_suite/functions/test_regression_mingw.c3t
Normal file
721
test/test_suite/functions/test_regression_mingw.c3t
Normal file
@@ -0,0 +1,721 @@
|
||||
// #target: x64_mingw
|
||||
|
||||
module test;
|
||||
import test2;
|
||||
import std::array::list;
|
||||
import std::array::linkedlist;
|
||||
import hello_world;
|
||||
|
||||
|
||||
extern func int printf(char *, ...);
|
||||
|
||||
func void helloWorld()
|
||||
{
|
||||
printf("helloWorld!\n");
|
||||
}
|
||||
func int test_static()
|
||||
{
|
||||
static int x = 1;
|
||||
x++;
|
||||
printf("Test static %d\n", x);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct Bobo { short b; float c; short d; short e; float f; short g; }
|
||||
|
||||
|
||||
struct Blob { int z; int f; }
|
||||
|
||||
union Foor
|
||||
{
|
||||
long a;
|
||||
char[12] b;
|
||||
}
|
||||
|
||||
|
||||
func int helo(double d, Bobo b)
|
||||
{
|
||||
int[3] de = { 1, 2, 3 };
|
||||
Bobo c = b;
|
||||
helo(1.0, c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
func int test1(int a, int b)
|
||||
{
|
||||
a = a >> b;
|
||||
if (b > 128) return -1;
|
||||
return a;
|
||||
}
|
||||
|
||||
struct Foo2
|
||||
{
|
||||
int x;
|
||||
}
|
||||
|
||||
func void Foo2.printme(Foo2 *foo)
|
||||
{
|
||||
printf("Foo is: %d\n", foo.x);
|
||||
}
|
||||
|
||||
func int Foo2.mutate(Foo2 *foo)
|
||||
{
|
||||
printf("Mutating");
|
||||
return ++foo.x;
|
||||
}
|
||||
|
||||
|
||||
extern func void test_virtual3(virtual* y);
|
||||
|
||||
interface Baz
|
||||
{
|
||||
func void open();
|
||||
func int close();
|
||||
}
|
||||
|
||||
extern func void test_virtual2(virtual Baz* z);
|
||||
|
||||
define oopsInt = test2::argh<int>;
|
||||
define oopsDouble = test2::argh<int>;
|
||||
define Argh = func int(double, Bobo);
|
||||
define Argh2 = func int(double, Bobo);
|
||||
|
||||
|
||||
|
||||
func int sum_us(int... x)
|
||||
{
|
||||
int sum = 0;
|
||||
if (x.len() == 0) return 0;
|
||||
sum += x[0] + sum_us(...x[1..^1]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
define Frob = long;
|
||||
|
||||
func int sumd(int[] x)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < x.len(); i++) sum += x[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
struct Foo
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
}
|
||||
|
||||
define getValueInt = test2::getValue<int>;
|
||||
define getValueDouble = test2::getValue<double>;
|
||||
define IntBlob = test2::Blob<int>;
|
||||
define DoubleBlob = Blob<double>;
|
||||
define getMultInt = getMult<int>;
|
||||
define getMultDouble = getMult<double>;
|
||||
|
||||
define IntArray = List<int>;
|
||||
define IntList = LinkedList<int>;
|
||||
|
||||
enum MyEnum : int
|
||||
{
|
||||
HELO = 12,
|
||||
WORLD = 14,
|
||||
BYE = -5
|
||||
}
|
||||
|
||||
|
||||
func void main()
|
||||
{
|
||||
test_static();
|
||||
test_static();
|
||||
test_static();
|
||||
hello_world::hello();
|
||||
IntList list;
|
||||
list.push(10);
|
||||
list.push(15);
|
||||
list.push(30);
|
||||
for (int i = 0; i < (int)(list.len()); i++)
|
||||
{
|
||||
printf("Element[%d]: %d\n", i, list.get(i));
|
||||
}
|
||||
list.free();
|
||||
|
||||
printf("Min %d Max %d Elements: %d\n", MyEnum.min, MyEnum.max, MyEnum.elements);
|
||||
|
||||
int max = MyEnum.max;
|
||||
int min = MyEnum.min;
|
||||
int elements = MyEnum.elements;
|
||||
printf("Hello\n");
|
||||
IntArray array;
|
||||
array.append(100);
|
||||
array.append(200);
|
||||
array.append(400);
|
||||
array.push(600);
|
||||
array.insertAt(2, 300);
|
||||
for (int i = 0; i < (int)(array.len()); i++)
|
||||
{
|
||||
printf("Element[%d]: %d\n", i, array.get(i));
|
||||
}
|
||||
array.free();
|
||||
IntBlob a = { 42 };
|
||||
DoubleBlob b = { 33.3 };
|
||||
printf("a was %d\n", getValueInt(a));
|
||||
printf("b was %f\n", getValueDouble(b));
|
||||
printf("Mult int was %d\n", getMultInt(25));
|
||||
printf("Mult double was %f\n", getMultDouble(3.3));
|
||||
|
||||
|
||||
helloWorld();
|
||||
Foo ddx;
|
||||
int fro = 3;
|
||||
int[4] x = { 1, 2, 3, 3 };
|
||||
fro += printf("1Vararg4unsplatA: %d\n", sum_us(...x));
|
||||
printf("%d\n", fro);
|
||||
int[] z = &x;
|
||||
int[3] de = { 1, 2, 3 };
|
||||
printf("Vararg4unsplatB: %d\n", sum_us(...&x));
|
||||
printf("Vararg4unsplatC: %d\n", sum_us(...z));
|
||||
printf("Vararg4: %d\n", sum_us(1, 2, 4, 5));
|
||||
printf("Vararg1: %d\n", sum_us(1));
|
||||
printf("Vararg0: %d\n", sum_us());
|
||||
Argh a1;
|
||||
Argh2 b2;
|
||||
}
|
||||
|
||||
module hello_world;
|
||||
import foo;
|
||||
|
||||
extern func int printf(char *, ...);
|
||||
define doubleMult = check<double>;
|
||||
|
||||
func void hello()
|
||||
{
|
||||
printf("Hello baby\n");
|
||||
printf("Mult %f\n", doubleMult(11.1));
|
||||
}
|
||||
|
||||
module foo <Type>;
|
||||
|
||||
func Type check(Type i)
|
||||
{
|
||||
return i * i;
|
||||
}
|
||||
|
||||
module test2 <Type>;
|
||||
|
||||
struct Blob
|
||||
{
|
||||
Type a;
|
||||
}
|
||||
|
||||
func Type getMult(Type a)
|
||||
{
|
||||
return a * a;
|
||||
}
|
||||
Type argh = 234;
|
||||
|
||||
error MyErr
|
||||
{
|
||||
Type x;
|
||||
}
|
||||
|
||||
enum Hello : int
|
||||
{
|
||||
FOO = 3,
|
||||
BAR = 4,
|
||||
}
|
||||
|
||||
macro Hello wut()
|
||||
{
|
||||
return Hello.FOO;
|
||||
}
|
||||
|
||||
define Bye = Hello;
|
||||
define wat = wut;
|
||||
define byebye = hello;
|
||||
|
||||
func int hello()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
func Type getValue(Blob blob)
|
||||
{
|
||||
return blob.a;
|
||||
}
|
||||
|
||||
// #expect: test.ll
|
||||
|
||||
%Blob = type { i32 }
|
||||
%Blob.0 = type { double }
|
||||
%List = type { i64, i64, i32* }
|
||||
%LinkedList = type { i64, %Node*, %Node* }
|
||||
%Node = type { %Node*, %Node*, i32 }
|
||||
%Foo2 = type { i32 }
|
||||
%Bobo = type { i16, float, i16, i16, float, i16 }
|
||||
%"virtual*" = type { i8*, i64 }
|
||||
%"virtual$" = type { i8*, i64 }
|
||||
%"int[]" = type { i32*, i64 }
|
||||
%Foo = type { i32, i32 }
|
||||
|
||||
define void @test.Foo2__printme(%Foo2* %0)
|
||||
entry:
|
||||
%foo = alloca %Foo2*, align 8
|
||||
store %Foo2* %0, %Foo2** %foo, align 8
|
||||
%1 = load %Foo2*, %Foo2** %foo, align 8
|
||||
%2 = getelementptr inbounds %Foo2, %Foo2* %1, i32 0, i32 0
|
||||
%3 = load i32, i32* %2, align 8
|
||||
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.21, i32 0, i32 0), i32 %3)
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @test.Foo2__mutate(%Foo2* %0)
|
||||
entry:
|
||||
%foo = alloca %Foo2*, align 8
|
||||
store %Foo2* %0, %Foo2** %foo, align 8
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.22, i32 0, i32 0))
|
||||
%2 = load %Foo2*, %Foo2** %foo, align 8
|
||||
%3 = getelementptr inbounds %Foo2, %Foo2* %2, i32 0, i32 0
|
||||
%4 = load i32, i32* %3, align 8
|
||||
%add = add i32 %4, 1
|
||||
store i32 %add, i32* %3, align 8
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
define void @test.helloWorld()
|
||||
entry:
|
||||
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @test.test_static()
|
||||
entry:
|
||||
%0 = load i32, i32* @test_static.x, align 4
|
||||
%add = add i32 %0, 1
|
||||
store i32 %add, i32* @test_static.x, align 4
|
||||
%1 = load i32, i32* @test_static.x, align 4
|
||||
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.1, i32 0, i32 0), i32 %1)
|
||||
%3 = load i32, i32* @test_static.x, align 4
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
define i32 @test.helo(double %0, %Bobo* align 4 %1)
|
||||
%d = alloca double, align 8
|
||||
%b = alloca %Bobo, align 4
|
||||
%de = alloca [3 x i32], align 4
|
||||
%c = alloca %Bobo, align 4
|
||||
%indirectarg = alloca %Bobo, align 4
|
||||
store double %0, double* %d, align 8
|
||||
%2 = bitcast %Bobo* %b to i8*
|
||||
%3 = bitcast %Bobo* %1 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %2, i8* align 4 %3, i32 20, i1 false)
|
||||
%4 = bitcast [3 x i32]* %de to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %4, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
|
||||
%5 = bitcast %Bobo* %c to i8*
|
||||
%6 = bitcast %Bobo* %b to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %5, i8* align 4 %6, i32 20, i1 false)
|
||||
%7 = bitcast %Bobo* %indirectarg to i8*
|
||||
%8 = bitcast %Bobo* %c to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %7, i8* align 4 %8, i32 20, i1 false)
|
||||
%9 = call i32 @test.helo(double 1.000000e+00, %Bobo* %indirectarg)
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
define i32 @test.test1(i32 %0, i32 %1)
|
||||
%a = alloca i32, align 4
|
||||
%b = alloca i32, align 4
|
||||
store i32 %0, i32* %a, align 4
|
||||
store i32 %1, i32* %b, align 4
|
||||
%2 = load i32, i32* %a, align 4
|
||||
%3 = load i32, i32* %b, align 4
|
||||
%ashr = ashr i32 %2, %3
|
||||
%4 = freeze i32 %ashr
|
||||
store i32 %4, i32* %a, align 4
|
||||
%5 = load i32, i32* %b, align 4
|
||||
%gt = icmp sgt i32 %5, 128
|
||||
br i1 %gt, label %if.then, label %if.exit
|
||||
|
||||
ret i32 -1
|
||||
|
||||
%6 = load i32, i32* %a, align 4
|
||||
ret i32 %6
|
||||
}
|
||||
|
||||
declare void @test_virtual3(%"virtual*"* align 8)
|
||||
|
||||
declare void @test_virtual2(%"virtual$"* align 8)
|
||||
|
||||
define i32 @test.sum_us(%"int[]"* align 8 %0)
|
||||
entry:
|
||||
%x = alloca %"int[]", align 8
|
||||
%sum = alloca i32, align 4
|
||||
%vararg = alloca %"int[]", align 8
|
||||
%indirectarg = alloca %"int[]", align 8
|
||||
%1 = bitcast %"int[]"* %x to i8*
|
||||
%2 = bitcast %"int[]"* %0 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 16, i1 false)
|
||||
store i32 0, i32* %sum, align 4
|
||||
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
||||
%3 = load i64, i64* %len, align 8
|
||||
%eq = icmp eq i64 %3, 0
|
||||
br i1 %eq, label %if.then, label %if.exit
|
||||
|
||||
if.then:
|
||||
ret i32 0
|
||||
|
||||
if.exit:
|
||||
%4 = load i32, i32* %sum, align 4
|
||||
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0
|
||||
%saptr = load i32*, i32** %subarrayptr, align 8
|
||||
%sarridx = getelementptr inbounds i32, i32* %saptr, i64 0
|
||||
%5 = load i32, i32* %sarridx, align 4
|
||||
%6 = load %"int[]", %"int[]"* %x, align 8
|
||||
%7 = extractvalue %"int[]" %6, 0
|
||||
%8 = extractvalue %"int[]" %6, 1
|
||||
%sub = sub i64 %8, 1
|
||||
%9 = add i64 %sub, 1
|
||||
%size = sub i64 %9, 1
|
||||
%offsetsub = getelementptr inbounds i32, i32* %7, i64 1
|
||||
%10 = insertvalue %"int[]" undef, i32* %offsetsub, 0
|
||||
%11 = insertvalue %"int[]" %10, i64 %size, 1
|
||||
%12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1
|
||||
%13 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0
|
||||
store %"int[]" %11, %"int[]"* %indirectarg, align 8
|
||||
%14 = call i32 @test.sum_us(%"int[]"* %indirectarg)
|
||||
%add = add i32 %5, %14
|
||||
%add1 = add i32 %4, %add
|
||||
store i32 %add1, i32* %sum, align 4
|
||||
%15 = load i32, i32* %sum, align 4
|
||||
ret i32 %15
|
||||
}
|
||||
|
||||
define i32 @test.sumd(%"int[]"* align 8 %0)
|
||||
entry:
|
||||
%x = alloca %"int[]", align 8
|
||||
%sum = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
%1 = bitcast %"int[]"* %x to i8*
|
||||
%2 = bitcast %"int[]"* %0 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 16, i1 false)
|
||||
store i32 0, i32* %sum, align 4
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond:
|
||||
%3 = load i32, i32* %i, align 4
|
||||
%sisiext = sext i32 %3 to i64
|
||||
%len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
||||
%4 = load i64, i64* %len, align 8
|
||||
%lt = icmp slt i64 %sisiext, %4
|
||||
%check = icmp slt i64 %4, 0
|
||||
%siui-lt = or i1 %check, %lt
|
||||
br i1 %siui-lt, label %for.body, label %for.exit
|
||||
|
||||
for.body:
|
||||
%5 = load i32, i32* %sum, align 4
|
||||
%subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0
|
||||
%saptr = load i32*, i32** %subarrayptr, align 8
|
||||
%6 = load i32, i32* %i, align 4
|
||||
%sisiext1 = sext i32 %6 to i64
|
||||
%sarridx = getelementptr inbounds i32, i32* %saptr, i64 %sisiext1
|
||||
%7 = load i32, i32* %sarridx, align 4
|
||||
%add = add i32 %5, %7
|
||||
store i32 %add, i32* %sum, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc:
|
||||
%8 = load i32, i32* %i, align 4
|
||||
%add2 = add i32 %8, 1
|
||||
store i32 %add2, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.exit:
|
||||
%9 = load i32, i32* %sum, align 4
|
||||
ret i32 %9
|
||||
}
|
||||
|
||||
define void @main()
|
||||
entry:
|
||||
%list = alloca %LinkedList, align 8
|
||||
%i = alloca i32, align 4
|
||||
%max = alloca i32, align 4
|
||||
%min = alloca i32, align 4
|
||||
%elements = alloca i32, align 4
|
||||
%array = alloca %List, align 8
|
||||
%i1 = alloca i32, align 4
|
||||
%a = alloca %Blob, align 4
|
||||
%b = alloca %Blob.0, align 8
|
||||
%ddx = alloca %Foo, align 4
|
||||
%fro = alloca i32, align 4
|
||||
%x = alloca [4 x i32], align 4
|
||||
%vararg = alloca %"int[]", align 8
|
||||
%indirectarg = alloca %"int[]", align 8
|
||||
%z = alloca %"int[]", align 8
|
||||
%de = alloca [3 x i32], align 4
|
||||
%vararg12 = alloca %"int[]", align 8
|
||||
%indirectarg13 = alloca %"int[]", align 8
|
||||
%vararg14 = alloca %"int[]", align 8
|
||||
%indirectarg15 = alloca %"int[]", align 8
|
||||
%vararg16 = alloca %"int[]", align 8
|
||||
%varargslots = alloca [4 x i32], align 4
|
||||
%indirectarg17 = alloca %"int[]", align 8
|
||||
%vararg18 = alloca %"int[]", align 8
|
||||
%varargslots19 = alloca [1 x i32], align 4
|
||||
%indirectarg20 = alloca %"int[]", align 8
|
||||
%vararg21 = alloca %"int[]", align 8
|
||||
%indirectarg22 = alloca %"int[]", align 8
|
||||
%a1 = alloca i32 (double, %Bobo*)*, align 8
|
||||
%b2 = alloca i32 (double, %Bobo*)*, align 8
|
||||
%0 = call i32 @test.test_static()
|
||||
%1 = call i32 @test.test_static()
|
||||
%2 = call i32 @test.test_static()
|
||||
call void @hello_world.hello()
|
||||
%3 = bitcast %LinkedList* %list to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 24, i1 false)
|
||||
call void @"std::array::linkedlist.int.LinkedList__push"(%LinkedList* %list, i32 10)
|
||||
call void @"std::array::linkedlist.int.LinkedList__push"(%LinkedList* %list, i32 15)
|
||||
call void @"std::array::linkedlist.int.LinkedList__push"(%LinkedList* %list, i32 30)
|
||||
store i32 0, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.cond:
|
||||
%4 = load i32, i32* %i, align 4
|
||||
%5 = call i64 @"std::array::linkedlist.int.LinkedList__len"(%LinkedList* %list)
|
||||
%uisitrunc = trunc i64 %5 to i32
|
||||
%lt = icmp slt i32 %4, %uisitrunc
|
||||
br i1 %lt, label %for.body, label %for.exit
|
||||
|
||||
for.body:
|
||||
%6 = load i32, i32* %i, align 4
|
||||
%7 = load i32, i32* %i, align 4
|
||||
%siuiext = zext i32 %7 to i64
|
||||
%8 = call i32 @"std::array::linkedlist.int.LinkedList__get"(%LinkedList* %list, i64 %siuiext)
|
||||
%9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.2, i32 0, i32 0), i32 %6, i32 %8)
|
||||
br label %for.inc
|
||||
|
||||
for.inc:
|
||||
%10 = load i32, i32* %i, align 4
|
||||
%add = add i32 %10, 1
|
||||
store i32 %add, i32* %i, align 4
|
||||
br label %for.cond
|
||||
|
||||
for.exit:
|
||||
call void @"std::array::linkedlist.int.LinkedList__free"(%LinkedList* %list)
|
||||
%11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str.3, i32 0, i32 0), i32 -5, i32 14, i32 3)
|
||||
store i32 14, i32* %max, align 4
|
||||
store i32 -5, i32* %min, align 4
|
||||
store i32 3, i32* %elements, align 4
|
||||
%12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0))
|
||||
%13 = bitcast %List* %array to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %13, i8 0, i64 24, i1 false)
|
||||
call void @"std::array::list.int.List__append"(%List* %array, i32 100)
|
||||
call void @"std::array::list.int.List__append"(%List* %array, i32 200)
|
||||
call void @"std::array::list.int.List__append"(%List* %array, i32 400)
|
||||
call void @"std::array::list.int.List__push"(%List* %array, i32 600)
|
||||
call void @"std::array::list.int.List__insertAt"(%List* %array, i64 2, i32 300)
|
||||
store i32 0, i32* %i1, align 4
|
||||
br label %for.cond2
|
||||
|
||||
for.cond2:
|
||||
%14 = load i32, i32* %i1, align 4
|
||||
%15 = call i64 @"std::array::list.int.List__len"(%List* %array)
|
||||
%uisitrunc3 = trunc i64 %15 to i32
|
||||
%lt4 = icmp slt i32 %14, %uisitrunc3
|
||||
br i1 %lt4, label %for.body5, label %for.exit9
|
||||
|
||||
for.body5:
|
||||
%16 = load i32, i32* %i1, align 4
|
||||
%17 = load i32, i32* %i1, align 4
|
||||
%siuiext6 = zext i32 %17 to i64
|
||||
%18 = call i32 @"std::array::list.int.List__get"(%List* %array, i64 %siuiext6)
|
||||
%19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.5, i32 0, i32 0), i32 %16, i32 %18)
|
||||
br label %for.inc7
|
||||
|
||||
for.inc7:
|
||||
%20 = load i32, i32* %i1, align 4
|
||||
%add8 = add i32 %20, 1
|
||||
store i32 %add8, i32* %i1, align 4
|
||||
br label %for.cond2
|
||||
|
||||
for.exit9:
|
||||
call void @"std::array::list.int.List__free"(%List* %array)
|
||||
%21 = bitcast %Blob* %a to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %21, i8* align 4 bitcast (%Blob* @.__const.6 to i8*), i32 4, i1 false)
|
||||
%22 = bitcast %Blob.0* %b to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %22, i8* align 8 bitcast (%Blob.0* @.__const.7 to i8*), i32 8, i1 false)
|
||||
%23 = bitcast %Blob* %a to i32*
|
||||
%coerced = load i32, i32* %23, align 4
|
||||
%24 = call i32 @test2.int.getValue(i32 %coerced)
|
||||
%25 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.8, i32 0, i32 0), i32 %24)
|
||||
%26 = bitcast %Blob.0* %b to i64*
|
||||
%coerced10 = load i64, i64* %26, align 8
|
||||
%27 = call double @test2.double.getValue(i64 %coerced10)
|
||||
%28 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.9, i32 0, i32 0), double %27)
|
||||
%29 = call i32 @test2.int.getMult(i32 25)
|
||||
%30 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.10, i32 0, i32 0), i32 %29)
|
||||
%31 = call double @test2.double.getMult(double 3.300000e+00)
|
||||
%32 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.11, i32 0, i32 0), double %31)
|
||||
call void @test.helloWorld()
|
||||
%33 = bitcast %Foo* %ddx to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %33, i8 0, i64 8, i1 false)
|
||||
store i32 3, i32* %fro, align 4
|
||||
%34 = bitcast [4 x i32]* %x to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %34, i8* align 4 bitcast ([4 x i32]* @.__const.12 to i8*), i32 16, i1 false)
|
||||
%35 = load i32, i32* %fro, align 4
|
||||
%36 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1
|
||||
%37 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0
|
||||
store i64 4, i64* %36, align 8
|
||||
%38 = bitcast [4 x i32]* %x to i32*
|
||||
store i32* %38, i32** %37, align 8
|
||||
%39 = bitcast %"int[]"* %indirectarg to i8*
|
||||
%40 = bitcast %"int[]"* %vararg to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %39, i8* align 8 %40, i32 16, i1 false)
|
||||
%41 = call i32 @test.sum_us(%"int[]"* %indirectarg)
|
||||
%42 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.13, i32 0, i32 0), i32 %41)
|
||||
%add11 = add i32 %35, %42
|
||||
store i32 %add11, i32* %fro, align 4
|
||||
%43 = load i32, i32* %fro, align 4
|
||||
%44 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.14, i32 0, i32 0), i32 %43)
|
||||
%45 = bitcast [4 x i32]* %x to i32*
|
||||
%46 = insertvalue %"int[]" undef, i32* %45, 0
|
||||
%47 = insertvalue %"int[]" %46, i64 4, 1
|
||||
store %"int[]" %47, %"int[]"* %z, align 8
|
||||
%48 = bitcast [3 x i32]* %de to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %48, i8* align 4 bitcast ([3 x i32]* @.__const.15 to i8*), i32 12, i1 false)
|
||||
%49 = getelementptr inbounds %"int[]", %"int[]"* %vararg12, i32 0, i32 1
|
||||
%50 = getelementptr inbounds %"int[]", %"int[]"* %vararg12, i32 0, i32 0
|
||||
store i64 4, i64* %49, align 8
|
||||
%51 = bitcast [4 x i32]* %x to i32*
|
||||
store i32* %51, i32** %50, align 8
|
||||
%52 = bitcast %"int[]"* %indirectarg13 to i8*
|
||||
%53 = bitcast %"int[]"* %vararg12 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %52, i8* align 8 %53, i32 16, i1 false)
|
||||
%54 = call i32 @test.sum_us(%"int[]"* %indirectarg13)
|
||||
%55 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.16, i32 0, i32 0), i32 %54)
|
||||
%56 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 1
|
||||
%57 = getelementptr inbounds %"int[]", %"int[]"* %vararg14, i32 0, i32 0
|
||||
%58 = bitcast %"int[]"* %indirectarg15 to i8*
|
||||
%59 = bitcast %"int[]"* %z to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %58, i8* align 8 %59, i32 16, i1 false)
|
||||
%60 = call i32 @test.sum_us(%"int[]"* %indirectarg15)
|
||||
%61 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.17, i32 0, i32 0), i32 %60)
|
||||
%62 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 0
|
||||
store i32 1, i32* %62, align 4
|
||||
%63 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 1
|
||||
store i32 2, i32* %63, align 4
|
||||
%64 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 2
|
||||
store i32 4, i32* %64, align 4
|
||||
%65 = getelementptr inbounds [4 x i32], [4 x i32]* %varargslots, i64 0, i64 3
|
||||
store i32 5, i32* %65, align 4
|
||||
%66 = getelementptr inbounds %"int[]", %"int[]"* %vararg16, i32 0, i32 1
|
||||
store i64 4, i64* %66, align 8
|
||||
%67 = getelementptr inbounds %"int[]", %"int[]"* %vararg16, i32 0, i32 0
|
||||
%68 = bitcast [4 x i32]* %varargslots to i32*
|
||||
store i32* %68, i32** %67, align 8
|
||||
%69 = bitcast %"int[]"* %indirectarg17 to i8*
|
||||
%70 = bitcast %"int[]"* %vararg16 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %69, i8* align 8 %70, i32 16, i1 false)
|
||||
%71 = call i32 @test.sum_us(%"int[]"* %indirectarg17)
|
||||
%72 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.18, i32 0, i32 0), i32 %71)
|
||||
%73 = getelementptr inbounds [1 x i32], [1 x i32]* %varargslots19, i64 0, i64 0
|
||||
store i32 1, i32* %73, align 4
|
||||
%74 = getelementptr inbounds %"int[]", %"int[]"* %vararg18, i32 0, i32 1
|
||||
store i64 1, i64* %74, align 8
|
||||
%75 = getelementptr inbounds %"int[]", %"int[]"* %vararg18, i32 0, i32 0
|
||||
%76 = bitcast [1 x i32]* %varargslots19 to i32*
|
||||
store i32* %76, i32** %75, align 8
|
||||
%77 = bitcast %"int[]"* %indirectarg20 to i8*
|
||||
%78 = bitcast %"int[]"* %vararg18 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %77, i8* align 8 %78, i32 16, i1 false)
|
||||
%79 = call i32 @test.sum_us(%"int[]"* %indirectarg20)
|
||||
%80 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0), i32 %79)
|
||||
%81 = getelementptr inbounds %"int[]", %"int[]"* %vararg21, i32 0, i32 1
|
||||
store i64 0, i64* %81, align 8
|
||||
%82 = bitcast %"int[]"* %indirectarg22 to i8*
|
||||
%83 = bitcast %"int[]"* %vararg21 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %82, i8* align 8 %83, i32 16, i1 false)
|
||||
%84 = call i32 @test.sum_us(%"int[]"* %indirectarg22)
|
||||
%85 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.20, i32 0, i32 0), i32 %84)
|
||||
store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %a1, align 8
|
||||
store i32 (double, %Bobo*)* null, i32 (double, %Bobo*)** %b2, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
// #expect: hello_world.ll
|
||||
|
||||
define void @hello_world.hello()
|
||||
entry:
|
||||
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))
|
||||
%1 = call double @foo.double.check(double 1.110000e+01)
|
||||
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1, i32 0, i32 0), double %1)
|
||||
ret void
|
||||
|
||||
// #expect: foo.double.ll
|
||||
|
||||
define double @foo.double.check(double %0)
|
||||
entry:
|
||||
%i = alloca double, align 8
|
||||
store double %0, double* %i, align 8
|
||||
%1 = load double, double* %i, align 8
|
||||
%2 = load double, double* %i, align 8
|
||||
%fmul = fmul double %1, %2
|
||||
ret double %fmul
|
||||
|
||||
|
||||
// #expect: test2.int.ll
|
||||
|
||||
%Blob = type { i32 }
|
||||
@test2.int.argh = global i32 234, align 4
|
||||
|
||||
define i32 @test2.int.getMult(i32 %0)
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
store i32 %0, i32* %a, align 4
|
||||
%1 = load i32, i32* %a, align 4
|
||||
%2 = load i32, i32* %a, align 4
|
||||
%mul = mul i32 %1, %2
|
||||
ret i32 %mul
|
||||
|
||||
define i32 @test2.int.hello()
|
||||
entry:
|
||||
ret i32 1
|
||||
}
|
||||
|
||||
define i32 @test2.int.getValue(i32 %0)
|
||||
entry:
|
||||
%blob = alloca %Blob, align 4
|
||||
%coerce = bitcast %Blob* %blob to i32*
|
||||
store i32 %0, i32* %coerce, align 4
|
||||
%1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0
|
||||
%2 = load i32, i32* %1, align 4
|
||||
ret i32 %2
|
||||
|
||||
|
||||
// #expect: test2.double.ll
|
||||
|
||||
%Blob = type { double }
|
||||
@test2.double.argh = global double 2.340000e+02, align 8
|
||||
|
||||
define double @test2.double.getMult(double %0)
|
||||
entry:
|
||||
%a = alloca double, align 8
|
||||
store double %0, double* %a, align 8
|
||||
%1 = load double, double* %a, align 8
|
||||
%2 = load double, double* %a, align 8
|
||||
%fmul = fmul double %1, %2
|
||||
ret double %fmul
|
||||
|
||||
|
||||
define i32 @test2.double.hello()
|
||||
entry:
|
||||
ret i32 1
|
||||
|
||||
define double @test2.double.getValue(i64 %0)
|
||||
entry:
|
||||
%blob = alloca %Blob, align 8
|
||||
%coerce = bitcast %Blob* %blob to i64*
|
||||
store i64 %0, i64* %coerce, align 8
|
||||
%1 = getelementptr inbounds %Blob, %Blob* %blob, i32 0, i32 0
|
||||
%2 = load double, double* %1, align 8
|
||||
ret double %2
|
||||
|
||||
Reference in New Issue
Block a user