Set stdlib library for testing and profit. Fix bugs when using void* to step. Make constants private linkage. Compare pointers using unsigned comparison without conversion. Use manual ptrdiff code. Fix issue returning "void!". Unify pointers when doing Foo* - void*. Allow comparing for example void* < Foo*

This commit is contained in:
Christoffer Lerno
2021-04-29 03:09:37 +02:00
committed by Christoffer Lerno
parent 01f7343945
commit 0e076234ca
25 changed files with 268 additions and 49 deletions

View File

@@ -1,9 +1,118 @@
module std::mem;
extern func void* _malloc(usize bytes) @cname("malloc");
extern func void* _realloc(void* ptr, usize bytes) @cname("realloc");
extern func void* _calloc(usize bytes, usize elements) @cname("calloc");
extern func void _free(void* ptr) @cname("free");
public enum AllocationKind
{
ALLOC,
REALLOC,
FREE,
}
public enum AllocationFailureKind
{
OUT_OF_MEMORY
}
public error AllocationFailure
{
AllocationFailureKind failureKind;
}
public typedef func void!(void *data, void** pointer, usize bytes, usize alignment, AllocationKind kind) as AllocatorFunction;
public struct Allocator
{
AllocatorFunction allocation_function;
void *data;
}
public func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline
{
switch (kind)
{
case ALLOC:
void* data = _malloc(bytes);
if (!data) return AllocationFailure({ OUT_OF_MEMORY })!;
*pointer = data;
return;
case REALLOC:
void* data = _realloc(*pointer, bytes);
if (!data) return AllocationFailure({ OUT_OF_MEMORY })!;
*pointer = data;
return;
case FREE:
_free(*pointer);
*pointer = null;
return;
}
$unreachable;
}
public struct RingAllocator
{
char *data;
usize size;
usize offset;
}
public func void* RingAllocator.alloc(RingAllocator *allocator, usize size)
{
if (size > allocator.size) return null;
// Wraparound? If so, start at the beginning.
if (allocator.offset + size > allocator.size)
{
allocator.offset = size;
return allocator.data;
}
void* data = allocator.offset + allocator.data;
allocator.offset = (allocator.offset + size) & allocator.size;
return data;
}
public func void* RingAllocator.realloc(RingAllocator *allocator, void* ptr, usize size)
{
if (size > allocator.size) return null;
assert(allocator.data >= ptr && ptr < allocator.data + size, "Realloc on other allocator.");
// 1. The pointer is before the allocator
if (allocator.data + allocator.offset > ptr)
{
if (allocator.data + allocator.size < ptr + size)
{
// 1a. There is not enough space, we need to copy to the start.
usize pointer_offset = ptr - allocator.data;
usize copy_len = pointer_offset + size > allocator.offset ? allocator.offset - pointer_offset : size;
//memcpy(allocator.data, ptr, copy_len);
allocator.offset = size;
return allocator.data;
}
// 1b. There is enough space, so we just change the offset:
allocator.offset = ptr - allocator.data + size;
return ptr;
}
// 2. The pointer is after the allocator
// 2a. Is there sufficient space?
if (ptr + size <= allocator.data + allocator.size)
{
// Good, if so we simply change the offset and return the pointer.
allocator.offset = ptr - allocator.data + size;
return ptr;
}
// 2b. Not sufficient space, we copy to the beginning.
usize pointer_offset = ptr - allocator.data;
usize copy_len = allocator.size - (ptr - allocator.data);
if (copy_len > size) copy_len = size;
//memcpy(allocator.data, ptr, copy_len);
allocator.offset = size;
return allocator.data;
}
public Allocator main_allocator = { &system_malloc_function, null };
public macro malloc($Type)
{
// TODO: return cast(_malloc($Type.sizeof) as $Type*);

View File

@@ -0,0 +1,32 @@
module std::runtime;
struct VirtualAny
{
void* ptr;
typeid type_id;
}
struct VirtualContainer
{
void* ptr;
void* impl_ptr;
}
struct SubArrayContainer
{
void* ptr;
usize len;
}
struct VarArrayHeader
{
usize size;
usize capacity;
void *allocator;
}
struct VarArrayContainer
{
}

View File

@@ -63,7 +63,8 @@ static void usage(void)
OUTPUT(" headers <file1> [<file2> ...] Analyse files and generate C headers for public methods.");
OUTPUT("");
OUTPUT("Options:");
OUTPUT(" --lib <dir> - Use this directory as the c3 library path.");
OUTPUT(" --stdlib <dir> - Use this directory as the C3 standard library path.");
OUTPUT(" --lib <dir> - Use this directory as the C3 library path.");
OUTPUT(" --path <dir> - Use this as the base directory for the current command.");
OUTPUT(" --template <template> - Use a different template: \"lib\", \"staticlib\" or a path.");
OUTPUT(" --about - Prints a short description of C3.");
@@ -354,6 +355,12 @@ static void parse_option(BuildOptions *options)
options->emit_llvm = true;
return;
}
if (match_longopt("stdlib"))
{
if (at_end() || next_is_opt()) error_exit("error: --stdlib needs a directory.");
options->std_lib_dir = check_dir(next_arg());
return;
}
if (match_longopt("lib"))
{
if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory.");

View File

@@ -164,6 +164,7 @@ typedef enum
typedef struct BuildOptions_
{
const char* lib_dir[MAX_LIB_DIRS];
const char* std_lib_dir;
int lib_count;
const char** files;
const char* project_name;

View File

@@ -16,7 +16,7 @@ Vmem tokdata_arena;
Vmem decl_arena;
Vmem type_info_arena;
void compiler_init(void)
void compiler_init(const char *std_lib_dir)
{
// Skip library detection.
//compiler.lib_dir = find_lib_dir();
@@ -34,7 +34,14 @@ void compiler_init(void)
(void) sourceloc_calloc();
(void) toktype_calloc();
(void) tokdata_calloc();
compiler.lib_dir = find_lib_dir();
if (std_lib_dir)
{
compiler.lib_dir = std_lib_dir;
}
else
{
compiler.lib_dir = find_lib_dir();
}
}
static void compiler_lex(BuildTarget *target)
@@ -79,6 +86,7 @@ void compiler_compile(BuildTarget *target)
diag_setup(target->test_output);
if (compiler.lib_dir)
{
vec_add(target->sources, strformat("%s/std/runtime.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/builtin.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/io.c3", compiler.lib_dir));
vec_add(target->sources, strformat("%s/std/mem.c3", compiler.lib_dir));

View File

@@ -6,7 +6,7 @@
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
void compiler_init();
void compiler_init(const char *std_lib_dir);
void compile_files(BuildTarget *target);
void init_build_target(BuildTarget *build_target, BuildOptions *build_options);
void init_default_build_target(BuildTarget *target, BuildOptions *options, const char *name);

View File

@@ -136,7 +136,7 @@ static inline LLVMValueRef llvm_emit_subscript_addr_with_base(GenContext *c, Typ
{
case TYPE_POINTER:
return LLVMBuildInBoundsGEP2(c->builder,
llvm_get_type(c, type->pointer),
llvm_get_pointee_type(c, type),
parent_value, &index_value, 1, "ptridx");
case TYPE_ARRAY:
{
@@ -605,7 +605,8 @@ static inline void llvm_emit_initialize_reference_temporary_const(GenContext *c,
// Create a global const.
LLVMTypeRef type = modified ? LLVMTypeOf(value) : llvm_get_type(c, expr->type);
LLVMValueRef global_copy = LLVMAddGlobal(c->module, type, "");
LLVMValueRef global_copy = LLVMAddGlobal(c->module, type, ".__const");
LLVMSetLinkage(global_copy, LLVMPrivateLinkage);
// Set a nice alignment
unsigned alignment = type_alloca_alignment(expr->type);
@@ -972,7 +973,7 @@ static inline void llvm_emit_inc_dec_change(GenContext *c, bool use_mod, BEValue
{
// Use byte here, we don't need a big offset.
LLVMValueRef add = LLVMConstInt(diff < 0 ? llvm_get_type(c, type_ichar) : llvm_get_type(c, type_char), diff, diff < 0);
after_value = LLVMBuildGEP2(c->builder, llvm_get_type(c, type->pointer), value.value, &add, 1, "ptrincdec");
after_value = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, type), value.value, &add, 1, "ptrincdec");
break;
}
case ALL_FLOATS:
@@ -1387,7 +1388,7 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
// Change pointer from Foo[x] to Foo*
parent_base = llvm_emit_bitcast(context, parent_base, pointer_type);
// Move pointer
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_type(context, pointer_type->pointer), parent_base, &start_index, 1, "offset");
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, pointer_type), parent_base, &start_index, 1, "offset");
break;
}
case TYPE_SUBARRAY:
@@ -1398,7 +1399,7 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
case TYPE_POINTER:
{
// Move pointer
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_type(context, parent_type->pointer), parent_base, &start_index, 1, "offset");
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, parent_type), parent_base, &start_index, 1, "offset");
break;
}
default:
@@ -1657,6 +1658,29 @@ LLVMValueRef llvm_emit_int_comparison(GenContext *c, Type *lhs_type, Type *rhs_t
}
static LLVMValueRef llvm_emit_ptr_comparison(GenContext *c, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
{
switch (binary_op)
{
case BINARYOP_EQ:
return LLVMBuildICmp(c->builder, LLVMIntEQ, lhs_value, rhs_value, "eq");
case BINARYOP_NE:
return LLVMBuildICmp(c->builder, LLVMIntNE, lhs_value, rhs_value, "neq");
case BINARYOP_GE:
return LLVMBuildICmp(c->builder, LLVMIntUGE, lhs_value, rhs_value, "ge");
case BINARYOP_GT:
return LLVMBuildICmp(c->builder, LLVMIntUGT, lhs_value, rhs_value, "gt");
case BINARYOP_LE:
return LLVMBuildICmp(c->builder, LLVMIntULE, lhs_value, rhs_value, "le");
case BINARYOP_LT:
return LLVMBuildICmp(c->builder, LLVMIntULT, lhs_value, rhs_value, "lt");
default:
UNREACHABLE
}
}
static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left, LLVMValueRef right)
{
LLVMTypeRef left_type = LLVMTypeOf(left);
@@ -1725,6 +1749,11 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
llvm_value_set_bool(be_value, llvm_emit_int_comparison(c, lhs_type, rhs_type, lhs_value, rhs_value, binary_op));
return;
}
if (type_is_pointer(lhs_type) && binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ)
{
llvm_value_set_bool(be_value, llvm_emit_ptr_comparison(c, lhs_value, rhs_value, binary_op));
return;
}
bool is_float = type_is_float(lhs_type);
LLVMValueRef val;
switch (binary_op)
@@ -1744,11 +1773,14 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
{
if (lhs_type == rhs_type)
{
val = LLVMBuildPtrDiff(c->builder, lhs_value, rhs_value, "ptrdiff");
LLVMTypeRef int_type = llvm_get_type(c, type_iptrdiff);
val = LLVMBuildSub(c->builder, LLVMBuildPtrToInt(c->builder, lhs_value, int_type, ""),
LLVMBuildPtrToInt(c->builder, rhs_value, int_type, ""), "");
val = LLVMBuildExactSDiv(c->builder, val, llvm_const_int(c, type_iptrdiff, type_abi_alignment(lhs_type->pointer)), "");
break;
}
rhs_value = LLVMBuildNeg(c->builder, rhs_value, "");
val = LLVMBuildGEP2(c->builder, llvm_get_type(c, lhs_type->canonical->pointer), lhs_value, &rhs_value, 1, "ptrsub");
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub");
break;
}
if (is_float)
@@ -1762,7 +1794,7 @@ static void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr,
if (lhs_type->type_kind == TYPE_POINTER)
{
assert(type_is_integer(rhs_type));
val = LLVMBuildGEP2(c->builder, llvm_get_type(c, lhs_type->pointer), lhs_value, &rhs_value, 1, "ptradd");
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd");
break;
}
if (is_float)
@@ -2231,13 +2263,14 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
return;
case TYPE_STRLIT:
{
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), expr->const_expr.string.len + 1), "");
LLVMSetLinkage(global_name, LLVMInternalLinkage);
LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), expr->const_expr.string.len + 1), ".str");
LLVMSetLinkage(global_name, LLVMPrivateLinkage);
LLVMSetGlobalConstant(global_name, 1);
LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context,
expr->const_expr.string.chars,
expr->const_expr.string.len,
0));
llvm_set_alignment(global_name, 1);
global_name = LLVMConstBitCast(global_name, LLVMPointerType(llvm_get_type(c, type_char), 0));
llvm_value_set(be_value, global_name, type);
return;
@@ -2716,7 +2749,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr)
else
{
// 9b. Otherwise we also need to allocate memory for the arguments:
Type *pointee_type = vararg_param->type->pointer;
Type *pointee_type = vararg_param->type->array.base;
LLVMTypeRef llvm_pointee = llvm_get_type(c, pointee_type);
Type *array = type_get_array(pointee_type, arguments - non_variadic_params);
LLVMTypeRef llvm_array_type = llvm_get_type(c, array);

View File

@@ -256,8 +256,9 @@ void llvm_emit_return_abi(GenContext *c, BEValue *return_value, BEValue *failabl
// In this case we use the failable as the actual return.
if (signature->failable)
{
if (return_value)
if (return_value && return_value->value)
{
llvm_store_bevalue_aligned(c, c->return_out, return_value, 0);
}
return_out = c->failable_out;

View File

@@ -256,6 +256,7 @@ static inline LLVMBasicBlockRef llvm_get_current_block_if_in_use(GenContext *con
LLVMMetadataRef llvm_get_debug_type(GenContext *c, Type *type);
static inline LLVMTypeRef llvm_get_ptr_type(GenContext *c, Type *type);
LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type);
LLVMTypeRef llvm_get_pointee_type(GenContext *c, Type *any_type);
static inline LLVMValueRef llvm_get_zero(GenContext *c, Type *type);
void llvm_debug_scope_push(GenContext *context, LLVMMetadataRef debug_scope);

View File

@@ -313,6 +313,13 @@ LLVMTypeRef llvm_func_type(GenContext *context, Type *type)
}
LLVMTypeRef llvm_get_pointee_type(GenContext *c, Type *any_type)
{
any_type = any_type->canonical;
assert(any_type->type_kind == TYPE_POINTER);
if (any_type == type_voidptr) return llvm_get_type(c, type_char);
return llvm_get_type(c, any_type->pointer);
}
LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
{

View File

@@ -3351,6 +3351,20 @@ static bool sema_check_int_type_fit(Expr *expr, Type *target_type)
return true;
}
static void unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref)
{
if (*left_type_ref == *right_type_ref) return;
if (*left_type_ref == type_voidptr)
{
cast(left, *right_type_ref);
*left_type_ref = *right_type_ref;
}
if (*right_type_ref == type_voidptr)
{
cast(right, *left_type_ref);
*right_type_ref = *left_type_ref;
}
}
/**
* Analyse a - b
* @return true if analysis succeeded
@@ -3370,6 +3384,7 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
if (right_type->type_kind == TYPE_POINTER)
{
// 3a. Require that both types are the same.
unify_voidptr(left, right, &left_type, &right_type);
if (left_type != right_type)
{
SEMA_ERROR(expr, "'%s' - '%s' is not allowed. Subtracting pointers of different types from each other is not possible.", type_to_error_string(left_type), type_to_error_string(right_type));
@@ -3466,6 +3481,8 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
left = temp;
right_type = left_type;
left_type = left->type->canonical;
expr->binary_expr.left = left;
expr->binary_expr.right = right;
}
// 3. The "left" will now always be the pointer.
@@ -4006,7 +4023,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
break;
case TYPE_POINTER:
// Only comparisons between the same type is allowed. Subtypes not allowed.
if (left_type != right_type)
if (left_type != right_type && left_type != type_voidptr && right_type != type_voidptr)
{
SEMA_ERROR(expr, "Cannot compare pointers of different types.");
return false;

View File

@@ -15,12 +15,13 @@ int main(int argc, const char *argv[])
DEBUG_LOG("Version: %d", version);
// Init the compiler
compiler_init();
// Parse arguments.
BuildOptions build_options = parse_arguments(argc, argv);
// Init the compiler
compiler_init(build_options.std_lib_dir);
BuildTarget build_target = { .name = NULL };
switch (build_options.command)

View File

@@ -91,12 +91,14 @@ char *read_file(const char *path, size_t *return_size)
const char* find_lib_dir(void)
{
const char *path = find_executable_path();
DEBUG_LOG("Detected executable path at %s", path);
struct stat info;
char *lib_path = NULL;
asprintf(&lib_path, "%s../lib/std/", path);
DEBUG_LOG("Checking %s", lib_path);
int err = stat(lib_path, &info);

View File

@@ -14,14 +14,14 @@ func double test(uint x)
// #expect: array_literal.ll
@0 = constant [30 x double] [double 0.000000e+00, double 1.270600e+01, double 4.303000e+00, double 3.182000e+00, double 2.776000e+00, double 2.571000e+00, double 2.447000e+00, double 2.365000e+00, double 2.306000e+00, double 2.262000e+00, double 2.228000e+00, double 2.201000e+00, double 2.179000e+00, double 2.160000e+00, double 2.145000e+00, double 2.131000e+00, double 2.120000e+00, double 2.110000e+00, double 2.101000e+00, double 2.093000e+00, double 2.086000e+00, double 2.080000e+00, double 2.074000e+00, double 2.069000e+00, double 2.064000e+00, double 2.060000e+00, double 2.056000e+00, double 2.052000e+00, double 2.048000e+00, double 2.045000e+00], align 16
@.__const = private constant [30 x double] [double 0.000000e+00, double 1.270600e+01, double 4.303000e+00, double 3.182000e+00, double 2.776000e+00, double 2.571000e+00, double 2.447000e+00, double 2.365000e+00, double 2.306000e+00, double 2.262000e+00, double 2.228000e+00, double 2.201000e+00, double 2.179000e+00, double 2.160000e+00, double 2.145000e+00, double 2.131000e+00, double 2.120000e+00, double 2.110000e+00, double 2.101000e+00, double 2.093000e+00, double 2.086000e+00, double 2.080000e+00, double 2.074000e+00, double 2.069000e+00, double 2.064000e+00, double 2.060000e+00, double 2.056000e+00, double 2.052000e+00, double 2.048000e+00, double 2.045000e+00], align 16
entry:
%x = alloca i32, align 4
%student_t = alloca [30 x double], align 16
store i32 %0, i32* %x, align 4
%1 = bitcast [30 x double]* %student_t to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %1, i8* align 16 bitcast ([30 x double]* @0 to i8*), i32 240, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 16 %1, i8* align 16 bitcast ([30 x double]* @.__const to i8*), i32 240, i1 false)
%2 = load i32, i32* %x, align 4
%uiuiext = zext i32 %2 to i64
%arridx = getelementptr inbounds [30 x double], [30 x double]* %student_t, i64 0, i64 %uiuiext

View File

@@ -15,7 +15,7 @@ Connection[3] link
// #expect: complex_array_const.ll
@0 = internal constant [6 x i8] c"link1\00"
@1 = internal constant [6 x i8] c"link2\00"
@2 = internal constant [6 x i8] c"link3\00"
@link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i32 0, i32 0), i64 30 }], align 16
@.str = private constant [6 x i8] c"link1\00"
@.str.1 = private constant [6 x i8] c"link2\00"
@.str.2 = private constant [6 x i8] c"link3\00"
@link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16

View File

@@ -94,5 +94,5 @@ entry:
%34 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
%35 = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %34, i32 0, i32 1
%36 = load i32, i32* %35, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @0, i32 0, i32 0), i32 %16, double %19, double %22, double %25, i32 %27, double %30, i32 %33, i32 %36)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @.str, i32 0, i32 0), i32 %16, double %19, double %22, double %25, i32 %27, double %30, i32 %33, i32 %36)
ret void

View File

@@ -7,4 +7,4 @@ func char* foo()
// #expect: strings.ll
@0 = internal constant [32 x i8] c"*** Word \22%s\22 on line %d is not\00"
@.str = private constant [32 x i8] c"*** Word \22%s\22 on line %d is not\00"

View File

@@ -20,19 +20,19 @@ func void test()
%x1 = alloca i8, align 1
%b = alloca i8, align 1
%z1 = alloca float, align 4
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0), i32 1)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @1, i32 0, i32 0), i32 123)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @2, i32 0, i32 0), double 1.230000e+01)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 1)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 123)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), double 1.230000e+01)
store i8 -123, i8* %x1, align 1
store i8 0, i8* %b, align 1
store float 0x40289999A0000000, float* %z1, align 4
%0 = load i8, i8* %b, align 1
%1 = trunc i8 %0 to i1
%boolsi = zext i1 %1 to i32
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @3, i32 0, i32 0), i32 %boolsi)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %boolsi)
%2 = load i8, i8* %x1, align 1
%sisiext = sext i8 %2 to i32
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @4, i32 0, i32 0), i32 %sisiext)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.4, i32 0, i32 0), i32 %sisiext)
%3 = load float, float* %z1, align 4
%fpfpext = fpext float %3 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @5, i32 0, i32 0), double %fpfpext)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.5, i32 0, i32 0), double %fpfpext)

View File

@@ -50,7 +50,7 @@ entry:
%idx34 = alloca i64, align 8
%a35 = alloca double, align 8
%0 = bitcast [3 x float]* %foo to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x float]* @0 to i8*), i32 12, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x float]* @.__const to i8*), i32 12, i1 false)
store i64 0, i64* %idx, align 8
br label %foreach.cond
@@ -65,7 +65,7 @@ foreach.body:
store float %3, float* %a, align 4
%4 = load float, float* %a, align 4
%fpfpext = fpext float %4 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @1, i32 0, i32 0), double %fpfpext)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), double %fpfpext)
br label %foreach.inc
foreach.inc:
@@ -93,7 +93,7 @@ foreach.body5:
%11 = load float*, float** %a2, align 8
%12 = load float, float* %11, align 8
%fpfpext6 = fpext float %12 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @2, i32 0, i32 0), double %fpfpext6)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), double %fpfpext6)
br label %foreach.inc7
foreach.inc7:
@@ -119,7 +119,7 @@ foreach.body13:
%ptrptr14 = bitcast i8* %17 to float*
%18 = load float, float* %ptrptr14, align 8
%fpfpext15 = fpext float %18 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @3, i32 0, i32 0), double %fpfpext15)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i32 0, i32 0), double %fpfpext15)
br label %foreach.inc16
foreach.inc16:
@@ -144,7 +144,7 @@ foreach.body21:
%24 = load i64, i64* %i, align 8
%25 = load float, float* %a18, align 4
%fpfpext22 = fpext float %25 to double
call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @4, i32 0, i32 0), i64 %24, double %fpfpext22)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.3, i32 0, i32 0), i64 %24, double %fpfpext22)
br label %foreach.inc23
foreach.inc23:
@@ -173,7 +173,7 @@ foreach.body30:
%32 = load i8, i8* %i25, align 1
%uisiext = zext i8 %32 to i32
%33 = load double, double* %a27, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @5, i32 0, i32 0), i32 %uisiext, double %33)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.4, i32 0, i32 0), i32 %uisiext, double %33)
br label %foreach.inc32
foreach.inc32:
@@ -197,7 +197,7 @@ foreach.body38:
%fpfpext39 = fpext float %38 to double
store double %fpfpext39, double* %a35, align 8
%39 = load double, double* %a35, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @6, i32 0, i32 0), double %39)
call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.5, i32 0, i32 0), double %39)
br label %foreach.inc40
foreach.inc40:

View File

@@ -31,8 +31,8 @@ func int main()
// #expect: while_switch.ll
@0 = internal constant [2 x i8] c"3\00"
@1 = internal constant [2 x i8] c"4\00"
@.str = private constant [2 x i8] c"3\00"
@.str.1 = private constant [2 x i8] c"4\00"
entry:
%switch = alloca i32, align 4
@@ -57,10 +57,10 @@ switch.entry:
i32 6, label %switch.default
]
switch.case:
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @0, i32 0, i32 0))
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0))
br label %switch.case1
switch.case1:
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @1, i32 0, i32 0))
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i32 0, i32 0))
br label %switch.default
switch.default:
br label %switch.exit

View File

@@ -20,5 +20,5 @@ func void test1()
entry:
%p = alloca %test.Point, align 4
%0 = bitcast %test.Point* %p to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%test.Point* @0 to i8*), i32 8, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%test.Point* @.__const to i8*), i32 8, i1 false)

View File

@@ -9,7 +9,7 @@ func void test()
%x = alloca [3 x i32], align 4
%y = alloca %"int[]", align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @0 to i8*), i32 12, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 1
%2 = insertvalue %"int[]" undef, i32* %offset, 0

View File

@@ -10,7 +10,7 @@ func void test()
%x = alloca [3 x i32], align 4
%y = alloca %"int[]", align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @0 to i8*), i32 12, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 1
%2 = insertvalue %"int[]" undef, i32* %offset, 0

View File

@@ -9,7 +9,7 @@ func void test()
%x = alloca [3 x i32], align 4
%y = alloca %"int[]", align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @0 to i8*), i32 12, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 1
%2 = insertvalue %"int[]" undef, i32* %offset, 0

View File

@@ -9,7 +9,7 @@ func void test()
%x = alloca [3 x i32], align 4
%y = alloca %"int[]", align 8
%0 = bitcast [3 x i32]* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @0 to i8*), i32 12, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([3 x i32]* @.__const to i8*), i32 12, i1 false)
%1 = bitcast [3 x i32]* %x to i32*
%offset = getelementptr inbounds i32, i32* %1, i64 0
%2 = insertvalue %"int[]" undef, i32* %offset, 0