diff --git a/resources/lib/std/mem.c3 b/resources/lib/std/mem.c3 index 221846caf..fc5a02e5c 100644 --- a/resources/lib/std/mem.c3 +++ b/resources/lib/std/mem.c3 @@ -25,6 +25,11 @@ struct Allocator void *data; } +func void copy(char* dst, char* src, usize size) +{ + for (usize i = 0; i < size; i++) dst[i] = src[i]; +} + func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline { switch (kind) @@ -47,6 +52,37 @@ func void! system_malloc_function(void *unused, void** pointer, usize bytes, usi $unreachable; } + +struct SlotAllocator +{ + void* pages; + usize page_size; + usize page_count; + usize bitmask; + usize current_page; +} + +func void*! SlotAllocator.alloc(SlotAllocator *allocator, usize size) +{ + void* active_page = (char*)(allocator.pages) + allocator.current_page * allocator.page_size; + void** page_pointer = (void**)(active_page); + if (*page_pointer) + { + mem::free(*page_pointer); + *page_pointer = null; + } + if (size > allocator.page_size - $sizeof(page_pointer)) + { + void* mem = mem::_malloc(size); + if (!mem) return AllocationFailure.OUT_OF_MEMORY!; + *page_pointer = mem; + allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask); + return mem; + } + allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask); + return &page_pointer[1]; +} + struct RingAllocator { char *data; @@ -131,4 +167,24 @@ func void* realloc(void *ptr, usize size) @inline func void free(void* ptr) @inline { _free(ptr); +} + + +const TEMP_BLOCK_SIZE = 1024; +const TEMP_PAGES = 64; + +private char[TEMP_BLOCK_SIZE * TEMP_PAGES] allocator_static_storage; +private void*[TEMP_PAGES] allocator_static_page_storage; + +SlotAllocator default_allocator = { + .pages = &allocator_static_storage, + .page_size = TEMP_BLOCK_SIZE, + .page_count = TEMP_PAGES, + .bitmask = TEMP_PAGES - 1, + .current_page = 0, +}; + +func void*! talloc(usize size) +{ + return default_allocator.alloc(size); } \ No newline at end of file diff --git a/resources/testfragments/tmem.c3 b/resources/testfragments/tmem.c3 new file mode 100644 index 000000000..d5001acc3 --- /dev/null +++ b/resources/testfragments/tmem.c3 @@ -0,0 +1,86 @@ +module tmem; +import std::mem; +import std::io; + +struct String +{ + Allocator allocator; + usize len; + usize capacity; + char* ptr; +} + +func void String.init(String *s, char[] c) +{ + s.capacity = c.len + 16; + s.ptr = mem::_malloc(s.capacity); + s.len = c.len; + mem::copy(s.ptr, (char*)(c), c.len); +} + +func char* String.zstr(String *s) +{ + char* c = mem::_malloc(s.len + 1); + mem::copy(c, s.ptr, s.len); + c[s.len] = 0; + return c; +} + +func void String.appendc(String *s, char c) +{ + if (s.capacity == s.len) + { + s.capacity *= 2; + char* new_ptr = mem::_malloc(s.capacity); + mem::copy(new_ptr, s.ptr, s.len); + s.ptr = new_ptr; + } + s.ptr[s.len++] = c; +} + +func void String.append(String *s, char[] other_string) +{ + if (s.capacity < s.len + other_string.len) + { + do + { + s.capacity *= 2; + } + while (s.capacity < s.len + other_string.len); + char* new_ptr = mem::_malloc(s.capacity); + mem::copy(new_ptr, s.ptr, s.len); + s.ptr = new_ptr; + } + mem::copy(s.ptr + s.len, (char*)(other_string), other_string.len); + s.len += other_string.len; +} + +func void String.concat(String *s, String* other_string) +{ + if (s.capacity < s.len + other_string.len) + { + do + { + s.capacity *= 2; + } + while (s.capacity < s.len + other_string.len); + char* new_ptr = mem::_malloc(s.capacity); + mem::copy(new_ptr, s.ptr, s.len); + s.ptr = new_ptr; + } + mem::copy(s.ptr + s.len, other_string.ptr, other_string.len); + s.len += other_string.len; +} + +func void main() +{ + String s; + s.init("Hello"); + s.appendc(' '); + s.appendc('W'); + s.append("orld!"); + String w; + w.init("Yo man!"); + s.concat(&w); + io::printf("Message was: %s\n", s.zstr()); +} \ No newline at end of file diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 1b48a6f9b..3fe57ab31 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -247,7 +247,6 @@ static void setup_int_define(const char *id, uint64_t i) TokenType token_type = TOKEN_CONST_IDENT; id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); - expr->constant = true; expr_const_set_int(&expr->const_expr, i, TYPE_IXX); expr->original_type = expr->type = type_compint; expr->span = INVALID_RANGE; @@ -266,7 +265,6 @@ static void setup_bool_define(const char *id, bool value) Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); expr_const_set_bool(&expr->const_expr, value); expr->original_type = expr->type = type_bool; - expr->constant = true; expr->span = INVALID_RANGE; expr->resolve_status = RESOLVE_NOT_DONE; void *previous = stable_set(&global_context.compiler_defines, id, expr); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index c96b5160e..ee6442c19 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -653,8 +653,6 @@ typedef struct Expr *left; Expr *right; BinaryOp operator; - bool left_maybe : 1; - bool right_maybe : 1; } ExprBinary; typedef struct @@ -923,7 +921,6 @@ struct Expr_ ResolveStatus resolve_status : 3; bool failable : 1; bool pure : 1; - bool constant : 1; SourceSpan span; Type *type; Type *original_type; @@ -1796,10 +1793,18 @@ void expr_const_set_null(ExprConst *expr); bool expr_const_int_overflowed(const ExprConst *expr); bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op); bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind); +ByteSize expr_const_list_size(const ConstInitializer *list); + void expr_insert_addr(Expr *original); void expr_insert_deref(Expr *expr); Expr *expr_variable(Decl *decl); -bool expr_is_constant_eval(Expr *expr); +typedef enum +{ + CONSTANT_EVAL_ANY, + CONSTANT_EVAL_FOLDABLE, + CONSTANT_EVAL_NO_LINKTIME, +} ConstantEvalKind; +bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); const char *expr_const_to_error_string(const ExprConst *expr); static inline bool expr_is_init_list(Expr *expr) { diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 41f2b99d4..239925e39 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -74,7 +74,6 @@ Expr *copy_expr(Expr *source_expr) case EXPR_FLATPATH: case EXPR_UNDEF: case EXPR_NOP: - case EXPR_BYTES: return expr; case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index ca612a44d..5e2965952 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -179,7 +179,6 @@ typedef enum EXPR_POISONED, EXPR_ACCESS, EXPR_BINARY, - EXPR_BYTES, EXPR_MACRO_BODY_EXPANSION, EXPR_CALL, EXPR_CAST, diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 4b87ee675..e7c71cf09 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -57,6 +57,7 @@ static void gencontext_destroy(GenContext *context) LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned int align, bool bitcast) { + LLVMValueRef target = bitcast ? LLVMBuildBitCast(c->builder, ref, llvm_get_type(c, type_get_ptr(type_char)), "") : ref; return LLVMBuildMemSet(c->builder, target, LLVMConstInt(llvm_get_type(c, type_char), 0, false), LLVMConstInt(llvm_get_type(c, type_ulong), size, false), align); @@ -78,7 +79,7 @@ LLVMValueRef llvm_emit_const_array_padding(LLVMTypeRef element_type, IndexDiff d return LLVMConstNull(padding_type); } -LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool *modified) +LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init) { switch (const_init->kind) { @@ -93,18 +94,16 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ Type *element_type = array_type->array.base; LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); ConstInitializer **elements = const_init->init_array_full; + assert(array_type->type_kind == TYPE_ARRAY); ArrayIndex size = array_type->array.len; - if (array_type->type_kind == TYPE_SUBARRAY) - { - size = vec_size(elements); - } assert(size > 0); LLVMValueRef *parts = VECNEW(LLVMValueRef, size); for (ArrayIndex i = 0; i < size; i++) { - vec_add(parts, llvm_emit_const_initializer(c, elements[i], &was_modified)); + LLVMValueRef element = llvm_emit_const_initializer(c, elements[i]); + if (element_type_llvm != LLVMTypeOf(element)) was_modified = true; + vec_add(parts, element); } - if (was_modified) *modified = was_modified; if (was_modified) { return LLVMConstStructInContext(c->context, parts, vec_size(parts), true); @@ -118,6 +117,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ Type *array_type = const_init->type; Type *element_type = array_type->array.base; LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); + AlignSize expected_align = llvm_abi_alignment(c, element_type_llvm); ConstInitializer **elements = const_init->init_array.elements; unsigned element_count = vec_size(elements); assert(element_count > 0 && "Array should always have gotten at least one element."); @@ -131,18 +131,19 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ assert(element->kind == CONST_INIT_ARRAY_VALUE); ArrayIndex element_index = element->init_array_value.index; IndexDiff diff = element_index - current_index; - unsigned curr_alignment = type_abi_alignment(element->type); - if (alignment && curr_alignment != alignment) + if (alignment && expected_align != alignment) { pack = true; } - alignment = curr_alignment; + alignment = expected_align; // Add zeroes if (diff > 0) { vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, diff, &was_modified)); } - vec_add(parts, llvm_emit_const_initializer(c, element->init_array_value.element, &was_modified)); + LLVMValueRef value = llvm_emit_const_initializer(c, element->init_array_value.element); + if (LLVMTypeOf(value) == element_type_llvm) was_modified = true; + vec_add(parts, value); current_index = element_index + 1; } @@ -151,7 +152,6 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ { vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, end_diff, &was_modified)); } - if (was_modified) *modified = was_modified; if (was_modified) { return LLVMConstStructInContext(c->context, parts, vec_size(parts), pack); @@ -161,13 +161,10 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ case CONST_INIT_UNION: { Decl *decl = const_init->type->decl; - // Get the type of the member that is used for this particular - // constant value, for example if this is a union { double, int } - // then the type may be double or int. - Type *member_type = decl->strukt.members[const_init->init_union.index]->type->canonical; // Emit our value. - LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element, modified); + LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element); + LLVMTypeRef result_type = LLVMTypeOf(result); // Get the union value LLVMTypeRef union_type_llvm = llvm_get_type(c, decl->type); @@ -177,7 +174,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ // We need to calculate some possible padding. ByteSize union_size = type_size(const_init->type); - ByteSize member_size = type_size(member_type); + ByteSize member_size = llvm_abi_size(c, result_type); ByteSize padding = union_size - member_size; // Create the resulting values: @@ -192,15 +189,9 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ } // Is this another type than usual for the union? - if (first_type != llvm_get_type(c, member_type)) + if (first_type != result_type) { // Yes, so the type needs to be modified. - *modified = true; - } - - // If it is modified we simply create a packed struct for representation. - if (*modified) - { return LLVMConstStructInContext(c->context, values, value_count, false); } @@ -212,21 +203,36 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ Decl **members = decl->strukt.members; MemberIndex count = vec_size(members); LLVMValueRef *entries = NULL; + bool was_modified = false; for (MemberIndex i = 0; i < count; i++) { if (members[i]->padding) { vec_add(entries, llvm_emit_const_padding(c, members[i]->padding)); } - vec_add(entries, llvm_emit_const_initializer(c, const_init->init_struct[i], modified)); + LLVMTypeRef expected_type = llvm_get_type(c, const_init->init_struct[i]->type); + LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i]); + LLVMTypeRef element_type = LLVMTypeOf(element); + if (expected_type != element_type) + { + was_modified = true; + } + AlignSize new_align = llvm_abi_alignment(c, element_type); + AlignSize expected_align = llvm_abi_alignment(c, expected_type); + if (i != 0 && new_align < expected_align) + { + vec_add(entries, llvm_emit_const_padding(c, expected_align - new_align)); + } + vec_add(entries, element); } if (decl->strukt.padding) { vec_add(entries, llvm_emit_const_padding(c, decl->strukt.padding)); } - if (*modified) + if (was_modified) { - return LLVMConstStructInContext(c->context, entries, vec_size(entries), decl->is_packed); + LLVMValueRef value = LLVMConstStructInContext(c->context, entries, vec_size(entries), decl->is_packed); + return value; } return LLVMConstNamedStruct(llvm_get_type(c, const_init->type), entries, vec_size(entries)); } @@ -234,47 +240,12 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ { BEValue value; llvm_emit_expr(c, &value, const_init->init_value); - LLVMValueRef llvm_value = llvm_value_rvalue_store(c, &value); - LLVMTypeRef expected_type = llvm_get_type(c, const_init->type); - if (expected_type != LLVMTypeOf(llvm_value)) *modified = true; - return llvm_value; + return llvm_value_rvalue_store(c, &value); } } UNREACHABLE } -static LLVMValueRef llvm_emit_const_initializer_simple(GenContext *c, Expr *expr, bool *modified) -{ - Expr **elements = expr->initializer_list; - unsigned element_count = vec_size(elements); - LLVMValueRef* values = malloc_arena(element_count * sizeof(LLVMValueRef)); - Type *expr_type = expr->type->canonical; - LLVMTypeRef array_type = expr_type->type_kind == TYPE_ARRAY ? llvm_get_type(c, expr_type->array.base) : NULL; - assert(array_type || type_is_structlike(expr_type)); - for (unsigned i = 0; i < element_count; i++) - { - BEValue value; - llvm_emit_expr(c, &value, elements[i]); - LLVMValueRef llvm_value = llvm_value_rvalue_store(c, &value); - LLVMTypeRef expected_type = array_type ? array_type : llvm_get_type(c, expr_type->decl->strukt.members[0]->type); - if (expected_type != LLVMTypeOf(llvm_value)) *modified = true; - values[i] = llvm_value; - } - if (array_type) - { - if (*modified) - { - return LLVMConstStructInContext(c->context, values, element_count, true); - } - return LLVMConstArray(array_type, values, element_count); - } - if (*modified) - { - return LLVMConstStructInContext(c->context, values, element_count, true); - } - return LLVMConstNamedStruct(llvm_get_type(c, expr_type), values, element_count); -} - static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl) { @@ -334,7 +305,6 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) // Skip real constants. if (!decl->type) return; - bool modified = false; LLVMValueRef init_value; ByteSize alignment = type_alloca_alignment(decl->type); @@ -345,46 +315,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) if (init_expr->expr_kind == EXPR_CONST && init_expr->const_expr.const_kind == CONST_LIST) { ConstInitializer *list = init_expr->const_expr.list; - init_value = llvm_emit_const_initializer(c, list, &modified); - Type *type = type_lowering(init_expr->type); - if (type->type_kind == TYPE_SUBARRAY) - { - LLVMTypeRef const_type = LLVMTypeOf(init_value); - LLVMValueRef global_copy = LLVMAddGlobal(c->module, const_type, ".__const"); - LLVMSetLinkage(global_copy, LLVMPrivateLinkage); - - // Set a nice alignment - Type *ptr = type_get_ptr(type); - llvm_set_alignment(global_copy, type_alloca_alignment(ptr)); - - // Set the value and make it constant - LLVMSetInitializer(global_copy, init_value); - LLVMSetGlobalConstant(global_copy, true); - - LLVMValueRef value = LLVMConstBitCast(global_copy, llvm_get_type(c, ptr)); - ByteSize size; - switch (list->kind) - { - case CONST_INIT_ZERO: - size = 0; - break; - case CONST_INIT_ARRAY: - size = VECLAST(list->init_array.elements)->init_array_value.index + 1; - break; - case CONST_INIT_ARRAY_FULL: - size = vec_size(list->init_array_full); - break; - default: - UNREACHABLE - } - LLVMTypeRef subarray_type = llvm_get_type(c, type); - LLVMValueRef result = LLVMGetUndef(subarray_type); - LLVMValueRef len = llvm_const_int(c, type_usize, size); - unsigned id = 0; - result = LLVMConstInsertValue(result, value, &id, 1); - id = 1; - init_value = LLVMConstInsertValue(result, len, &id, 1); - } + init_value = llvm_emit_const_initializer(c, list); } else { @@ -459,7 +390,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) break; } - if (modified) + if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, decl->type)) { decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type)); } @@ -513,6 +444,7 @@ void gencontext_print_llvm_ir(GenContext *context) LLVMValueRef llvm_emit_alloca(GenContext *c, LLVMTypeRef type, unsigned alignment, const char *name) { + assert(c->builder); assert(alignment > 0); LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder); LLVMPositionBuilderBefore(c->builder, c->alloca_point); @@ -925,9 +857,23 @@ void llvm_value_addr(GenContext *c, BEValue *value) { llvm_value_fold_failable(c, value); if (value->kind == BE_ADDRESS) return; - LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "tempaddr"); - llvm_store_self_aligned(c, temp, value->value, value->type); - llvm_value_set_address(value, temp, value->type); + if (!c->builder) + { + LLVMValueRef val = llvm_value_rvalue_store(c, value); + LLVMValueRef ref = LLVMAddGlobal(c->module, LLVMTypeOf(val), ".taddr"); + llvm_set_alignment(ref, llvm_abi_alignment(c, LLVMTypeOf(val))); + LLVMSetLinkage(ref, LLVMPrivateLinkage); + LLVMSetVisibility(ref, LLVMHiddenVisibility); + LLVMSetInitializer(ref, val); + llvm_emit_bitcast(c, ref, type_get_ptr(value->type)); + llvm_value_set_address(value, ref, value->type); + } + else + { + LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "taddr"); + llvm_store_self_aligned(c, temp, value->value, value->type); + llvm_value_set_address(value, temp, value->type); + } } void llvm_value_rvalue(GenContext *c, BEValue *value) @@ -1261,6 +1207,7 @@ void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, un LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name) { + assert(c->builder); LLVMValueRef value = LLVMBuildLoad2(c->builder, type, pointer, name); assert(LLVMGetTypeContext(type) == c->context); llvm_set_alignment(value, alignment ? alignment : llvm_abi_alignment(c, type)); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index ef23236e5..ad69c486d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -19,6 +19,41 @@ LLVMValueRef llvm_emit_is_no_error_value(GenContext *c, BEValue *value) return LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, type_anyerr), "not_err"); } + +LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...) +{ + LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type)); + va_list args; + va_start(args, type); + LLVMValueRef val; + bool is_constant = true; + while (is_constant && (val = va_arg(args, LLVMValueRef)) != NULL) + { + if (!LLVMIsConstant(val)) is_constant = false; + } + va_end(args); + va_start(args, type); + unsigned index = 0; + if (is_constant) + { + while ((val = va_arg(args, LLVMValueRef)) != NULL) + { + result = LLVMConstInsertValue(result, val, &index, 1); + index++; + } + } + else + { + assert(c->builder); + while ((val = va_arg(args, LLVMValueRef)) != NULL) + { + result = LLVMBuildInsertValue(c->builder, result, val, index++, ""); + } + } + va_end(args); + return result; +} + LLVMTypeRef llvm_const_padding_type(GenContext *c, ByteSize size) { assert(size > 0); @@ -480,22 +515,10 @@ static void llvm_emit_arr_to_subarray_cast(GenContext *c, BEValue *value, Type * ByteSize size = value->type->pointer->array.len; Type *array_type = value->type->pointer->array.base; LLVMTypeRef subarray_type = llvm_get_type(c, to_type); - LLVMValueRef result = LLVMGetUndef(subarray_type); LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_get_ptr(array_type)); LLVMValueRef len = llvm_const_int(c, type_usize, size); value->type = to_type; - if (!c->builder) - { - unsigned id = 0; - result = LLVMConstInsertValue(result, pointer, &id, 1); - id = 1; - value->value = LLVMConstInsertValue(result, len, &id, 1); - } - else - { - result = LLVMBuildInsertValue(c->builder, result, pointer, 0, ""); - value->value = LLVMBuildInsertValue(c->builder, result, len, 1, ""); - } + value->value = llvm_emit_aggregate_value(c, to_type, pointer, len, NULL); } @@ -571,7 +594,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ } else { - value->value = LLVMConstBitCast(value->value, llvm_get_type(c, to_type)); + value->value = LLVMConstPtrToInt(value->value, llvm_get_type(c, to_type)); } break; case CAST_APTSA: @@ -665,6 +688,12 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ break; case CAST_XIPTR: llvm_value_rvalue(c, value); + if (LLVMIsConstant(value->value)) + { + value->value = LLVMConstIntToPtr(value->value, llvm_get_type(c, to_type)); + break; + } + assert(c->builder); value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr"); break; case CAST_UISI: @@ -790,10 +819,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, Type *canonical = expr->type->canonical; assert(expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST); - LLVMValueRef value = llvm_emit_const_initializer(c, expr->const_expr.list, &modified); + LLVMValueRef value = llvm_emit_const_initializer(c, expr->const_expr.list); + LLVMTypeRef expected_type = llvm_get_type(c, canonical); // Create a global const. - LLVMTypeRef type = modified ? LLVMTypeOf(value) : llvm_get_type(c, canonical); + LLVMTypeRef type = LLVMTypeOf(value); LLVMValueRef global_copy = LLVMAddGlobal(c->module, type, ".__const"); LLVMSetLinkage(global_copy, LLVMPrivateLinkage); @@ -808,6 +838,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, // Ensure we have a reference. llvm_value_addr(c, ref); + if (expected_type != type) + { + global_copy = LLVMConstBitCast(global_copy, LLVMPointerType(expected_type, 0)); + } + // Perform the memcpy. llvm_emit_memcpy(c, ref->value, ref->alignment, global_copy, alignment, type_size(expr->type)); } @@ -944,10 +979,6 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r VECEACH(elements, i) { Expr *element = elements[i]; - if (element->expr_kind == EXPR_COMPOUND_LITERAL) - { - element = element->expr_compound_literal.initializer; - } unsigned offset = 0; BEValue pointer; if (is_struct) @@ -1234,22 +1265,18 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e llvm_emit_inc_dec_change(c, use_mod, &addr, NULL, value, expr, diff); } + static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) { Type *type = type_reduced_from_expr(expr->unary_expr.expr); + Expr *inner = expr->unary_expr.expr; LLVMValueRef llvm_value; switch (expr->unary_expr.operator) { case UNARYOP_ERROR: FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator); - case UNARYOP_TADDR: - llvm_value = llvm_emit_alloca_aligned(c, expr->unary_expr.expr->type, "taddr"); - llvm_emit_expr(c, value, expr->unary_expr.expr); - llvm_store_bevalue_dest_aligned(c, llvm_value, value); - llvm_value_set(value, llvm_value, type); - return; case UNARYOP_NOT: - llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_emit_expr(c, value, inner); llvm_value_rvalue(c, value); if (type_is_float(type)) { @@ -1266,12 +1293,12 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr llvm_value_set_bool(value, llvm_value); return; case UNARYOP_BITNEG: - llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_emit_expr(c, value, inner); llvm_value_rvalue(c, value); value->value = LLVMBuildNot(c->builder, value->value, "bnot"); return; case UNARYOP_NEG: - llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_emit_expr(c, value, inner); llvm_value_rvalue(c, value); if (type_is_float(type)) { @@ -1296,8 +1323,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr } value->value = LLVMBuildNeg(c->builder, value->value, "neg"); return; + case UNARYOP_TADDR: case UNARYOP_ADDR: - llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_emit_expr(c, value, inner); // Create an addr llvm_value_addr(c, value); // Transform to value @@ -1305,7 +1333,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr value->type = type_lowering(expr->type); return; case UNARYOP_DEREF: - llvm_emit_expr(c, value, expr->unary_expr.expr); + llvm_emit_expr(c, value, inner); // Load the pointer value. llvm_value_rvalue(c, value); // Convert pointer to address @@ -1313,10 +1341,10 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr value->type = type_lowering(expr->type); return; case UNARYOP_INC: - llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false); + llvm_emit_pre_inc_dec(c, value, inner, 1, false); return; case UNARYOP_DEC: - llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, -1, false); + llvm_emit_pre_inc_dec(c, value, inner, -1, false); return; } UNREACHABLE @@ -1522,7 +1550,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV *parent_type_ref = parent_type; } -static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *expr) +static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr) { Type *parent_type; Type *end_type; @@ -1531,13 +1559,13 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr * Type *start_type; LLVMValueRef start_index; // Use general function to get all the values we need (a lot!) - llvm_emit_slice_values(context, expr, &parent_type, + llvm_emit_slice_values(c, expr, &parent_type, &parent_base, &start_type, &start_index, &end_type, &end_index); // Calculate the size - LLVMValueRef size = LLVMBuildSub(context->builder, LLVMBuildAdd(context->builder, end_index, llvm_const_int(context, start_type, 1), ""), start_index, "size"); + LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end_index, llvm_const_int(c, start_type, 1), ""), start_index, "size"); LLVMValueRef start_pointer; switch (parent_type->type_kind) { @@ -1545,20 +1573,20 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr * { Type *pointer_type = type_get_ptr(parent_type->array.base); // Change pointer from Foo[x] to Foo* - parent_base = llvm_emit_bitcast(context, parent_base, pointer_type); + parent_base = llvm_emit_bitcast(c, parent_base, pointer_type); // Move pointer - start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, pointer_type), parent_base, &start_index, 1, "offset"); + start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, pointer_type), parent_base, &start_index, 1, "offset"); break; } case TYPE_SUBARRAY: { - start_pointer = LLVMBuildInBoundsGEP(context->builder, parent_base, &start_index, 1, "offsetsub"); + start_pointer = LLVMBuildInBoundsGEP(c->builder, parent_base, &start_index, 1, "offsetsub"); break; } case TYPE_POINTER: { // Move pointer - start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, parent_type), parent_base, &start_index, 1, "offset"); + start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, parent_type), parent_base, &start_index, 1, "offset"); break; } default: @@ -1566,9 +1594,7 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr * } // Create a new subarray type - LLVMValueRef result = LLVMGetUndef(llvm_get_type(context, expr->type)); - result = LLVMBuildInsertValue(context->builder, result, start_pointer, 0, ""); - llvm_value_set(be_value, LLVMBuildInsertValue(context->builder, result, size, 1, ""), expr->type); + llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr->type, start_pointer, size, NULL), expr->type); } static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) @@ -2103,6 +2129,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu case BINARYOP_SUB: if (lhs_type->type_kind == TYPE_POINTER) { + bool is_constant = LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value); if (lhs_type == rhs_type) { LLVMTypeRef int_type = llvm_get_type(c, type_iptrdiff); @@ -2111,8 +2138,17 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu 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_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub"); + if (is_constant) + { + rhs_value = LLVMConstNeg(rhs_value); + // TODO use GEP2 + val = LLVMConstGEP(lhs_value, &rhs_value, 1); + } + else + { + rhs_value = LLVMBuildNeg(c->builder, rhs_value, ""); + val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub"); + } break; } if (is_float) @@ -2126,7 +2162,16 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu if (lhs_type->type_kind == TYPE_POINTER) { assert(type_is_integer(rhs_type)); - val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd"); + if (LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value)) + { + // TODO use LLVMConstGEP2 + // val = LLVMConstGEP2(llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1); + val = LLVMConstGEP(lhs_value, &rhs_value, 1); + } + else + { + val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd"); + } break; } if (is_float) @@ -2639,6 +2684,11 @@ static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Real f) static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr) { + if (!c->builder) + { + llvm_value_set(value, llvm_emit_const_initializer(c, expr->const_expr.list), expr->type); + return; + } llvm_value_set_address(value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type); llvm_emit_initialize_reference_const(c, value, expr); } @@ -3577,7 +3627,6 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue } } BEValue value; - if (expr->expr_kind == EXPR_COMPOUND_LITERAL) expr = expr->expr_compound_literal.initializer; if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST) { llvm_emit_const_initialize_reference(c, ref, expr); @@ -3827,7 +3876,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_try_assign_expr(c, value, expr); return; case EXPR_NOP: - case EXPR_BYTES: return; case EXPR_ELSE: gencontext_emit_else_expr(c, value, expr); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 97166eb23..c8a25f017 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -236,7 +236,7 @@ void llvm_emit_debug_local_var(GenContext *c, Decl *var); void llvm_emit_debug_global_var(GenContext *c, Decl *global); void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end); void llvm_emit_extern_decl(GenContext *context, Decl *decl); -LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool *modified); +LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init); void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type); void llvm_emit_global_variable_init(GenContext *c, Decl *decl); @@ -250,6 +250,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name); void llvm_emit_local_var_alloca(GenContext *c, Decl *decl); LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl); +LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...); LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned align, bool bitcast); LLVMValueRef llvm_emit_memclear(GenContext *c, BEValue *ref); void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLVMValueRef source, unsigned src_align, uint64_t len); @@ -324,11 +325,14 @@ static inline LLVMValueRef llvm_emit_store(GenContext *context, Decl *decl, LLVM static inline LLVMValueRef llvm_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type) { assert(type->type_kind == TYPE_POINTER); - if (!context->builder) + LLVMTypeRef result_type = llvm_get_type(context, type); + if (result_type == LLVMTypeOf(value)) return value; + if (LLVMIsConstant(value)) { - return LLVMConstBitCast(value, llvm_get_type(context, type)); + return LLVMConstBitCast(value, result_type); } - return LLVMBuildBitCast(context->builder, value, llvm_get_type(context, type), ""); + assert(context->builder); + return LLVMBuildBitCast(context->builder, value, result_type, ""); } static inline bool llvm_use_debug(GenContext *context) { return context->debug.builder != NULL; } diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index dddfbef80..07e54fb38 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -54,6 +54,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) // then we essentially treat this as a global. if (decl->var.is_static) { + void *builder = c->builder; + c->builder = NULL; decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal"); if (decl->var.failable) { @@ -63,6 +65,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) decl->var.failable_ref = LLVMAddGlobal(c->module, llvm_get_type(c, type_anyerr), scratch_buffer_to_string()); } llvm_emit_global_variable_init(c, decl); + c->builder = builder; return decl->backend_ref; } llvm_emit_local_var_alloca(c, decl); diff --git a/src/compiler/number.c b/src/compiler/number.c index 1bc43a9e9..ce1466d25 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -277,5 +277,20 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind) expr->float_type = kind; } +ByteSize expr_const_list_size(const ConstInitializer *list) +{ + switch (list->kind) + { + case CONST_INIT_ZERO: + return 0; + case CONST_INIT_ARRAY: + return VECLAST(list->init_array.elements)->init_array_value.index + 1; + case CONST_INIT_ARRAY_FULL: + return vec_size(list->init_array_full); + default: + UNREACHABLE + } +} + diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index d694528a7..34d6dcdf4 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -667,7 +667,6 @@ static Expr *parse_subscript_expr(Context *context, Expr *left) { index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); expr_set_type(index, type_uint); - index->constant = true; index->resolve_status = RESOLVE_DONE; expr_const_set_int(&index->const_expr, 0, type_uint->type_kind); } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index d3976caf9..2167b9a09 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -679,25 +679,28 @@ bool cast_may_implicit(Type *from_type, Type *to_type) bool may_convert_float_const_implicit(Expr *expr, Type *to_type) { Type *to_type_flat = type_flatten(to_type); - Real limit; + Real hi_limit; + Real lo_limit; switch (to_type_flat->type_kind) { case TYPE_F16: - limit = FLOAT16_LIMIT; + lo_limit = hi_limit = FLOAT16_LIMIT; break; case TYPE_F32: - limit = FLOAT32_LIMIT; + lo_limit = hi_limit = FLOAT32_LIMIT; break; case TYPE_F64: - limit = FLOAT64_LIMIT; + lo_limit = hi_limit = FLOAT64_LIMIT; break; case TYPE_F128: // Assume this to be true return true; + case TYPE_BOOL: + return true; default: UNREACHABLE } - if (expr->const_expr.f < -limit || expr->const_expr.f > limit) + if (expr->const_expr.f < -lo_limit || expr->const_expr.f > hi_limit) { #if LONG_DOUBLE SEMA_ERROR(expr, "The value '%Lg' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.f, type_quoted_error_string(to_type)); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 0ad66e444..62aedb616 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1394,28 +1394,9 @@ bool sema_analyse_var_decl(Context *context, Decl *decl) if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false; // 2. Check const-ness - if ((is_global || decl->var.is_static) && !init_expr->constant) + if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY)) { - // 3. Special case is when the init expression is the reference - // to a constant global structure. - if (init_expr->expr_kind == EXPR_CONST_IDENTIFIER) - { - // 4. If so we copy the init expression, which should always be constant. - *init_expr = *init_expr->identifier_expr.decl->var.init_expr; - assert(init_expr->constant); - } - else - { - if (init_expr->expr_kind == EXPR_CAST) - { - SEMA_ERROR(init_expr, "The expression may not be a non constant cast."); - } - else - { - SEMA_ERROR(init_expr, "The expression must be a constant value."); - } - return false; - } + SEMA_ERROR(init_expr, "The expression must be a constant value."); } else { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index faa8ea831..2c2e205d4 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -84,7 +84,6 @@ void expr_copy_properties(Expr *to, Expr *from) { to->failable = from->failable; to->pure = from->pure; - to->constant = from->constant; } void expr_copy_types(Expr *to, Expr *from) @@ -107,9 +106,6 @@ void expr_insert_addr(Expr *original) expr_set_type(original, type_get_ptr(inner->type)); original->unary_expr.operator = UNARYOP_ADDR; original->unary_expr.expr = inner; - original->pure = false; - original->constant = false; - original->failable = inner->failable; } Expr *expr_variable(Decl *decl) @@ -117,12 +113,251 @@ Expr *expr_variable(Decl *decl) Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span); expr->identifier_expr.decl = decl; expr->pure = true; - expr->constant = false; expr->resolve_status = RESOLVE_DONE; expr_set_type(expr, decl->type); return expr; } +static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +{ + if (eval_kind != CONSTANT_EVAL_ANY) return false; + Expr *inner = expr->unary_expr.expr; + switch (inner->expr_kind) + { + case EXPR_CONST: + case EXPR_INITIALIZER_LIST: + case EXPR_DESIGNATED_INITIALIZER_LIST: + return expr_is_constant_eval(inner, eval_kind); + case EXPR_IDENTIFIER: + case EXPR_CONST_IDENTIFIER: + { + Decl *decl = inner->identifier_expr.decl; + if (decl->decl_kind == DECL_FUNC) return true; + if (decl->decl_kind != DECL_VAR) return false; + switch (decl->var.kind) + { + case VARDECL_CONST: + case VARDECL_GLOBAL: + return true; + case VARDECL_LOCAL: + return decl->var.is_static; + case VARDECL_PARAM: + case VARDECL_MEMBER: + case VARDECL_PARAM_CT: + case VARDECL_PARAM_CT_TYPE: + case VARDECL_PARAM_REF: + case VARDECL_PARAM_EXPR: + case VARDECL_LOCAL_CT: + case VARDECL_LOCAL_CT_TYPE: + case VARDECL_UNWRAPPED: + case VARDECL_ERASE: + case VARDECL_REWRAPPED: + return false; + } + } + default: + return false; + } +} + +bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +{ + switch (expr->cast_expr.kind) + { + case CAST_ERROR: + return false; + case CAST_ERBOOL: + case CAST_EUBOOL: + case CAST_EUER: + case CAST_EREU: + case CAST_XIERR: + case CAST_PTRPTR: + case CAST_ARRPTR: + case CAST_STRPTR: + case CAST_PTRBOOL: + case CAST_BOOLINT: + case CAST_BOOLFP: + case CAST_BOOLBOOL: + case CAST_FPBOOL: + case CAST_INTBOOL: + case CAST_FPFP: + case CAST_FPSI: + case CAST_FPUI: + case CAST_SISI: + case CAST_SIUI: + case CAST_SIFP: + case CAST_XIPTR: + case CAST_UISI: + case CAST_UIUI: + case CAST_UIFP: + case CAST_APTSA: + case CAST_SAPTR: + case CAST_SABOOL: + case CAST_STST: + case CAST_VRPTR: + case CAST_PTRVR: + case CAST_VRBOOL: + case CAST_ENUMLOW: + if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false; + return expr_is_constant_eval(expr->cast_expr.expr, eval_kind); + case CAST_EUINT: + case CAST_ERINT: + case CAST_PTRXI: + if (eval_kind != CONSTANT_EVAL_ANY) return false; + return expr_is_constant_eval(expr->cast_expr.expr, eval_kind); + } + UNREACHABLE +} +static bool expr_binary_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +{ + if (expr->binary_expr.operator >= BINARYOP_ASSIGN) return false; + if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false; + Expr *left = expr->binary_expr.left; + Expr *right = expr->binary_expr.right; + int pointers = type_flatten(left->type)->type_kind == TYPE_POINTER ? 1 : 0; + pointers += type_flatten(right->type)->type_kind == TYPE_POINTER ? 1 : 0; + switch (expr->binary_expr.operator) + { + case BINARYOP_ERROR: + UNREACHABLE + case BINARYOP_SUB: + // Pointer diffs are not compile time resolved. + if (pointers == 2) return false; + if (pointers == 0) eval_kind = CONSTANT_EVAL_NO_LINKTIME; + break; + case BINARYOP_ADD: + assert(pointers != 2); + if (pointers == 0) eval_kind = CONSTANT_EVAL_NO_LINKTIME; + break; + default: + // For the default operations we don't accept linktime resolution + eval_kind = CONSTANT_EVAL_NO_LINKTIME; + break; + } + if (!expr_is_constant_eval(left, eval_kind)) return false; + if (!expr_is_constant_eval(right, eval_kind)) return false; + return true; +} + +static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind) +{ + VECEACH(exprs, i) + { + if (!expr_is_constant_eval(exprs[i], eval_kind)) return false; + } + return true; +} + +bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +{ + RETRY: + switch (expr->expr_kind) + { + case EXPR_ACCESS: + expr = expr->access_expr.parent; + goto RETRY; + case EXPR_BINARY: + return expr_binary_is_constant_eval(expr, eval_kind); + case EXPR_CAST: + return expr_cast_is_constant_eval(expr, eval_kind); + case EXPR_CONST: + return true; + case EXPR_CONST_IDENTIFIER: + expr = expr->identifier_expr.decl->var.init_expr; + goto RETRY; + case EXPR_COND: + return expr_list_is_constant_eval(expr->cond_expr, eval_kind); + case EXPR_DESIGNATOR: + expr = expr->designator_expr.value; + goto RETRY; + case EXPR_ELSE: + if (expr->else_expr.is_jump) return false; + assert(!expr_is_constant_eval(expr->else_expr.expr, eval_kind)); + return false; + case EXPR_EXPR_BLOCK: + case EXPR_DECL: + case EXPR_CALL: + case EXPR_CATCH_UNWRAP: + case EXPR_MACRO_BODY_EXPANSION: + case EXPR_TRY_UNWRAP: + case EXPR_TRY_UNWRAP_CHAIN: + case EXPR_TRY_ASSIGN: + case EXPR_POST_UNARY: + case EXPR_SCOPED_EXPR: + case EXPR_SLICE_ASSIGN: + case EXPR_MACRO_BLOCK: + case EXPR_IDENTIFIER: + case EXPR_GUARD: + case EXPR_UNDEF: + return false; + case EXPR_EXPRESSION_LIST: + return expr_list_is_constant_eval(expr->expression_list, eval_kind); + case EXPR_FAILABLE: + expr = expr->failable_expr; + goto RETRY; + case EXPR_GROUP: + expr = expr->group_expr; + goto RETRY; + case EXPR_INITIALIZER_LIST: + return expr_list_is_constant_eval(expr->initializer_list, eval_kind); + case EXPR_DESIGNATED_INITIALIZER_LIST: + return expr_list_is_constant_eval(expr->designated_init_list, eval_kind); + case EXPR_LEN: + expr = expr->len_expr.inner; + goto RETRY; + case EXPR_SLICE: + if (expr->slice_expr.start && !expr_is_constant_eval(expr->slice_expr.start, CONSTANT_EVAL_FOLDABLE)) return false; + if (expr->slice_expr.end && !expr_is_constant_eval(expr->slice_expr.end, CONSTANT_EVAL_FOLDABLE)) return false; + return expr_is_constant_eval(expr->slice_expr.expr, eval_kind); + case EXPR_SUBSCRIPT: + if (!expr_is_constant_eval(expr->subscript_expr.index, eval_kind)) return false; + expr = expr->subscript_expr.expr; + goto RETRY; + case EXPR_TERNARY: + assert(!expr_is_constant_eval(expr->ternary_expr.cond, eval_kind)); + return false; + case EXPR_TRY: + expr = expr->try_expr.expr; + goto RETRY; + case EXPR_TYPEID: + return eval_kind == CONSTANT_EVAL_ANY; + case EXPR_UNARY: + switch (expr->unary_expr.operator) + { + case UNARYOP_ERROR: + case UNARYOP_DEREF: + return false; + case UNARYOP_ADDR: + return expr_unary_addr_is_constant_eval(expr, eval_kind); + case UNARYOP_NEG: + case UNARYOP_BITNEG: + case UNARYOP_NOT: + case UNARYOP_TADDR: + expr = expr->unary_expr.expr; + goto RETRY; + case UNARYOP_INC: + case UNARYOP_DEC: + return false; + } + UNREACHABLE + case EXPR_CT_CALL: + case EXPR_TYPEOF: + case EXPR_TYPEINFO: + case EXPR_HASH_IDENT: + case EXPR_CT_IDENT: + case EXPR_FLATPATH: + case EXPR_COMPOUND_LITERAL: + case EXPR_MACRO_EXPANSION: + case EXPR_PLACEHOLDER: + case EXPR_POISONED: + UNREACHABLE + case EXPR_NOP: + return true; + } + UNREACHABLE +} + + void expr_insert_deref(Expr *original) { assert(original->resolve_status == RESOLVE_DONE); @@ -141,7 +376,6 @@ void expr_insert_deref(Expr *original) original->unary_expr.operator = UNARYOP_DEREF; original->unary_expr.expr = inner; original->pure = false; - original->constant = false; original->failable = inner->failable; } @@ -149,7 +383,6 @@ void expr_insert_deref(Expr *original) static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right) { expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; expr->failable = left->failable | right->failable; } @@ -310,7 +543,10 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr switch (decl->var.kind) { case VARDECL_CONST: - if (!type_is_builtin(decl->type->type_kind)) break; + if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) + { + UNREACHABLE + } expr_replace(expr, copy_expr(decl->var.init_expr)); return sema_analyse_expr(context, to, expr); case VARDECL_PARAM_EXPR: @@ -402,6 +638,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e { Expr *left = expr->ternary_expr.then_expr; Expr *cond = expr->ternary_expr.cond; + int path = -1; // Normal if (left) { @@ -409,6 +646,10 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (!cast_implicit(cond, type_bool)) return expr_poison(expr); if (!sema_analyse_expr(context, to, left)) return expr_poison(expr); expr->failable = left->failable | cond->failable; + if (cond->expr_kind == EXPR_CONST) + { + path = cond->const_expr.b ? 1 : 0; + } } else { @@ -421,6 +662,13 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e SEMA_ERROR(cond, "Cannot convert expression to boolean."); return false; } + if (expr_is_constant_eval(cond, true)) + { + Expr *copy = copy_expr(cond); + cast(copy, type_bool); + assert(cond->expr_kind == EXPR_CONST); + path = cond->const_expr.b ? 1 : 0; + } left = cond; } @@ -428,7 +676,6 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (!sema_analyse_expr(context, to, right)) return expr_poison(expr); expr->pure = cond->pure & left->pure & right->pure; - expr->constant = cond->constant & left->constant & right->pure; expr->failable |= right->failable; Type *left_canonical = left->type->canonical; @@ -458,8 +705,12 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false; } - expr_unify_binary(expr, left, right); + if (path > -1) + { + expr_replace(expr, path ? left : right); + } + expr_unify_binary(expr, left, right); return true; } @@ -487,7 +738,6 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, TokenId name, Dec assert(enum_constant->resolve_status == RESOLVE_DONE); expr_set_type(expr, decl->type); expr->expr_kind = EXPR_CONST; - expr->constant = true; expr->pure = true; if (enum_constant->decl_kind == DECL_ENUM_CONSTANT) { @@ -522,37 +772,6 @@ static inline bool find_possible_inferred_identifier(Type *to, Expr *expr) } -bool expr_is_constant_eval(Expr *expr) -{ - // TODO rethink this. - switch (expr->expr_kind) - { - case EXPR_CONST: - return true; - case EXPR_COMPOUND_LITERAL: - return expr_is_constant_eval(expr->expr_compound_literal.initializer); - case EXPR_INITIALIZER_LIST: - { - Expr** init_exprs = expr->initializer_list; - VECEACH(init_exprs, i) - { - if (!expr_is_constant_eval(init_exprs[i])) return false; - } - return true; - } - case EXPR_DESIGNATED_INITIALIZER_LIST: - { - Expr** init_exprs = expr->designated_init_list; - VECEACH(init_exprs, i) - { - if (!expr_is_constant_eval(init_exprs[i])) return false; - } - return true; - } - default: - return false; - } -} static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr *expr) { @@ -605,7 +824,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr { Expr *copy = copy_expr(decl->var.init_expr); if (!sema_analyse_expr(context, to, copy)) return false; - if (!expr_is_constant_eval(copy)) + if (!expr_is_constant_eval(copy, false)) { SEMA_ERROR(expr, "Constant value did not evaluate to a constant."); return false; @@ -627,7 +846,6 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr expr->identifier_expr.decl = decl; expr_set_type(expr, decl->type); expr->pure = true; - expr->constant = false; DEBUG_LOG("Resolution successful of %s.", decl->name); return true; } @@ -693,7 +911,6 @@ static inline bool sema_expr_analyse_ct_identifier(Context *context, Expr *expr) expr->ct_ident_expr.decl = decl; expr_set_type(expr, decl->type); expr->pure = true; - expr->constant = true; return true; } @@ -1156,7 +1373,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal // $foo assert(callee.macro); if (!sema_analyse_expr_of_required_type(context, param->type, arg, false)) return false; - if (!expr_is_constant_eval(arg)) + if (!expr_is_constant_eval(arg, CONSTANT_EVAL_ANY)) { SEMA_ERROR(arg, "A compile time parameter must always be a constant, did you mistake it for a normal paramter?"); return false; @@ -1338,7 +1555,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast) return true; case AST_RETURN_STMT: if (!ast->return_stmt.expr) return true; - return expr_is_constant_eval(ast->return_stmt.expr); + return expr_is_constant_eval(ast->return_stmt.expr, CONSTANT_EVAL_ANY); case AST_EXPR_STMT: return sema_check_expr_compile_time(context, ast->expr_stmt); case AST_CT_COMPOUND_STMT: @@ -1492,7 +1709,7 @@ static bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_ if (vec_size(context->returns) == 1) { Expr *result = context->returns[0]->return_stmt.expr; - if (result && expr_is_constant_eval(result)) + if (result && expr_is_constant_eval(result, CONSTANT_EVAL_ANY)) { if (sema_check_stmt_compile_time(context, body)) { @@ -1727,7 +1944,6 @@ bool sema_expr_analyse_general_call(Context *context, Type *to, Expr *expr, Decl static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr) { - expr->constant = false; expr->pure = false; Expr *func_expr = expr->call_expr.function; @@ -1858,24 +2074,59 @@ static Type *sema_expr_find_indexable_type_recursively(Type **type, Expr **paren } static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr) { - if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false; + Expr *subscripted = expr->subscript_expr.expr; + if (!sema_analyse_expr_value(context, NULL, subscripted)) return false; + + Expr *index = expr->subscript_expr.index; + if (!sema_analyse_expr(context, NULL, index)) return false; + expr->failable = expr->subscript_expr.expr->failable; assert(expr->expr_kind == EXPR_SUBSCRIPT); - Expr *subscripted = expr->subscript_expr.expr; Type *type = type_flatten(subscripted->type); - Expr *index = expr->subscript_expr.index; Type *current_type = type; Expr *current_expr = subscripted; + if (type == type_complist) + { + assert(current_expr->expr_kind == EXPR_CT_IDENT); + current_expr = current_expr->ct_ident_expr.decl->var.init_expr; + assert(current_expr->expr_kind == EXPR_INITIALIZER_LIST); + if (index->expr_kind != EXPR_CONST || index->const_expr.const_kind != CONST_INTEGER) + { + SEMA_ERROR(index, "To subscript a compile time list a compile time integer index is needed."); + return false; + } + if (!bigint_fits_in_bits(&index->const_expr.i, 64, true)) + { + SEMA_ERROR(index, "Index does not fit into an 64-signed integer."); + return false; + } + int64_t i = bigint_as_signed(&index->const_expr.i); + unsigned count = vec_size(current_expr->initializer_list); + if (expr->subscript_expr.from_back) + { + i = count - i; + } + if (i < 0 || i >= count) + { + SEMA_ERROR(index, "Index %lld is out of range.", (long long)i); + return false; + } + Expr *indexed_expr = current_expr->initializer_list[i]; + if (!sema_cast_rvalue(context, NULL, indexed_expr)) return false; + expr_replace(expr, indexed_expr); + return true; + } + + if (!sema_cast_rvalue(context, NULL, current_expr)) return false; Type *inner_type = sema_expr_find_indexable_type_recursively(¤t_type, ¤t_expr); if (!inner_type) { SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(type)); return false; } - if (!sema_analyse_expr(context, NULL, index)) return false; - expr->constant = index->constant & subscripted->constant; + expr->pure = index->pure & subscripted->pure; // Cast to an appropriate type for index. @@ -1897,7 +2148,6 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) assert(expr->expr_kind == EXPR_SLICE); Expr *subscripted = expr->slice_expr.expr; expr->pure = subscripted->pure; - expr->constant = subscripted->constant; Type *type = type_flatten(subscripted->type); Expr *start = expr->slice_expr.start; Expr *end = expr->slice_expr.end; @@ -1914,10 +2164,8 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr) if (!sema_analyse_expr(context, type_int, start)) return false; expr->pure &= start->pure; - expr->constant &= start->constant; if (end && !sema_analyse_expr(context, type_int, end)) return false; expr->pure &= !end || end->pure; - expr->constant &= !end || end->constant; // Fix index sizes if (!expr_cast_to_index(start)) return false; @@ -2002,7 +2250,6 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, expr_to_rewrite->expr_kind = EXPR_CONST; expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind); expr_set_type(expr_to_rewrite, type); - expr_to_rewrite->constant = true; expr_to_rewrite->pure = true; expr_to_rewrite->resolve_status = RESOLVE_DONE; } @@ -2011,7 +2258,6 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string) { expr_to_rewrite->expr_kind = EXPR_CONST; - expr_to_rewrite->constant = true; expr_to_rewrite->const_expr.const_kind = CONST_STRING; expr_to_rewrite->const_expr.string.chars = (char *)string; expr_to_rewrite->const_expr.string.len = (int)strlen(string); @@ -2023,7 +2269,6 @@ static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *str static bool sema_expr_analyse_typeinfo(Context *context, Expr *expr) { - expr->constant = true; expr->pure = true; TypeInfo *type_info = expr->type_expr; @@ -2139,7 +2384,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T return false; } - expr->constant = true; expr->pure = true; TokenType type = TOKTYPE(identifier_token); @@ -2171,7 +2415,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T expr->const_expr.f = nan(""); #endif expr_set_type(expr, parent->type); - expr->constant = true; expr->pure = true; expr->resolve_status = RESOLVE_DONE; return true; @@ -2183,7 +2426,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T expr->const_expr.const_kind = CONST_FLOAT; expr->const_expr.f = INFINITY; expr_set_type(expr, parent->type->canonical); - expr->constant = true; expr->pure = true; expr->resolve_status = RESOLVE_DONE; return true; @@ -2317,7 +2559,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T expr->type_expr->type = member->type; expr->type_expr->resolve_status = RESOLVE_DONE; expr_set_type(expr, type_typeinfo); - expr->constant = expr->pure = true; + expr->pure = true; return true; } @@ -2460,7 +2702,6 @@ CHECK_DEEPER: // 13. Copy properties. expr->access_expr.parent = current_parent; - expr->constant = expr->access_expr.parent->constant; expr->pure = expr->access_expr.parent->pure; expr_set_type(expr, member->type); expr->access_expr.ref = member; @@ -2621,7 +2862,6 @@ static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr } current = new_current; } - expr->constant = is_constant; expr->pure = is_constant; return current; } @@ -2926,7 +3166,6 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass bool is_structlike = type_is_structlike(assigned->canonical); initializer->pure = true; - initializer->constant = true; ArrayIndex max_index = -1; VECEACH(init_expressions, i) { @@ -2935,18 +3174,17 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass if (!result) return false; if (!sema_analyse_expr_of_required_type(context, result, expr->designator_expr.value, true)) return false; expr->pure &= expr->designator_expr.value->pure; - expr->constant &= expr->designator_expr.value->constant; expr->failable |= expr->designator_expr.value->failable; expr->resolve_status = RESOLVE_DONE; initializer->pure &= expr->pure; - initializer->constant &= expr->constant; } if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY) { initializer->type = sema_type_lower_by_size(initializer->type, max_index + 1); } - if (initializer->constant) + + if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY)) { ConstInitializer *const_init = MALLOC(sizeof(ConstInitializer)); sema_create_const_initializer(const_init, initializer); @@ -2963,7 +3201,6 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer) { initializer->pure = true; - initializer->constant = true; Expr **elements = initializer->initializer_list; Decl **members = assigned->strukt.members; @@ -3000,7 +3237,6 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, // 5. We know the required type, so resolve the expression. if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i], 0)) return false; initializer->pure &= element->pure; - initializer->constant &= element->constant; initializer->failable |= element->failable; } @@ -3011,7 +3247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, return false; } - if (initializer->constant) + if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY)) { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_STRUCT; @@ -3045,7 +3281,6 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer) { initializer->pure = true; - initializer->constant = true; Expr **elements = initializer->initializer_list; @@ -3075,7 +3310,6 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T if (!sema_analyse_expr_of_required_type(context, inner_type, element, true)) return false; initializer->failable |= element->failable; initializer->pure &= element->pure; - initializer->constant &= element->constant; } if (expected_members > size) @@ -3084,7 +3318,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T return false; } - if (initializer->constant) + if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY)) { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_ARRAY_FULL; @@ -3113,21 +3347,18 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T static inline bool sema_expr_analyse_untyped_initializer(Context *context, Expr *initializer) { initializer->pure = true; - initializer->constant = true; Expr **elements = initializer->initializer_list; - unsigned size = vec_size(elements); - Type *element_type = NULL; bool no_common_elements = false; - VECEACH(elements, i) + unsigned element_count = vec_size(elements); + for (unsigned i = 0; i < element_count; i++) { Expr *element = elements[i]; if (!sema_analyse_expr(context, NULL, element)) return false; initializer->failable |= element->failable; initializer->pure &= element->pure; - initializer->constant &= element->constant; if (no_common_elements) continue; if (element_type == NULL) { @@ -3137,7 +3368,13 @@ static inline bool sema_expr_analyse_untyped_initializer(Context *context, Expr element_type = type_find_max_type(element->type, element_type); if (!element_type) no_common_elements = true; } - TODO + if (no_common_elements || type_is_ct(element_type)) + { + expr_set_type(initializer, type_complist); + return true; + } + expr_set_type(initializer, type_get_array(element_type, element_count)); + return true; } static inline bool sema_expr_analyse_initializer(Context *context, Type *external_type, Type *assigned, Expr *expr) @@ -3167,7 +3404,6 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *externa initializer->kind = CONST_INIT_ZERO; initializer->type = type_flatten(expr->type); expr_set_as_const_list(expr, initializer); - expr->constant = true; expr->pure = true; return true; } @@ -3203,8 +3439,20 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to case TYPE_UNION: case TYPE_ARRAY: case TYPE_INFERRED_ARRAY: - case TYPE_SUBARRAY: return sema_expr_analyse_initializer(context, to, assigned, expr); + case TYPE_SUBARRAY: + { + // Resolve this as an inferred array. + Type *type = type_get_inferred_array(assigned->array.base); + if (!sema_expr_analyse_initializer(context, type, type, expr)) return false; + expr->resolve_status = RESOLVE_DONE; + expr_insert_addr(expr); + if (!sema_analyse_expr(context, NULL, expr)) return false; + return cast(expr, to); + } + case TYPE_POINTER: + SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array."); + return false; default: break; } @@ -3226,11 +3474,9 @@ static inline bool sema_expr_analyse_expr_list(Context *context, Type *to, Expr Expr *checked_expr = expr->expression_list[i]; success &= sema_analyse_expr_of_required_type(context, i == last ? to : NULL, checked_expr, 0); expr->failable |= checked_expr->failable; - constant &= checked_expr->constant; pure &= checked_expr->pure; } expr->pure = pure; - expr->constant = constant; return success; } @@ -3240,7 +3486,6 @@ static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr bool success = sema_resolve_type_info(context, expr->cast_expr.type_info); success &= sema_analyse_expr(context, NULL, inner); expr->pure = inner->pure; - expr->constant = inner->constant; if (!success) return false; Type *target_type = expr->cast_expr.type_info->type; @@ -3413,7 +3658,6 @@ static bool sema_expr_analyse_ct_type_identifier_assign(Context *context, Expr * */ static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right) { - expr->constant = false; expr->pure = false; @@ -3493,7 +3737,6 @@ static bool sema_expr_analyse_ct_common_assign(Context *context, Expr *expr, Exp static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr *left, Expr *right, bool int_only) { expr->pure = false; - expr->constant = false; if (left->expr_kind == EXPR_CT_IDENT) { @@ -3604,7 +3847,6 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr // 3. Copy type & set properties. expr_copy_types(expr, left); expr->pure = false; - expr->constant = false; expr->failable = left->failable | right->failable; @@ -3701,6 +3943,24 @@ static void unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type ** *right_type_ref = *left_type_ref; } } + +static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff) +{ + // Do we have (iptr)(ptr) +- rhs? If so we change it to + // (iptr)((char*)(ptr) +- 1) + if (maybe_pointer->expr_kind == EXPR_CAST + && maybe_pointer->cast_expr.kind == CAST_PTRXI + && type_flatten(maybe_pointer->type) == type_flatten(type_iptr) + && cast_may_implicit(maybe_diff->type, maybe_diff->type)) + { + Type *cast_to_iptr = maybe_pointer->type; + maybe_pointer->cast_expr.kind = CAST_PTRPTR; + maybe_pointer->type = type_get_ptr(type_char); + return cast_to_iptr; + } + return NULL; +} + /** * Analyse a - b * @return true if analysis succeeded @@ -3710,6 +3970,10 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * // 1. Analyse a and b. if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; + // Do we have (iptr)(ptr) - rhs? If so we change it to + // (iptr)((char*)(ptr) - 1) + Type *cast_to_iptr = defer_iptr_cast(left, right); + Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; @@ -3759,7 +4023,11 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr * // 7. Assign the type of the left side. expr_copy_types(expr, left); expr_unify_binary_properties(expr, left, right); - + if (cast_to_iptr) + { + expr->resolve_status = RESOLVE_DONE; + return cast(expr, cast_to_iptr); + } return true; } @@ -3804,6 +4072,9 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * // this is safe in the pointer case actually. if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; + Type *cast_to_iptr = defer_iptr_cast(left, right); + if (!cast_to_iptr) cast_to_iptr = defer_iptr_cast(right, left); + Type *left_type = left->type->canonical; Type *right_type = right->type->canonical; @@ -3843,9 +4114,16 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr * // 3c. Set the type and other properties. expr_copy_types(expr, left); expr_unify_binary_properties(expr, left, right); + + if (cast_to_iptr) + { + expr->resolve_status = RESOLVE_DONE; + return cast(expr, cast_to_iptr); + } return true; } + assert(!cast_to_iptr); // 4. Do an binary arithmetic promotion if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s.")) { @@ -4095,7 +4373,6 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr if (!cast_implicit(left, numeric_arithmetic_promotion(left->type))) return false; expr->pure = left->pure & right->pure; - expr->constant = left->constant & right->constant; expr->failable = left->failable | right->failable; // 5. For a constant right hand side we will make a series of checks. @@ -4178,7 +4455,6 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false; expr->pure = false; - expr->constant = false; expr->failable = left->failable | right->failable; // 2. Ensure the left hand side is assignable @@ -4487,7 +4763,6 @@ static bool sema_take_addr_of(Expr *inner, bool *is_constant) case EXPR_CONST_IDENTIFIER: return sema_take_addr_of_ident(inner, is_constant); case EXPR_UNARY: - *is_constant = inner->constant; if (inner->unary_expr.operator == UNARYOP_DEREF) return true; break; case EXPR_ACCESS: @@ -4498,12 +4773,10 @@ static bool sema_take_addr_of(Expr *inner, bool *is_constant) { bool index_was_const = false; if (!sema_take_addr_of(inner->subscript_expr.expr, &index_was_const)) return false; - *is_constant = index_was_const && inner->constant; return true; } case EXPR_SLICE: { - *is_constant = false; bool dummy; return sema_take_addr_of(inner->slice_expr.expr, &dummy); } @@ -4540,7 +4813,6 @@ static bool sema_expr_analyse_addr(Context *context, Type *to, Expr *expr, Expr // 3. Get the pointer of the underlying type. expr_set_type(expr, type_get_ptr(inner->type)); - expr->constant = is_constant; expr->pure = inner->pure; expr->failable = inner->failable; @@ -4697,8 +4969,7 @@ static inline bool sema_expr_analyse_ct_incdec(Context *context, Expr *expr, Exp * @return false if analysis fails. */ static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner) -{ - expr->constant = false; +{; expr->pure = false; expr->failable = inner->failable; @@ -4865,7 +5136,6 @@ static inline bool sema_expr_analyse_post_unary(Context *context, Type *to, Expr static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bool implicitly_create_variable) { - expr->constant = false; Expr *init = expr->try_assign_expr.init; Expr *lhs = expr->try_assign_expr.expr; @@ -4935,7 +5205,7 @@ static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bo if (!sema_analyse_expr_value(context, NULL, lhs)) return false; } - expr->constant = false; + expr->pure = init->pure & lhs->pure; expr_set_type(expr, type_bool); return true; @@ -4945,7 +5215,7 @@ static inline bool sema_expr_analyse_try(Context *context, Expr *expr) Expr *inner = expr->try_expr.expr; if (!sema_analyse_expr(context, NULL, inner)) return false; expr->pure = inner->pure; - expr->constant = false; + if (!inner->failable) { SEMA_ERROR(expr->try_expr.expr, "Expected a failable expression to '%s'.", expr->expr_kind == EXPR_TRY ? "try" : "catch"); @@ -4960,7 +5230,7 @@ static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr Expr *inner = expr->else_expr.expr; bool success = sema_analyse_expr(context, to, inner); expr->pure = inner->pure; - expr->constant = false; + if (!success) return false; Type *type = inner->type; if (!inner->failable) @@ -4997,7 +5267,7 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp if (!success) return false; expr_copy_types(expr, inner); expr->pure = false; - expr->constant = false; + if (!inner->failable) { SEMA_ERROR(expr, "No failable to rethrow before '!!' in the expression, please remove '!!'."); @@ -5013,7 +5283,6 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp static inline bool sema_expr_analyse_const(Type *to, Expr *expr) { - expr->constant = true; expr->pure = true; return true; } @@ -5089,7 +5358,7 @@ static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr expr->failable = context->expr_failable_return; context->expr_failable_return = saved_expr_failable_return; context->expected_block_type = prev_expected_block_type; - expr->constant = false; + expr->pure = false; return success; } @@ -5109,7 +5378,7 @@ static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr) TODO if (!sema_analyse_expr(context, NULL, expr->typeof_expr)) return false; expr->pure = expr->typeof_expr->pure; - expr->constant = expr->typeof_expr->constant; + Type *type = expr->typeof_expr->type->canonical; expr->expr_kind = EXPR_TYPEID; expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span); @@ -5125,7 +5394,7 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr * if (!sema_analyse_expr(context, NULL, inner)) return false; expr->pure = inner->pure; - expr->constant = inner->constant; + if (inner->failable) { SEMA_ERROR(inner, "The inner expression is already a failable."); @@ -5984,7 +6253,7 @@ static inline bool sema_expr_analyse_decl(Context *context, Type *to, Expr *expr if (!sema_analyse_var_decl(context, expr->decl_expr)) return false; expr_set_type(expr, expr->decl_expr->type); expr->pure = !expr->decl_expr->var.init_expr || expr->decl_expr->var.init_expr->pure; - expr->constant = expr->decl_expr->var.kind == VARDECL_CONST; + return true; } static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) @@ -6041,7 +6310,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * case EXPR_GUARD: return sema_expr_analyse_guard(context, to, expr); case EXPR_CONST: - case EXPR_BYTES: return sema_expr_analyse_const(to, expr); case EXPR_BINARY: if (!sema_expr_analyse_binary(context, to, expr)) return false; diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 655a66092..f15f8ac77 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -441,10 +441,12 @@ bool sema_add_member(Context *context, Decl *decl) bool sema_add_local(Context *context, Decl *decl) { + decl->module = context->module; // Ignore synthetic locals. if (decl->name_token.index == NO_TOKEN_ID.index) return true; Decl *other = sema_resolve_normal_symbol(context, decl->name_token, NULL, false); - if (other) + assert(!other || other->module); + if (other && other->module == context->module) { sema_shadow_error(decl, other); decl_poison(decl); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index fdfd7753d..de8f0b86c 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -724,7 +724,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl) } if (decl->var.init_expr && decl->var.is_static) { - if (!expr_is_constant_eval(decl->var.init_expr)) + if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) { SEMA_ERROR(decl->var.init_expr, "Static variable initialization must be constant."); return false; @@ -762,9 +762,9 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement) if (decl->var.init_expr) { if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false; - if (decl->var.init_expr->expr_kind != EXPR_CONST) + if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY)) { - SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here."); + SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name); return false; } } @@ -776,12 +776,13 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement) } else { - if (decl->var.init_expr) + Expr *init = decl->var.init_expr; + if (init) { - if (!sema_analyse_expr(context, NULL, decl->var.init_expr)) return false; - if (decl->var.init_expr->expr_kind != EXPR_CONST) + if (!sema_analyse_expr(context, NULL, init)) return false; + if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY)) { - SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here."); + SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name); return false; } decl->type = decl->var.init_expr->type; diff --git a/src/version.h b/src/version.h index 5e30b6c21..f59962f01 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "A232" \ No newline at end of file +#define COMPILER_VERSION "A233" \ No newline at end of file diff --git a/test/test_suite/compile_time/compile_time_ptr_ref.c3t b/test/test_suite/compile_time/compile_time_ptr_ref.c3t new file mode 100644 index 000000000..404ed8405 --- /dev/null +++ b/test/test_suite/compile_time/compile_time_ptr_ref.c3t @@ -0,0 +1,22 @@ +// #target: x64-darwin +module test; + + +int*[] blurp = { &ptr, &ptr, (&ptr + 1), &ptr - 1, (int*)((iptr)(&ptr) - 4) }; +int* c = (int*)((iptr)(&ptr) - 4); +int* c2 = (int*)((iptr)(&ptr) + 4); +int* c3 = (int*)(4 + (iptr)(&ptr)); +iptr ff = (iptr)(&ptr); +int ptr = 0; + +// #expect: test.ll + +%"int*[]" = type { i32**, i64 } + +@.taddr = private hidden global [5 x i32*] [i32* @test.ptr, i32* @test.ptr, i32* getelementptr inbounds (i32, i32* @test.ptr, i64 1), i32* getelementptr (i32, i32* @test.ptr, i64 -1), i32* bitcast (i8* getelementptr (i8, i8* bitcast (i32* @test.ptr to i8*), i64 -4) to i32*)], align 8 +@test.blurp = global %"int*[]" { i32** getelementptr inbounds ([5 x i32*], [5 x i32*]* @.taddr, i32 0, i32 0), i64 5 }, align 8 +@test.c = global i32* bitcast (i8* getelementptr (i8, i8* bitcast (i32* @test.ptr to i8*), i64 -4) to i32*), align 8 +@test.c2 = global i32* bitcast (i8* getelementptr (i8, i8* bitcast (i32* @test.ptr to i8*), i64 4) to i32*), align 8 +@test.c3 = global i32* bitcast (i8* getelementptr (i8, i8* bitcast (i32* @test.ptr to i8*), i64 4) to i32*), align 8 +@test.ff = global i64 ptrtoint (i32* @test.ptr to i64), align 8 +@test.ptr = global i32 0, align 4 \ No newline at end of file diff --git a/test/test_suite/compile_time/ternary_folding.c3t b/test/test_suite/compile_time/ternary_folding.c3t new file mode 100644 index 000000000..2ceafe276 --- /dev/null +++ b/test/test_suite/compile_time/ternary_folding.c3t @@ -0,0 +1,25 @@ +// #target: x64-darwin + +int foo = 2.2 ? 1 : 2; +double bar = false ? 1.0 : 2; +bool baz = 1 ? false : true; + +func void test() +{ + int x = 1 ? 0 : test2(); +} + +func int test2() { return 3; } + +// #expect: ternary_folding.ll + +@ternary_folding.foo = global i32 1, align 4 +@ternary_folding.bar = global double 2.000000e+00, align 8 +@ternary_folding.baz = global i8 0, align 1 + +define void @ternary_folding.test() #0 { +entry: + %x = alloca i32, align 4 + store i32 0, i32* %x, align 4 + ret void +} \ No newline at end of file diff --git a/test/test_suite/functions/test_regression.c3t b/test/test_suite/functions/test_regression.c3t index bfcb950d0..ec59fdc2c 100644 --- a/test/test_suite/functions/test_regression.c3t +++ b/test/test_suite/functions/test_regression.c3t @@ -355,7 +355,7 @@ entry: %x = alloca %"int[]", align 8 %sum = alloca i32, align 4 %vararg = alloca %"int[]", align 8 - %tempaddr = alloca %"int[]", align 8 + %taddr = alloca %"int[]", align 8 %pair = bitcast %"int[]"* %x to { i8*, i64 }* %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 store i8* %0, i8** %lo, align 8 @@ -387,8 +387,8 @@ if.exit: ; preds = %entry %10 = insertvalue %"int[]" %9, i64 %size, 1 %11 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 %12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 - store %"int[]" %10, %"int[]"* %tempaddr, align 8 - %casttemp = bitcast %"int[]"* %tempaddr to { i8*, i64 }* + store %"int[]" %10, %"int[]"* %taddr, align 8 + %casttemp = bitcast %"int[]"* %taddr to { i8*, i64 }* %lo1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0 %lo2 = load i8*, i8** %lo1, align 8 %hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1 diff --git a/test/test_suite/initializer_lists/disallowed_lists.c3 b/test/test_suite/initializer_lists/disallowed_lists.c3 new file mode 100644 index 000000000..b3ba706d5 --- /dev/null +++ b/test/test_suite/initializer_lists/disallowed_lists.c3 @@ -0,0 +1,8 @@ +func void test() +{ + char* hello = "123"; + char[] a = { '1', '2', '3' }; + char[*] b = { '1', '2', '3' }; + char[3] c = { '1', '2', '3' }; + char* d = { '1', '2', '3' }; // #error: Pointers cannot be initialized using an initializer list, instead you need to take the address of an array +} \ No newline at end of file diff --git a/test/test_suite/initializer_lists/fasta.c3t b/test/test_suite/initializer_lists/fasta.c3t index 5a72fff83..99c3a0321 100644 --- a/test/test_suite/initializer_lists/fasta.c3t +++ b/test/test_suite/initializer_lists/fasta.c3t @@ -105,6 +105,8 @@ func void main(int argc, char **argv) } // #expect: fasta.ll +%"char[]" = type { i8*, i64 } +%"double[]" = type { double*, i64 } @fasta.IM = constant i32 139968, align 1 @fasta.IA = constant i32 3877, align 1 @@ -115,12 +117,12 @@ func void main(int argc, char **argv) @fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8 @.str.11 = private constant [16 x i8] c"acgtBDHKMNRSVWY\00", align 1 @fasta.iub = global %"char[]" { i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.11, i32 0, i32 0), i64 15 }, align 8 -@.__const = private constant [15 x double] [double 2.700000e-01, double 1.200000e-01, double 1.200000e-01, double 2.700000e-01, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02], align 8 -@fasta.iub_p = global %"double[]" { %"double[]"* bitcast ([15 x double]* @.__const to %"double[]"*), i64 15 }, align 8 +@.taddr = private hidden global [15 x double] [double 2.700000e-01, double 1.200000e-01, double 1.200000e-01, double 2.700000e-01, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02], align 8 +@fasta.iub_p = global %"double[]" { double* getelementptr inbounds ([15 x double], [15 x double]* @.taddr, i32 0, i32 0), i64 15 }, align 8 @.str.12 = private constant [5 x i8] c"acgt\00", align 1 @fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8 -@.__const.13 = private constant [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8 -@fasta.homosapiens_p = global %"double[]" { %"double[]"* bitcast ([4 x double]* @.__const.13 to %"double[]"*), i64 4 }, align 8 +@.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8 +@fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8 @fasta.LINELEN = constant i32 60, align 1 @.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1 @.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1 @@ -381,4 +383,4 @@ if.exit: ; preds = %if.then, %entry %mul10 = mul i32 %11, 5 call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10) ret void -} \ No newline at end of file +} diff --git a/test/test_suite/initializer_lists/general_tests.c3t b/test/test_suite/initializer_lists/general_tests.c3t index 5a5f69cd0..12a10b387 100644 --- a/test/test_suite/initializer_lists/general_tests.c3t +++ b/test/test_suite/initializer_lists/general_tests.c3t @@ -1,4 +1,4 @@ -// #skip +// #target: x64-darwin union Baz { @@ -16,7 +16,11 @@ func int test() Baz ffe = { .x = 1 }; int[1] azz = {}; int[*] a = {}; - var $foo = { 1, 2, 3 }; + var $foo = { 11, 22, 33 }; + static int foo1 = $foo[1]; + int foo2 = $foo[2]; + var $foos = { "Hello!" }; + char* str = $foos[0]; bool x = ! int[] { 1, 2, 3 }; Bar b = {}; Baz z = {}; @@ -24,4 +28,81 @@ func int test() Bar[] foo = {}; Baz[3] baz = {}; return 1; -} \ No newline at end of file +} + + +// #expect: general_tests.ll + +%Baz = type { double } +%Bar = type { i32, i32 } +%"int[]" = type { i32*, i64 } +%"Bar[]" = type { %Bar*, i64 } + +@Baz = linkonce_odr constant i8 1 +@Bar = linkonce_odr constant i8 1 +@.__const = private constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8 +@test.foo1 = hidden global i32 22, align 4 +@.str = private constant [7 x i8] c"Hello!\00", align 1 + +; Function Attrs: nounwind +define i32 @general_tests.test() #0 { +entry: + %ffe = alloca %Baz, align 8 + %azz = alloca [1 x i32], align 4 + %a = alloca [0 x i32], align 4 + %foo2 = alloca i32, align 4 + %str = alloca i8*, align 8 + %literal = alloca [1 x i8*], align 8 + %x = alloca i8, align 1 + %literal1 = alloca [3 x i32], align 4 + %b = alloca %Bar, align 4 + %z = alloca %Baz, align 8 + %sub = alloca %"int[]", align 8 + %literal2 = alloca [0 x i32], align 4 + %foo = alloca %"Bar[]", align 8 + %literal3 = alloca [0 x %Bar], align 4 + %baz = alloca [3 x %Baz], align 16 + %0 = bitcast %Baz* %ffe to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %0, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false) + %1 = bitcast [1 x i32]* %azz to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false) + %2 = bitcast [0 x i32]* %a to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 0, i1 false) + store i32 33, i32* %foo2, align 4 + %3 = getelementptr inbounds i8*, [1 x i8*]* %literal, i32 0 + store i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i8** %3, align 8 + %arridx = getelementptr inbounds [1 x i8*], [1 x i8*]* %literal, i64 0, i64 0 + %4 = load i8*, i8** %arridx, align 8 + store i8* %4, i8** %str, align 8 + %5 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 0 + store i32 1, i32* %5, align 4 + %6 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 1 + store i32 2, i32* %6, align 4 + %7 = getelementptr inbounds i32, [3 x i32]* %literal1, i32 2 + store i32 3, i32* %7, align 4 + %8 = bitcast [3 x i32]* %literal1 to i32* + %9 = insertvalue %"int[]" undef, i32* %8, 0 + %10 = insertvalue %"int[]" %9, i64 3, 1 + %11 = extractvalue %"int[]" %10, 1 + %neq = icmp ne i64 %11, 0 + %not = xor i1 %neq, true + %12 = zext i1 %not to i8 + store i8 %12, i8* %x, align 1 + %13 = bitcast %Bar* %b to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %13, i8 0, i64 8, i1 false) + %14 = bitcast %Baz* %z to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %14, i8 0, i64 8, i1 false) + store [0 x i32] zeroinitializer, [0 x i32]* %literal2, align 4 + %15 = bitcast [0 x i32]* %literal2 to i32* + %16 = insertvalue %"int[]" undef, i32* %15, 0 + %17 = insertvalue %"int[]" %16, i64 0, 1 + store %"int[]" %17, %"int[]"* %sub, align 8 + store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal3, align 4 + %18 = bitcast [0 x %Bar]* %literal3 to %Bar* + %19 = insertvalue %"Bar[]" undef, %Bar* %18, 0 + %20 = insertvalue %"Bar[]" %19, i64 0, 1 + store %"Bar[]" %20, %"Bar[]"* %foo, align 8 + %21 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %21, i8 0, i64 24, i1 false) + ret i32 1 +} diff --git a/test/test_suite/initializer_lists/statics.c3t b/test/test_suite/initializer_lists/statics.c3t new file mode 100644 index 000000000..5f00bd4ae --- /dev/null +++ b/test/test_suite/initializer_lists/statics.c3t @@ -0,0 +1,93 @@ +// #target: x64-darwin +import std::io; +import std::mem; +union Baz +{ + int x; + double y; +} +struct Bar +{ + int x; + int y; +} + + +func void test() +{ + Bar[] b = { { 1, 2 } }; + static Bar[] c = { { 1, 2 } }; + io::printf("%d %d\n", b[0].y, c[0].y); + b[0].y += 1; + c[0].y += 1; + +} +func int main() +{ + test(); + test(); + test(); + return 1; +} + +// #expect: statics.ll + +%Bar = type { i32, i32 } +%"Bar[]" = type { %Bar*, i64 } + +@Baz = linkonce_odr constant i8 1 +@Bar = linkonce_odr constant i8 1 +@.taddr = private hidden global [1 x %Bar] [%Bar { i32 1, i32 2 }], align 4 +@test.c = hidden global %"Bar[]" { %Bar* getelementptr inbounds ([1 x %Bar], [1 x %Bar]* @.taddr, i32 0, i32 0), i64 1 }, align 8 +@.str = private constant [7 x i8] c"%d %d\0A\00", align 1 + +declare i32 @printf(i8*, ...) + +; Function Attrs: nounwind +define void @statics.test() #0 { +entry: + %b = alloca %"Bar[]", align 8 + %literal = alloca [1 x %Bar], align 4 + %0 = getelementptr inbounds %Bar, [1 x %Bar]* %literal, i32 0 + %1 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 0 + store i32 1, i32* %1, align 4 + %2 = getelementptr inbounds %Bar, %Bar* %0, i32 0, i32 1 + store i32 2, i32* %2, align 4 + %3 = bitcast [1 x %Bar]* %literal to %Bar* + %4 = insertvalue %"Bar[]" undef, %Bar* %3, 0 + %5 = insertvalue %"Bar[]" %4, i64 1, 1 + store %"Bar[]" %5, %"Bar[]"* %b, align 8 + %subarrayptr = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 + %saptr = load %Bar*, %Bar** %subarrayptr, align 8 + %sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 0 + %6 = getelementptr inbounds %Bar, %Bar* %sarridx, i32 0, i32 1 + %7 = load i32, i32* %6, align 4 + %saptr1 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 + %sarridx2 = getelementptr inbounds %Bar, %Bar* %saptr1, i64 0 + %8 = getelementptr inbounds %Bar, %Bar* %sarridx2, i32 0, i32 1 + %9 = load i32, i32* %8, align 4 + %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i32 %7, i32 %9) + %subarrayptr3 = getelementptr inbounds %"Bar[]", %"Bar[]"* %b, i32 0, i32 0 + %saptr4 = load %Bar*, %Bar** %subarrayptr3, align 8 + %sarridx5 = getelementptr inbounds %Bar, %Bar* %saptr4, i64 0 + %11 = getelementptr inbounds %Bar, %Bar* %sarridx5, i32 0, i32 1 + %12 = load i32, i32* %11, align 4 + %add = add i32 %12, 1 + store i32 %add, i32* %11, align 4 + %saptr6 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @test.c, i32 0, i32 0), align 8 + %sarridx7 = getelementptr inbounds %Bar, %Bar* %saptr6, i64 0 + %13 = getelementptr inbounds %Bar, %Bar* %sarridx7, i32 0, i32 1 + %14 = load i32, i32* %13, align 4 + %add8 = add i32 %14, 1 + store i32 %add8, i32* %13, align 4 + ret void +} + +; Function Attrs: nounwind +define i32 @main() #0 { +entry: + call void @statics.test() + call void @statics.test() + call void @statics.test() + ret i32 1 +} diff --git a/test/test_suite/initializer_lists/subarrays.c3t b/test/test_suite/initializer_lists/subarrays.c3t new file mode 100644 index 000000000..6f7acfd37 --- /dev/null +++ b/test/test_suite/initializer_lists/subarrays.c3t @@ -0,0 +1,180 @@ +// #target: x64-darwin + +import std::io; +import std::mem; +union Baz +{ + int x; + double y; +} +struct Bar +{ + int x; + int y; +} + + +Bar[] arrbar = { { 3, 4 }, { 8, 9 }}; +int[] xd = { 1, 2 }; +int* fofeo = &&(int[2]{ 3, 4 }); + +func int main() +{ + Bar w = arrbar[1]; + io::printf("%d\n", arrbar[1].x); + int[] x = { 1, 2, 3 }; + int* y = &&(int[3]{ 123, 234, 567 }); + io::println("Start:"); + io::printf("X len: %d mid element %d\n", (int)(x.len), x[1]); + io::printf("Y mid element %d\n", y[1]); + io::printf("Fofeo second element %d\n", fofeo[1]); + Baz ffe = { .x = 1 }; + int[1] azz = {}; + int[*] a = {}; + + //var $foo = { 1, 2, 3 }; + bool xy = ! int[] { 1, 2, 3 }; + if (!xy) io::println("Ok"); + Bar b = {}; + Baz z = {}; + int[] sub = {}; + Bar[] foo = {}; + Baz[3] baz = {}; + return 1; +} + +// #expect: subarrays.ll + +%Bar = type { i32, i32 } +%"Bar[]" = type { %Bar*, i64 } +%"int[]" = type { i32*, i64 } +%Baz = type { double } + +@Baz = linkonce_odr constant i8 1 +@Bar = linkonce_odr constant i8 1 +@.taddr = private hidden global [2 x %Bar] [%Bar { i32 3, i32 4 }, %Bar { i32 8, i32 9 }], align 4 +@subarrays.arrbar = global %"Bar[]" { %Bar* getelementptr inbounds ([2 x %Bar], [2 x %Bar]* @.taddr, i32 0, i32 0), i64 2 }, align 8 +@.taddr.3 = private hidden global [2 x i32] [i32 1, i32 2], align 4 +@subarrays.xd = global %"int[]" { i32* getelementptr inbounds ([2 x i32], [2 x i32]* @.taddr.3, i32 0, i32 0), i64 2 }, align 8 +@.taddr.4 = private hidden global [2 x i32] [i32 3, i32 4], align 4 +@subarrays.fofeo = global i32* getelementptr inbounds ([2 x i32], [2 x i32]* @.taddr.4, i32 0, i32 0), align 8 +@.str = private constant [4 x i8] c"%d\0A\00", align 1 +@.str.5 = private constant [7 x i8] c"Start:\00", align 1 +@.str.6 = private constant [26 x i8] c"X len: %d mid element %d\0A\00", align 1 +@.str.7 = private constant [18 x i8] c"Y mid element %d\0A\00", align 1 +@.str.8 = private constant [25 x i8] c"Fofeo second element %d\0A\00", align 1 +@.__const = private constant { i32, [4 x i8] } { i32 1, [4 x i8] undef }, align 8 +@.str.9 = private constant [3 x i8] c"Ok\00", align 1 + +define i32 @main() #0 { +entry: + %w = alloca %Bar, align 4 + %x = alloca %"int[]", align 8 + %literal = alloca [3 x i32], align 4 + %y = alloca i32*, align 8 + %literal3 = alloca [3 x i32], align 4 + %ffe = alloca %Baz, align 8 + %azz = alloca [1 x i32], align 4 + %a = alloca [0 x i32], align 4 + %xy = alloca i8, align 1 + %literal7 = alloca [3 x i32], align 4 + %b = alloca %Bar, align 4 + %z = alloca %Baz, align 8 + %sub = alloca %"int[]", align 8 + %literal9 = alloca [0 x i32], align 4 + %foo = alloca %"Bar[]", align 8 + %literal10 = alloca [0 x %Bar], align 4 + %baz = alloca [3 x %Baz], align 16 + %saptr = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 + %sarridx = getelementptr inbounds %Bar, %Bar* %saptr, i64 1 + %0 = bitcast %Bar* %w to i8* + %1 = bitcast %Bar* %sarridx to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 %1, i32 8, i1 false) + %saptr1 = load %Bar*, %Bar** getelementptr inbounds (%"Bar[]", %"Bar[]"* @subarrays.arrbar, i32 0, i32 0), align 8 + %sarridx2 = getelementptr inbounds %Bar, %Bar* %saptr1, i64 1 + %2 = getelementptr inbounds %Bar, %Bar* %sarridx2, i32 0, i32 0 + %3 = load i32, i32* %2, align 4 + %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %3) + %5 = getelementptr inbounds i32, [3 x i32]* %literal, i32 0 + store i32 1, i32* %5, align 4 + %6 = getelementptr inbounds i32, [3 x i32]* %literal, i32 1 + store i32 2, i32* %6, align 4 + %7 = getelementptr inbounds i32, [3 x i32]* %literal, i32 2 + store i32 3, i32* %7, align 4 + %8 = bitcast [3 x i32]* %literal to i32* + %9 = insertvalue %"int[]" undef, i32* %8, 0 + %10 = insertvalue %"int[]" %9, i64 3, 1 + store %"int[]" %10, %"int[]"* %x, align 8 + %11 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 0 + store i32 123, i32* %11, align 4 + %12 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 1 + store i32 234, i32* %12, align 4 + %13 = getelementptr inbounds i32, [3 x i32]* %literal3, i32 2 + store i32 567, i32* %13, align 4 + %ptrptr = bitcast [3 x i32]* %literal3 to i32* + store i32* %ptrptr, i32** %y, align 8 + %14 = call i32 @"std::io.println"(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0)) #3 + %len = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1 + %15 = load i64, i64* %len, align 8 + %uisitrunc = trunc i64 %15 to i32 + %subarrayptr = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0 + %saptr4 = load i32*, i32** %subarrayptr, align 8 + %sarridx5 = getelementptr inbounds i32, i32* %saptr4, i64 1 + %16 = load i32, i32* %sarridx5, align 4 + %17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.6, i32 0, i32 0), i32 %uisitrunc, i32 %16) + %18 = load i32*, i32** %y, align 8 + %ptridx = getelementptr inbounds i32, i32* %18, i64 1 + %19 = load i32, i32* %ptridx, align 4 + %20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.7, i32 0, i32 0), i32 %19) + %21 = load i32*, i32** @subarrays.fofeo, align 8 + %ptridx6 = getelementptr inbounds i32, i32* %21, i64 1 + %22 = load i32, i32* %ptridx6, align 4 + %23 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.8, i32 0, i32 0), i32 %22) + %24 = bitcast %Baz* %ffe to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %24, i8* align 8 bitcast ({ i32, [4 x i8] }* @.__const to i8*), i32 8, i1 false) + %25 = bitcast [1 x i32]* %azz to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %25, i8 0, i64 4, i1 false) + %26 = bitcast [0 x i32]* %a to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %26, i8 0, i64 0, i1 false) + %27 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 0 + store i32 1, i32* %27, align 4 + %28 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 1 + store i32 2, i32* %28, align 4 + %29 = getelementptr inbounds i32, [3 x i32]* %literal7, i32 2 + store i32 3, i32* %29, align 4 + %30 = bitcast [3 x i32]* %literal7 to i32* + %31 = insertvalue %"int[]" undef, i32* %30, 0 + %32 = insertvalue %"int[]" %31, i64 3, 1 + %33 = extractvalue %"int[]" %32, 1 + %neq = icmp ne i64 %33, 0 + %not = xor i1 %neq, true + %34 = zext i1 %not to i8 + store i8 %34, i8* %xy, align 1 + %35 = load i8, i8* %xy, align 1 + %36 = trunc i8 %35 to i1 + %not8 = xor i1 %36, true + br i1 %not8, label %if.then, label %if.exit + +if.then: ; preds = %entry + %37 = call i32 @"std::io.println"(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0)) #3 + br label %if.exit + +if.exit: ; preds = %if.then, %entry + %38 = bitcast %Bar* %b to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %38, i8 0, i64 8, i1 false) + %39 = bitcast %Baz* %z to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %39, i8 0, i64 8, i1 false) + store [0 x i32] zeroinitializer, [0 x i32]* %literal9, align 4 + %40 = bitcast [0 x i32]* %literal9 to i32* + %41 = insertvalue %"int[]" undef, i32* %40, 0 + %42 = insertvalue %"int[]" %41, i64 0, 1 + store %"int[]" %42, %"int[]"* %sub, align 8 + store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal10, align 4 + %43 = bitcast [0 x %Bar]* %literal10 to %Bar* + %44 = insertvalue %"Bar[]" undef, %Bar* %43, 0 + %45 = insertvalue %"Bar[]" %44, i64 0, 1 + store %"Bar[]" %45, %"Bar[]"* %foo, align 8 + %46 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %46, i8 0, i64 24, i1 false) + ret i32 1 +} \ No newline at end of file diff --git a/test/test_suite/initializer_lists/zero_init.c3t b/test/test_suite/initializer_lists/zero_init.c3t index 0d9747bb3..610f5fb5d 100644 --- a/test/test_suite/initializer_lists/zero_init.c3t +++ b/test/test_suite/initializer_lists/zero_init.c3t @@ -24,6 +24,15 @@ func int test() // #expect: zero_init.ll +%Bar = type { i32, i32 } +%Baz = type { double } +%"int[]" = type { i32*, i64 } +%"Bar[]" = type { %Bar*, i64 } + +@Baz = linkonce_odr constant i8 1 +@Bar = linkonce_odr constant i8 1 + +; Function Attrs: nounwind define i32 @zero_init.test() #0 { entry: %azz = alloca [1 x i32], align 4 @@ -31,7 +40,9 @@ entry: %b = alloca %Bar, align 4 %z = alloca %Baz, align 8 %sub = alloca %"int[]", align 8 + %literal = alloca [0 x i32], align 4 %foo = alloca %"Bar[]", align 8 + %literal1 = alloca [0 x %Bar], align 4 %baz = alloca [3 x %Baz], align 16 %0 = bitcast [1 x i32]* %azz to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) @@ -41,11 +52,17 @@ entry: call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 8, i1 false) %3 = bitcast %Baz* %z to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false) - %4 = bitcast %"int[]"* %sub to i8* - call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 16, i1 false) - %5 = bitcast %"Bar[]"* %foo to i8* - call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 16, i1 false) - %6 = bitcast [3 x %Baz]* %baz to i8* - call void @llvm.memset.p0i8.i64(i8* align 16 %6, i8 0, i64 24, i1 false) + store [0 x i32] zeroinitializer, [0 x i32]* %literal, align 4 + %4 = bitcast [0 x i32]* %literal to i32* + %5 = insertvalue %"int[]" undef, i32* %4, 0 + %6 = insertvalue %"int[]" %5, i64 0, 1 + store %"int[]" %6, %"int[]"* %sub, align 8 + store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal1, align 4 + %7 = bitcast [0 x %Bar]* %literal1 to %Bar* + %8 = insertvalue %"Bar[]" undef, %Bar* %7, 0 + %9 = insertvalue %"Bar[]" %8, i64 0, 1 + store %"Bar[]" %9, %"Bar[]"* %foo, align 8 + %10 = bitcast [3 x %Baz]* %baz to i8* + call void @llvm.memset.p0i8.i64(i8* align 16 %10, i8 0, i64 24, i1 false) ret i32 1 -} \ No newline at end of file +} diff --git a/test/test_suite/struct/struct_as_value.c3t b/test/test_suite/struct/struct_as_value.c3t index 643138407..c2b1acf55 100644 --- a/test/test_suite/struct/struct_as_value.c3t +++ b/test/test_suite/struct/struct_as_value.c3t @@ -15,10 +15,17 @@ func Event test(int x) // #expect: test.ll + @Event = linkonce_odr constant i8 1 + @.__const = private constant %Event { i32 1 }, align 4 + @.__const.1 = private constant %Event { i32 2 }, align 4 + + ; Function Attrs: nounwind + define i32 @test.test(i32 %0) #0 { + entry: %x = alloca i32, align 4 %foo = alloca %Event, align 4 %bar = alloca %Event, align 4 - %tempaddr = alloca %Event, align 4 + %taddr = alloca %Event, align 4 store i32 %0, i32* %x, align 4 %1 = bitcast %Event* %foo to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 bitcast (%Event* @.__const to i8*), i32 4, i1 false) @@ -28,17 +35,18 @@ func Event test(int x) %intbool = icmp ne i32 %3, 0 br i1 %intbool, label %cond.lhs, label %cond.rhs - cond.lhs: + cond.lhs: ; preds = %entry %4 = load %Event, %Event* %foo, align 4 br label %cond.phi - cond.rhs: + cond.rhs: ; preds = %entry %5 = load %Event, %Event* %bar, align 4 br label %cond.phi - cond.phi: + cond.phi: ; preds = %cond.rhs, %cond.lhs %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] - store %Event %val, %Event* %tempaddr, align 4 - %dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0 + store %Event %val, %Event* %taddr, align 4 + %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 %6 = load i32, i32* %dive, align 4 - ret i32 %6 \ No newline at end of file + ret i32 %6 + } \ No newline at end of file diff --git a/test/test_suite/struct/struct_as_value_aarch64.c3t b/test/test_suite/struct/struct_as_value_aarch64.c3t index bccfd2542..39211b0e7 100644 --- a/test/test_suite/struct/struct_as_value_aarch64.c3t +++ b/test/test_suite/struct/struct_as_value_aarch64.c3t @@ -18,7 +18,7 @@ func Event test(int x) %x = alloca i32, align 4 %foo = alloca %Event, align 4 %bar = alloca %Event, align 4 - %tempaddr = alloca %Event, align 4 + %taddr = alloca %Event, align 4 store i32 %0, i32* %x, align 4 %1 = bitcast %Event* %foo to i8* call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 bitcast (%Event* @.__const to i8*), i32 4, i1 false) @@ -38,8 +38,8 @@ cond.rhs: cond.phi: %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] - store %Event %val, %Event* %tempaddr, align 4 - %dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0 + store %Event %val, %Event* %taddr, align 4 + %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0 %6 = load i32, i32* %dive, align 4 %7 = zext i32 %6 to i64 ret i64 %7 \ No newline at end of file diff --git a/test/test_suite/union/union_in_struct.c3t b/test/test_suite/union/union_in_struct.c3t index 72a8003d5..2b8cbca66 100644 --- a/test/test_suite/union/union_in_struct.c3t +++ b/test/test_suite/union/union_in_struct.c3t @@ -1,5 +1,19 @@ +// #target: x64-darwin module test; +struct Foo +{ + char c; + union { + int a; + double b; + } + int z; +} + +Foo foo1 = { .a = 3, .z = 4 }; +Foo foo2 = { .b = 3, .z = 4 }; + struct Blend_Map_Entry { union vals { @@ -23,6 +37,8 @@ func void test(Blend_Map_Entry* foo) %Blend_Map_Entry = type { %vals } %vals = type { [2 x double], [8 x i8] } +@test.foo1 = global { i8, [4 x i8], { i32, [4 x i8] }, i32 } { i8 0, [4 x i8] undef, { i32, [4 x i8] } { i32 3, [4 x i8] undef }, i32 4 }, align 8 +@test.foo2 = global %Foo { i8 0, %anon { double 3.000000e+00 }, i32 4 }, align 8 @test.a = global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8 @test.b = global %Blend_Map_Entry { %vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8 @test.c = global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8