Fix of shadowing bug. Allow pointer and subarrays to be constant initialized. Compile time values may now pass around anything considered compile time constant. It's possible to index into an initializer list at compile time. (Some work still remains on this)

This commit is contained in:
Christoffer Lerno
2021-09-14 11:14:51 +02:00
committed by Christoffer Lerno
parent 1b103a3e22
commit e4c7dde30b
30 changed files with 1209 additions and 343 deletions

View File

@@ -25,6 +25,11 @@ struct Allocator
void *data; 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 func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline
{ {
switch (kind) switch (kind)
@@ -47,6 +52,37 @@ func void! system_malloc_function(void *unused, void** pointer, usize bytes, usi
$unreachable; $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 struct RingAllocator
{ {
char *data; char *data;
@@ -131,4 +167,24 @@ func void* realloc(void *ptr, usize size) @inline
func void free(void* ptr) @inline func void free(void* ptr) @inline
{ {
_free(ptr); _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);
} }

View File

@@ -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());
}

View File

@@ -247,7 +247,6 @@ static void setup_int_define(const char *id, uint64_t i)
TokenType token_type = TOKEN_CONST_IDENT; TokenType token_type = TOKEN_CONST_IDENT;
id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type); id = symtab_add(id, strlen(id), fnv1a(id, strlen(id)), &token_type);
Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE); Expr *expr = expr_new(EXPR_CONST, INVALID_RANGE);
expr->constant = true;
expr_const_set_int(&expr->const_expr, i, TYPE_IXX); expr_const_set_int(&expr->const_expr, i, TYPE_IXX);
expr->original_type = expr->type = type_compint; expr->original_type = expr->type = type_compint;
expr->span = INVALID_RANGE; 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 *expr = expr_new(EXPR_CONST, INVALID_RANGE);
expr_const_set_bool(&expr->const_expr, value); expr_const_set_bool(&expr->const_expr, value);
expr->original_type = expr->type = type_bool; expr->original_type = expr->type = type_bool;
expr->constant = true;
expr->span = INVALID_RANGE; expr->span = INVALID_RANGE;
expr->resolve_status = RESOLVE_NOT_DONE; expr->resolve_status = RESOLVE_NOT_DONE;
void *previous = stable_set(&global_context.compiler_defines, id, expr); void *previous = stable_set(&global_context.compiler_defines, id, expr);

View File

@@ -653,8 +653,6 @@ typedef struct
Expr *left; Expr *left;
Expr *right; Expr *right;
BinaryOp operator; BinaryOp operator;
bool left_maybe : 1;
bool right_maybe : 1;
} ExprBinary; } ExprBinary;
typedef struct typedef struct
@@ -923,7 +921,6 @@ struct Expr_
ResolveStatus resolve_status : 3; ResolveStatus resolve_status : 3;
bool failable : 1; bool failable : 1;
bool pure : 1; bool pure : 1;
bool constant : 1;
SourceSpan span; SourceSpan span;
Type *type; Type *type;
Type *original_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_int_overflowed(const ExprConst *expr);
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op); bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind); 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_addr(Expr *original);
void expr_insert_deref(Expr *expr); void expr_insert_deref(Expr *expr);
Expr *expr_variable(Decl *decl); 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); const char *expr_const_to_error_string(const ExprConst *expr);
static inline bool expr_is_init_list(Expr *expr) static inline bool expr_is_init_list(Expr *expr)
{ {

View File

@@ -74,7 +74,6 @@ Expr *copy_expr(Expr *source_expr)
case EXPR_FLATPATH: case EXPR_FLATPATH:
case EXPR_UNDEF: case EXPR_UNDEF:
case EXPR_NOP: case EXPR_NOP:
case EXPR_BYTES:
return expr; return expr;
case EXPR_DECL: case EXPR_DECL:
MACRO_COPY_DECL(expr->decl_expr); MACRO_COPY_DECL(expr->decl_expr);

View File

@@ -179,7 +179,6 @@ typedef enum
EXPR_POISONED, EXPR_POISONED,
EXPR_ACCESS, EXPR_ACCESS,
EXPR_BINARY, EXPR_BINARY,
EXPR_BYTES,
EXPR_MACRO_BODY_EXPANSION, EXPR_MACRO_BODY_EXPANSION,
EXPR_CALL, EXPR_CALL,
EXPR_CAST, EXPR_CAST,

View File

@@ -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 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; 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), return LLVMBuildMemSet(c->builder, target, LLVMConstInt(llvm_get_type(c, type_char), 0, false),
LLVMConstInt(llvm_get_type(c, type_ulong), size, false), align); 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); 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) switch (const_init->kind)
{ {
@@ -93,18 +94,16 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
Type *element_type = array_type->array.base; Type *element_type = array_type->array.base;
LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type);
ConstInitializer **elements = const_init->init_array_full; ConstInitializer **elements = const_init->init_array_full;
assert(array_type->type_kind == TYPE_ARRAY);
ArrayIndex size = array_type->array.len; ArrayIndex size = array_type->array.len;
if (array_type->type_kind == TYPE_SUBARRAY)
{
size = vec_size(elements);
}
assert(size > 0); assert(size > 0);
LLVMValueRef *parts = VECNEW(LLVMValueRef, size); LLVMValueRef *parts = VECNEW(LLVMValueRef, size);
for (ArrayIndex i = 0; i < size; i++) 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) if (was_modified)
{ {
return LLVMConstStructInContext(c->context, parts, vec_size(parts), true); 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 *array_type = const_init->type;
Type *element_type = array_type->array.base; Type *element_type = array_type->array.base;
LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type); 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; ConstInitializer **elements = const_init->init_array.elements;
unsigned element_count = vec_size(elements); unsigned element_count = vec_size(elements);
assert(element_count > 0 && "Array should always have gotten at least one element."); 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); assert(element->kind == CONST_INIT_ARRAY_VALUE);
ArrayIndex element_index = element->init_array_value.index; ArrayIndex element_index = element->init_array_value.index;
IndexDiff diff = element_index - current_index; IndexDiff diff = element_index - current_index;
unsigned curr_alignment = type_abi_alignment(element->type); if (alignment && expected_align != alignment)
if (alignment && curr_alignment != alignment)
{ {
pack = true; pack = true;
} }
alignment = curr_alignment; alignment = expected_align;
// Add zeroes // Add zeroes
if (diff > 0) if (diff > 0)
{ {
vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, diff, &was_modified)); 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; 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)); vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, end_diff, &was_modified));
} }
if (was_modified) *modified = was_modified;
if (was_modified) if (was_modified)
{ {
return LLVMConstStructInContext(c->context, parts, vec_size(parts), pack); 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: case CONST_INIT_UNION:
{ {
Decl *decl = const_init->type->decl; 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. // 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 // Get the union value
LLVMTypeRef union_type_llvm = llvm_get_type(c, decl->type); 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. // We need to calculate some possible padding.
ByteSize union_size = type_size(const_init->type); 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; ByteSize padding = union_size - member_size;
// Create the resulting values: // 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? // 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. // 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); 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; Decl **members = decl->strukt.members;
MemberIndex count = vec_size(members); MemberIndex count = vec_size(members);
LLVMValueRef *entries = NULL; LLVMValueRef *entries = NULL;
bool was_modified = false;
for (MemberIndex i = 0; i < count; i++) for (MemberIndex i = 0; i < count; i++)
{ {
if (members[i]->padding) if (members[i]->padding)
{ {
vec_add(entries, llvm_emit_const_padding(c, 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) if (decl->strukt.padding)
{ {
vec_add(entries, llvm_emit_const_padding(c, 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)); 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; BEValue value;
llvm_emit_expr(c, &value, const_init->init_value); llvm_emit_expr(c, &value, const_init->init_value);
LLVMValueRef llvm_value = llvm_value_rvalue_store(c, &value); return 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;
} }
} }
UNREACHABLE 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) 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. // Skip real constants.
if (!decl->type) return; if (!decl->type) return;
bool modified = false;
LLVMValueRef init_value; LLVMValueRef init_value;
ByteSize alignment = type_alloca_alignment(decl->type); 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) if (init_expr->expr_kind == EXPR_CONST && init_expr->const_expr.const_kind == CONST_LIST)
{ {
ConstInitializer *list = init_expr->const_expr.list; ConstInitializer *list = init_expr->const_expr.list;
init_value = llvm_emit_const_initializer(c, list, &modified); init_value = llvm_emit_const_initializer(c, list);
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);
}
} }
else else
{ {
@@ -459,7 +390,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
break; 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)); 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) LLVMValueRef llvm_emit_alloca(GenContext *c, LLVMTypeRef type, unsigned alignment, const char *name)
{ {
assert(c->builder);
assert(alignment > 0); assert(alignment > 0);
LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder);
LLVMPositionBuilderBefore(c->builder, c->alloca_point); LLVMPositionBuilderBefore(c->builder, c->alloca_point);
@@ -925,9 +857,23 @@ void llvm_value_addr(GenContext *c, BEValue *value)
{ {
llvm_value_fold_failable(c, value); llvm_value_fold_failable(c, value);
if (value->kind == BE_ADDRESS) return; if (value->kind == BE_ADDRESS) return;
LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "tempaddr"); if (!c->builder)
llvm_store_self_aligned(c, temp, value->value, value->type); {
llvm_value_set_address(value, temp, value->type); 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) 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) 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); LLVMValueRef value = LLVMBuildLoad2(c->builder, type, pointer, name);
assert(LLVMGetTypeContext(type) == c->context); assert(LLVMGetTypeContext(type) == c->context);
llvm_set_alignment(value, alignment ? alignment : llvm_abi_alignment(c, type)); llvm_set_alignment(value, alignment ? alignment : llvm_abi_alignment(c, type));

View File

@@ -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"); 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) LLVMTypeRef llvm_const_padding_type(GenContext *c, ByteSize size)
{ {
assert(size > 0); 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; ByteSize size = value->type->pointer->array.len;
Type *array_type = value->type->pointer->array.base; Type *array_type = value->type->pointer->array.base;
LLVMTypeRef subarray_type = llvm_get_type(c, to_type); 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 pointer = llvm_emit_bitcast(c, value->value, type_get_ptr(array_type));
LLVMValueRef len = llvm_const_int(c, type_usize, size); LLVMValueRef len = llvm_const_int(c, type_usize, size);
value->type = to_type; value->type = to_type;
if (!c->builder) value->value = llvm_emit_aggregate_value(c, to_type, pointer, len, NULL);
{
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, "");
}
} }
@@ -571,7 +594,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
} }
else else
{ {
value->value = LLVMConstBitCast(value->value, llvm_get_type(c, to_type)); value->value = LLVMConstPtrToInt(value->value, llvm_get_type(c, to_type));
} }
break; break;
case CAST_APTSA: case CAST_APTSA:
@@ -665,6 +688,12 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
break; break;
case CAST_XIPTR: case CAST_XIPTR:
llvm_value_rvalue(c, value); 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"); value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr");
break; break;
case CAST_UISI: case CAST_UISI:
@@ -790,10 +819,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref,
Type *canonical = expr->type->canonical; Type *canonical = expr->type->canonical;
assert(expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST); 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. // 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"); LLVMValueRef global_copy = LLVMAddGlobal(c->module, type, ".__const");
LLVMSetLinkage(global_copy, LLVMPrivateLinkage); LLVMSetLinkage(global_copy, LLVMPrivateLinkage);
@@ -808,6 +838,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref,
// Ensure we have a reference. // Ensure we have a reference.
llvm_value_addr(c, ref); llvm_value_addr(c, ref);
if (expected_type != type)
{
global_copy = LLVMConstBitCast(global_copy, LLVMPointerType(expected_type, 0));
}
// Perform the memcpy. // Perform the memcpy.
llvm_emit_memcpy(c, ref->value, ref->alignment, global_copy, alignment, type_size(expr->type)); 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) VECEACH(elements, i)
{ {
Expr *element = elements[i]; Expr *element = elements[i];
if (element->expr_kind == EXPR_COMPOUND_LITERAL)
{
element = element->expr_compound_literal.initializer;
}
unsigned offset = 0; unsigned offset = 0;
BEValue pointer; BEValue pointer;
if (is_struct) 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); 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) static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
Type *type = type_reduced_from_expr(expr->unary_expr.expr); Type *type = type_reduced_from_expr(expr->unary_expr.expr);
Expr *inner = expr->unary_expr.expr;
LLVMValueRef llvm_value; LLVMValueRef llvm_value;
switch (expr->unary_expr.operator) switch (expr->unary_expr.operator)
{ {
case UNARYOP_ERROR: case UNARYOP_ERROR:
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator); 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: case UNARYOP_NOT:
llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value); llvm_value_rvalue(c, value);
if (type_is_float(type)) 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); llvm_value_set_bool(value, llvm_value);
return; return;
case UNARYOP_BITNEG: case UNARYOP_BITNEG:
llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value); llvm_value_rvalue(c, value);
value->value = LLVMBuildNot(c->builder, value->value, "bnot"); value->value = LLVMBuildNot(c->builder, value->value, "bnot");
return; return;
case UNARYOP_NEG: case UNARYOP_NEG:
llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value); llvm_value_rvalue(c, value);
if (type_is_float(type)) 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"); value->value = LLVMBuildNeg(c->builder, value->value, "neg");
return; return;
case UNARYOP_TADDR:
case UNARYOP_ADDR: case UNARYOP_ADDR:
llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_emit_expr(c, value, inner);
// Create an addr // Create an addr
llvm_value_addr(c, value); llvm_value_addr(c, value);
// Transform to 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); value->type = type_lowering(expr->type);
return; return;
case UNARYOP_DEREF: case UNARYOP_DEREF:
llvm_emit_expr(c, value, expr->unary_expr.expr); llvm_emit_expr(c, value, inner);
// Load the pointer value. // Load the pointer value.
llvm_value_rvalue(c, value); llvm_value_rvalue(c, value);
// Convert pointer to address // 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); value->type = type_lowering(expr->type);
return; return;
case UNARYOP_INC: 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; return;
case UNARYOP_DEC: 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; return;
} }
UNREACHABLE UNREACHABLE
@@ -1522,7 +1550,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV
*parent_type_ref = parent_type; *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 *parent_type;
Type *end_type; Type *end_type;
@@ -1531,13 +1559,13 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
Type *start_type; Type *start_type;
LLVMValueRef start_index; LLVMValueRef start_index;
// Use general function to get all the values we need (a lot!) // 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, &parent_base,
&start_type, &start_index, &end_type, &end_index); &start_type, &start_index, &end_type, &end_index);
// Calculate the size // 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; LLVMValueRef start_pointer;
switch (parent_type->type_kind) 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); Type *pointer_type = type_get_ptr(parent_type->array.base);
// Change pointer from Foo[x] to Foo* // 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 // 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; break;
} }
case TYPE_SUBARRAY: 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; break;
} }
case TYPE_POINTER: case TYPE_POINTER:
{ {
// Move 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; break;
} }
default: default:
@@ -1566,9 +1594,7 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
} }
// Create a new subarray type // Create a new subarray type
LLVMValueRef result = LLVMGetUndef(llvm_get_type(context, expr->type)); llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr->type, start_pointer, size, NULL), expr->type);
result = LLVMBuildInsertValue(context->builder, result, start_pointer, 0, "");
llvm_value_set(be_value, LLVMBuildInsertValue(context->builder, result, size, 1, ""), expr->type);
} }
static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr) 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: case BINARYOP_SUB:
if (lhs_type->type_kind == TYPE_POINTER) if (lhs_type->type_kind == TYPE_POINTER)
{ {
bool is_constant = LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value);
if (lhs_type == rhs_type) if (lhs_type == rhs_type)
{ {
LLVMTypeRef int_type = llvm_get_type(c, type_iptrdiff); 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)), ""); val = LLVMBuildExactSDiv(c->builder, val, llvm_const_int(c, type_iptrdiff, type_abi_alignment(lhs_type->pointer)), "");
break; break;
} }
rhs_value = LLVMBuildNeg(c->builder, rhs_value, ""); if (is_constant)
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub"); {
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; break;
} }
if (is_float) 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) if (lhs_type->type_kind == TYPE_POINTER)
{ {
assert(type_is_integer(rhs_type)); 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; break;
} }
if (is_float) 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) 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_value_set_address(value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type);
llvm_emit_initialize_reference_const(c, value, expr); 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; 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) if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST)
{ {
llvm_emit_const_initialize_reference(c, ref, expr); 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); llvm_emit_try_assign_expr(c, value, expr);
return; return;
case EXPR_NOP: case EXPR_NOP:
case EXPR_BYTES:
return; return;
case EXPR_ELSE: case EXPR_ELSE:
gencontext_emit_else_expr(c, value, expr); gencontext_emit_else_expr(c, value, expr);

View File

@@ -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_debug_global_var(GenContext *c, Decl *global);
void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end); void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end);
void llvm_emit_extern_decl(GenContext *context, Decl *decl); 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_expr(GenContext *c, BEValue *value, Expr *expr);
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type); void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type);
void llvm_emit_global_variable_init(GenContext *c, Decl *decl); 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); 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); void llvm_emit_local_var_alloca(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_local_decl(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_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned align, bool bitcast);
LLVMValueRef llvm_emit_memclear(GenContext *c, BEValue *ref); 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); 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) static inline LLVMValueRef llvm_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type)
{ {
assert(type->type_kind == TYPE_POINTER); 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; } static inline bool llvm_use_debug(GenContext *context) { return context->debug.builder != NULL; }

View File

@@ -54,6 +54,8 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
// then we essentially treat this as a global. // then we essentially treat this as a global.
if (decl->var.is_static) 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"); decl->backend_ref = LLVMAddGlobal(c->module, llvm_get_type(c, decl->type), "tempglobal");
if (decl->var.failable) 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()); decl->var.failable_ref = LLVMAddGlobal(c->module, llvm_get_type(c, type_anyerr), scratch_buffer_to_string());
} }
llvm_emit_global_variable_init(c, decl); llvm_emit_global_variable_init(c, decl);
c->builder = builder;
return decl->backend_ref; return decl->backend_ref;
} }
llvm_emit_local_var_alloca(c, decl); llvm_emit_local_var_alloca(c, decl);

View File

@@ -277,5 +277,20 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind)
expr->float_type = 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
}
}

View File

@@ -667,7 +667,6 @@ static Expr *parse_subscript_expr(Context *context, Expr *left)
{ {
index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok); index = EXPR_NEW_TOKEN(EXPR_CONST, context->tok);
expr_set_type(index, type_uint); expr_set_type(index, type_uint);
index->constant = true;
index->resolve_status = RESOLVE_DONE; index->resolve_status = RESOLVE_DONE;
expr_const_set_int(&index->const_expr, 0, type_uint->type_kind); expr_const_set_int(&index->const_expr, 0, type_uint->type_kind);
} }

View File

@@ -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) bool may_convert_float_const_implicit(Expr *expr, Type *to_type)
{ {
Type *to_type_flat = type_flatten(to_type); Type *to_type_flat = type_flatten(to_type);
Real limit; Real hi_limit;
Real lo_limit;
switch (to_type_flat->type_kind) switch (to_type_flat->type_kind)
{ {
case TYPE_F16: case TYPE_F16:
limit = FLOAT16_LIMIT; lo_limit = hi_limit = FLOAT16_LIMIT;
break; break;
case TYPE_F32: case TYPE_F32:
limit = FLOAT32_LIMIT; lo_limit = hi_limit = FLOAT32_LIMIT;
break; break;
case TYPE_F64: case TYPE_F64:
limit = FLOAT64_LIMIT; lo_limit = hi_limit = FLOAT64_LIMIT;
break; break;
case TYPE_F128: case TYPE_F128:
// Assume this to be true // Assume this to be true
return true; return true;
case TYPE_BOOL:
return true;
default: default:
UNREACHABLE 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 #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)); 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));

View File

@@ -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; if (!sema_analyse_expr_of_required_type(context, decl->type, init_expr, false)) return false;
// 2. Check const-ness // 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 SEMA_ERROR(init_expr, "The expression must be a constant value.");
// 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;
}
} }
else else
{ {

View File

@@ -84,7 +84,6 @@ void expr_copy_properties(Expr *to, Expr *from)
{ {
to->failable = from->failable; to->failable = from->failable;
to->pure = from->pure; to->pure = from->pure;
to->constant = from->constant;
} }
void expr_copy_types(Expr *to, Expr *from) 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)); expr_set_type(original, type_get_ptr(inner->type));
original->unary_expr.operator = UNARYOP_ADDR; original->unary_expr.operator = UNARYOP_ADDR;
original->unary_expr.expr = inner; original->unary_expr.expr = inner;
original->pure = false;
original->constant = false;
original->failable = inner->failable;
} }
Expr *expr_variable(Decl *decl) Expr *expr_variable(Decl *decl)
@@ -117,12 +113,251 @@ Expr *expr_variable(Decl *decl)
Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span); Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span);
expr->identifier_expr.decl = decl; expr->identifier_expr.decl = decl;
expr->pure = true; expr->pure = true;
expr->constant = false;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
expr_set_type(expr, decl->type); expr_set_type(expr, decl->type);
return expr; 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) void expr_insert_deref(Expr *original)
{ {
assert(original->resolve_status == RESOLVE_DONE); 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.operator = UNARYOP_DEREF;
original->unary_expr.expr = inner; original->unary_expr.expr = inner;
original->pure = false; original->pure = false;
original->constant = false;
original->failable = inner->failable; 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) static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right)
{ {
expr->pure = left->pure & right->pure; expr->pure = left->pure & right->pure;
expr->constant = left->constant & right->constant;
expr->failable = left->failable | right->failable; 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) switch (decl->var.kind)
{ {
case VARDECL_CONST: 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)); expr_replace(expr, copy_expr(decl->var.init_expr));
return sema_analyse_expr(context, to, expr); return sema_analyse_expr(context, to, expr);
case VARDECL_PARAM_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 *left = expr->ternary_expr.then_expr;
Expr *cond = expr->ternary_expr.cond; Expr *cond = expr->ternary_expr.cond;
int path = -1;
// Normal // Normal
if (left) 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 (!cast_implicit(cond, type_bool)) return expr_poison(expr);
if (!sema_analyse_expr(context, to, left)) return expr_poison(expr); if (!sema_analyse_expr(context, to, left)) return expr_poison(expr);
expr->failable = left->failable | cond->failable; expr->failable = left->failable | cond->failable;
if (cond->expr_kind == EXPR_CONST)
{
path = cond->const_expr.b ? 1 : 0;
}
} }
else 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."); SEMA_ERROR(cond, "Cannot convert expression to boolean.");
return false; 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; 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); if (!sema_analyse_expr(context, to, right)) return expr_poison(expr);
expr->pure = cond->pure & left->pure & right->pure; expr->pure = cond->pure & left->pure & right->pure;
expr->constant = cond->constant & left->constant & right->pure;
expr->failable |= right->failable; expr->failable |= right->failable;
Type *left_canonical = left->type->canonical; 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; 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; 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); assert(enum_constant->resolve_status == RESOLVE_DONE);
expr_set_type(expr, decl->type); expr_set_type(expr, decl->type);
expr->expr_kind = EXPR_CONST; expr->expr_kind = EXPR_CONST;
expr->constant = true;
expr->pure = true; expr->pure = true;
if (enum_constant->decl_kind == DECL_ENUM_CONSTANT) 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) 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); Expr *copy = copy_expr(decl->var.init_expr);
if (!sema_analyse_expr(context, to, copy)) return false; 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."); SEMA_ERROR(expr, "Constant value did not evaluate to a constant.");
return false; return false;
@@ -627,7 +846,6 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
expr->identifier_expr.decl = decl; expr->identifier_expr.decl = decl;
expr_set_type(expr, decl->type); expr_set_type(expr, decl->type);
expr->pure = true; expr->pure = true;
expr->constant = false;
DEBUG_LOG("Resolution successful of %s.", decl->name); DEBUG_LOG("Resolution successful of %s.", decl->name);
return true; 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->ct_ident_expr.decl = decl;
expr_set_type(expr, decl->type); expr_set_type(expr, decl->type);
expr->pure = true; expr->pure = true;
expr->constant = true;
return true; return true;
} }
@@ -1156,7 +1373,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal
// $foo // $foo
assert(callee.macro); assert(callee.macro);
if (!sema_analyse_expr_of_required_type(context, param->type, arg, false)) return false; 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?"); SEMA_ERROR(arg, "A compile time parameter must always be a constant, did you mistake it for a normal paramter?");
return false; return false;
@@ -1338,7 +1555,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast)
return true; return true;
case AST_RETURN_STMT: case AST_RETURN_STMT:
if (!ast->return_stmt.expr) return true; 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: case AST_EXPR_STMT:
return sema_check_expr_compile_time(context, ast->expr_stmt); return sema_check_expr_compile_time(context, ast->expr_stmt);
case AST_CT_COMPOUND_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) if (vec_size(context->returns) == 1)
{ {
Expr *result = context->returns[0]->return_stmt.expr; 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)) 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) static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr)
{ {
expr->constant = false;
expr->pure = false; expr->pure = false;
Expr *func_expr = expr->call_expr.function; 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) 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; expr->failable = expr->subscript_expr.expr->failable;
assert(expr->expr_kind == EXPR_SUBSCRIPT); assert(expr->expr_kind == EXPR_SUBSCRIPT);
Expr *subscripted = expr->subscript_expr.expr;
Type *type = type_flatten(subscripted->type); Type *type = type_flatten(subscripted->type);
Expr *index = expr->subscript_expr.index;
Type *current_type = type; Type *current_type = type;
Expr *current_expr = subscripted; 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(&current_type, &current_expr); Type *inner_type = sema_expr_find_indexable_type_recursively(&current_type, &current_expr);
if (!inner_type) if (!inner_type)
{ {
SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(type)); SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(type));
return false; return false;
} }
if (!sema_analyse_expr(context, NULL, index)) return false;
expr->constant = index->constant & subscripted->constant;
expr->pure = index->pure & subscripted->pure; expr->pure = index->pure & subscripted->pure;
// Cast to an appropriate type for index. // 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); assert(expr->expr_kind == EXPR_SLICE);
Expr *subscripted = expr->slice_expr.expr; Expr *subscripted = expr->slice_expr.expr;
expr->pure = subscripted->pure; expr->pure = subscripted->pure;
expr->constant = subscripted->constant;
Type *type = type_flatten(subscripted->type); Type *type = type_flatten(subscripted->type);
Expr *start = expr->slice_expr.start; Expr *start = expr->slice_expr.start;
Expr *end = expr->slice_expr.end; 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; if (!sema_analyse_expr(context, type_int, start)) return false;
expr->pure &= start->pure; expr->pure &= start->pure;
expr->constant &= start->constant;
if (end && !sema_analyse_expr(context, type_int, end)) return false; if (end && !sema_analyse_expr(context, type_int, end)) return false;
expr->pure &= !end || end->pure; expr->pure &= !end || end->pure;
expr->constant &= !end || end->constant;
// Fix index sizes // Fix index sizes
if (!expr_cast_to_index(start)) return false; 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_to_rewrite->expr_kind = EXPR_CONST;
expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind); expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind);
expr_set_type(expr_to_rewrite, type); expr_set_type(expr_to_rewrite, type);
expr_to_rewrite->constant = true;
expr_to_rewrite->pure = true; expr_to_rewrite->pure = true;
expr_to_rewrite->resolve_status = RESOLVE_DONE; 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) static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string)
{ {
expr_to_rewrite->expr_kind = EXPR_CONST; 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.const_kind = CONST_STRING;
expr_to_rewrite->const_expr.string.chars = (char *)string; expr_to_rewrite->const_expr.string.chars = (char *)string;
expr_to_rewrite->const_expr.string.len = (int)strlen(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) static bool sema_expr_analyse_typeinfo(Context *context, Expr *expr)
{ {
expr->constant = true;
expr->pure = true; expr->pure = true;
TypeInfo *type_info = expr->type_expr; 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; return false;
} }
expr->constant = true;
expr->pure = true; expr->pure = true;
TokenType type = TOKTYPE(identifier_token); 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(""); expr->const_expr.f = nan("");
#endif #endif
expr_set_type(expr, parent->type); expr_set_type(expr, parent->type);
expr->constant = true;
expr->pure = true; expr->pure = true;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; 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.const_kind = CONST_FLOAT;
expr->const_expr.f = INFINITY; expr->const_expr.f = INFINITY;
expr_set_type(expr, parent->type->canonical); expr_set_type(expr, parent->type->canonical);
expr->constant = true;
expr->pure = true; expr->pure = true;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
return true; 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->type = member->type;
expr->type_expr->resolve_status = RESOLVE_DONE; expr->type_expr->resolve_status = RESOLVE_DONE;
expr_set_type(expr, type_typeinfo); expr_set_type(expr, type_typeinfo);
expr->constant = expr->pure = true; expr->pure = true;
return true; return true;
} }
@@ -2460,7 +2702,6 @@ CHECK_DEEPER:
// 13. Copy properties. // 13. Copy properties.
expr->access_expr.parent = current_parent; expr->access_expr.parent = current_parent;
expr->constant = expr->access_expr.parent->constant;
expr->pure = expr->access_expr.parent->pure; expr->pure = expr->access_expr.parent->pure;
expr_set_type(expr, member->type); expr_set_type(expr, member->type);
expr->access_expr.ref = member; expr->access_expr.ref = member;
@@ -2621,7 +2862,6 @@ static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr
} }
current = new_current; current = new_current;
} }
expr->constant = is_constant;
expr->pure = is_constant; expr->pure = is_constant;
return current; 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); bool is_structlike = type_is_structlike(assigned->canonical);
initializer->pure = true; initializer->pure = true;
initializer->constant = true;
ArrayIndex max_index = -1; ArrayIndex max_index = -1;
VECEACH(init_expressions, i) VECEACH(init_expressions, i)
{ {
@@ -2935,18 +3174,17 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
if (!result) return false; if (!result) return false;
if (!sema_analyse_expr_of_required_type(context, result, expr->designator_expr.value, true)) 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->pure &= expr->designator_expr.value->pure;
expr->constant &= expr->designator_expr.value->constant;
expr->failable |= expr->designator_expr.value->failable; expr->failable |= expr->designator_expr.value->failable;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
initializer->pure &= expr->pure; initializer->pure &= expr->pure;
initializer->constant &= expr->constant;
} }
if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY) if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY)
{ {
initializer->type = sema_type_lower_by_size(initializer->type, max_index + 1); 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)); ConstInitializer *const_init = MALLOC(sizeof(ConstInitializer));
sema_create_const_initializer(const_init, initializer); 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) static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
{ {
initializer->pure = true; initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list; Expr **elements = initializer->initializer_list;
Decl **members = assigned->strukt.members; 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. // 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; if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i], 0)) return false;
initializer->pure &= element->pure; initializer->pure &= element->pure;
initializer->constant &= element->constant;
initializer->failable |= element->failable; initializer->failable |= element->failable;
} }
@@ -3011,7 +3247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
return false; return false;
} }
if (initializer->constant) if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
{ {
ConstInitializer *const_init = CALLOCS(ConstInitializer); ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_STRUCT; 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) static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer)
{ {
initializer->pure = true; initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list; 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; if (!sema_analyse_expr_of_required_type(context, inner_type, element, true)) return false;
initializer->failable |= element->failable; initializer->failable |= element->failable;
initializer->pure &= element->pure; initializer->pure &= element->pure;
initializer->constant &= element->constant;
} }
if (expected_members > size) if (expected_members > size)
@@ -3084,7 +3318,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
return false; return false;
} }
if (initializer->constant) if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
{ {
ConstInitializer *const_init = CALLOCS(ConstInitializer); ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_ARRAY_FULL; 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) static inline bool sema_expr_analyse_untyped_initializer(Context *context, Expr *initializer)
{ {
initializer->pure = true; initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list; Expr **elements = initializer->initializer_list;
unsigned size = vec_size(elements);
Type *element_type = NULL; Type *element_type = NULL;
bool no_common_elements = false; 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]; Expr *element = elements[i];
if (!sema_analyse_expr(context, NULL, element)) return false; if (!sema_analyse_expr(context, NULL, element)) return false;
initializer->failable |= element->failable; initializer->failable |= element->failable;
initializer->pure &= element->pure; initializer->pure &= element->pure;
initializer->constant &= element->constant;
if (no_common_elements) continue; if (no_common_elements) continue;
if (element_type == NULL) 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); element_type = type_find_max_type(element->type, element_type);
if (!element_type) no_common_elements = true; 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) 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->kind = CONST_INIT_ZERO;
initializer->type = type_flatten(expr->type); initializer->type = type_flatten(expr->type);
expr_set_as_const_list(expr, initializer); expr_set_as_const_list(expr, initializer);
expr->constant = true;
expr->pure = true; expr->pure = true;
return true; return true;
} }
@@ -3203,8 +3439,20 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
case TYPE_UNION: case TYPE_UNION:
case TYPE_ARRAY: case TYPE_ARRAY:
case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_ARRAY:
case TYPE_SUBARRAY:
return sema_expr_analyse_initializer(context, to, assigned, expr); 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: default:
break; 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]; Expr *checked_expr = expr->expression_list[i];
success &= sema_analyse_expr_of_required_type(context, i == last ? to : NULL, checked_expr, 0); success &= sema_analyse_expr_of_required_type(context, i == last ? to : NULL, checked_expr, 0);
expr->failable |= checked_expr->failable; expr->failable |= checked_expr->failable;
constant &= checked_expr->constant;
pure &= checked_expr->pure; pure &= checked_expr->pure;
} }
expr->pure = pure; expr->pure = pure;
expr->constant = constant;
return success; 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); bool success = sema_resolve_type_info(context, expr->cast_expr.type_info);
success &= sema_analyse_expr(context, NULL, inner); success &= sema_analyse_expr(context, NULL, inner);
expr->pure = inner->pure; expr->pure = inner->pure;
expr->constant = inner->constant;
if (!success) return false; if (!success) return false;
Type *target_type = expr->cast_expr.type_info->type; 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) static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right)
{ {
expr->constant = false;
expr->pure = 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) static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr *left, Expr *right, bool int_only)
{ {
expr->pure = false; expr->pure = false;
expr->constant = false;
if (left->expr_kind == EXPR_CT_IDENT) 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. // 3. Copy type & set properties.
expr_copy_types(expr, left); expr_copy_types(expr, left);
expr->pure = false; expr->pure = false;
expr->constant = false;
expr->failable = left->failable | right->failable; 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; *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 * Analyse a - b
* @return true if analysis succeeded * @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. // 1. Analyse a and b.
if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; 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 *left_type = left->type->canonical;
Type *right_type = right->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. // 7. Assign the type of the left side.
expr_copy_types(expr, left); expr_copy_types(expr, left);
expr_unify_binary_properties(expr, left, right); expr_unify_binary_properties(expr, left, right);
if (cast_to_iptr)
{
expr->resolve_status = RESOLVE_DONE;
return cast(expr, cast_to_iptr);
}
return true; 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. // this is safe in the pointer case actually.
if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false; 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 *left_type = left->type->canonical;
Type *right_type = right->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. // 3c. Set the type and other properties.
expr_copy_types(expr, left); expr_copy_types(expr, left);
expr_unify_binary_properties(expr, left, right); expr_unify_binary_properties(expr, left, right);
if (cast_to_iptr)
{
expr->resolve_status = RESOLVE_DONE;
return cast(expr, cast_to_iptr);
}
return true; return true;
} }
assert(!cast_to_iptr);
// 4. Do an binary arithmetic promotion // 4. Do an binary arithmetic promotion
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s.")) 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; if (!cast_implicit(left, numeric_arithmetic_promotion(left->type))) return false;
expr->pure = left->pure & right->pure; expr->pure = left->pure & right->pure;
expr->constant = left->constant & right->constant;
expr->failable = left->failable | right->failable; expr->failable = left->failable | right->failable;
// 5. For a constant right hand side we will make a series of checks. // 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; if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false;
expr->pure = false; expr->pure = false;
expr->constant = false;
expr->failable = left->failable | right->failable; expr->failable = left->failable | right->failable;
// 2. Ensure the left hand side is assignable // 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: case EXPR_CONST_IDENTIFIER:
return sema_take_addr_of_ident(inner, is_constant); return sema_take_addr_of_ident(inner, is_constant);
case EXPR_UNARY: case EXPR_UNARY:
*is_constant = inner->constant;
if (inner->unary_expr.operator == UNARYOP_DEREF) return true; if (inner->unary_expr.operator == UNARYOP_DEREF) return true;
break; break;
case EXPR_ACCESS: case EXPR_ACCESS:
@@ -4498,12 +4773,10 @@ static bool sema_take_addr_of(Expr *inner, bool *is_constant)
{ {
bool index_was_const = false; bool index_was_const = false;
if (!sema_take_addr_of(inner->subscript_expr.expr, &index_was_const)) return false; if (!sema_take_addr_of(inner->subscript_expr.expr, &index_was_const)) return false;
*is_constant = index_was_const && inner->constant;
return true; return true;
} }
case EXPR_SLICE: case EXPR_SLICE:
{ {
*is_constant = false;
bool dummy; bool dummy;
return sema_take_addr_of(inner->slice_expr.expr, &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. // 3. Get the pointer of the underlying type.
expr_set_type(expr, type_get_ptr(inner->type)); expr_set_type(expr, type_get_ptr(inner->type));
expr->constant = is_constant;
expr->pure = inner->pure; expr->pure = inner->pure;
expr->failable = inner->failable; 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. * @return false if analysis fails.
*/ */
static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner) static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner)
{ {;
expr->constant = false;
expr->pure = false; expr->pure = false;
expr->failable = inner->failable; 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) 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 *init = expr->try_assign_expr.init;
Expr *lhs = expr->try_assign_expr.expr; 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; if (!sema_analyse_expr_value(context, NULL, lhs)) return false;
} }
expr->constant = false;
expr->pure = init->pure & lhs->pure; expr->pure = init->pure & lhs->pure;
expr_set_type(expr, type_bool); expr_set_type(expr, type_bool);
return true; return true;
@@ -4945,7 +5215,7 @@ static inline bool sema_expr_analyse_try(Context *context, Expr *expr)
Expr *inner = expr->try_expr.expr; Expr *inner = expr->try_expr.expr;
if (!sema_analyse_expr(context, NULL, inner)) return false; if (!sema_analyse_expr(context, NULL, inner)) return false;
expr->pure = inner->pure; expr->pure = inner->pure;
expr->constant = false;
if (!inner->failable) if (!inner->failable)
{ {
SEMA_ERROR(expr->try_expr.expr, "Expected a failable expression to '%s'.", expr->expr_kind == EXPR_TRY ? "try" : "catch"); 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; Expr *inner = expr->else_expr.expr;
bool success = sema_analyse_expr(context, to, inner); bool success = sema_analyse_expr(context, to, inner);
expr->pure = inner->pure; expr->pure = inner->pure;
expr->constant = false;
if (!success) return false; if (!success) return false;
Type *type = inner->type; Type *type = inner->type;
if (!inner->failable) if (!inner->failable)
@@ -4997,7 +5267,7 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp
if (!success) return false; if (!success) return false;
expr_copy_types(expr, inner); expr_copy_types(expr, inner);
expr->pure = false; expr->pure = false;
expr->constant = false;
if (!inner->failable) if (!inner->failable)
{ {
SEMA_ERROR(expr, "No failable to rethrow before '!!' in the expression, please remove '!!'."); 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) static inline bool sema_expr_analyse_const(Type *to, Expr *expr)
{ {
expr->constant = true;
expr->pure = true; expr->pure = true;
return 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; expr->failable = context->expr_failable_return;
context->expr_failable_return = saved_expr_failable_return; context->expr_failable_return = saved_expr_failable_return;
context->expected_block_type = prev_expected_block_type; context->expected_block_type = prev_expected_block_type;
expr->constant = false;
expr->pure = false; expr->pure = false;
return success; return success;
} }
@@ -5109,7 +5378,7 @@ static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr)
TODO TODO
if (!sema_analyse_expr(context, NULL, expr->typeof_expr)) return false; if (!sema_analyse_expr(context, NULL, expr->typeof_expr)) return false;
expr->pure = expr->typeof_expr->pure; expr->pure = expr->typeof_expr->pure;
expr->constant = expr->typeof_expr->constant;
Type *type = expr->typeof_expr->type->canonical; Type *type = expr->typeof_expr->type->canonical;
expr->expr_kind = EXPR_TYPEID; expr->expr_kind = EXPR_TYPEID;
expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span); 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; if (!sema_analyse_expr(context, NULL, inner)) return false;
expr->pure = inner->pure; expr->pure = inner->pure;
expr->constant = inner->constant;
if (inner->failable) if (inner->failable)
{ {
SEMA_ERROR(inner, "The inner expression is already a 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; if (!sema_analyse_var_decl(context, expr->decl_expr)) return false;
expr_set_type(expr, expr->decl_expr->type); expr_set_type(expr, expr->decl_expr->type);
expr->pure = !expr->decl_expr->var.init_expr || expr->decl_expr->var.init_expr->pure; 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; return true;
} }
static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr) 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: case EXPR_GUARD:
return sema_expr_analyse_guard(context, to, expr); return sema_expr_analyse_guard(context, to, expr);
case EXPR_CONST: case EXPR_CONST:
case EXPR_BYTES:
return sema_expr_analyse_const(to, expr); return sema_expr_analyse_const(to, expr);
case EXPR_BINARY: case EXPR_BINARY:
if (!sema_expr_analyse_binary(context, to, expr)) return false; if (!sema_expr_analyse_binary(context, to, expr)) return false;

View File

@@ -441,10 +441,12 @@ bool sema_add_member(Context *context, Decl *decl)
bool sema_add_local(Context *context, Decl *decl) bool sema_add_local(Context *context, Decl *decl)
{ {
decl->module = context->module;
// Ignore synthetic locals. // Ignore synthetic locals.
if (decl->name_token.index == NO_TOKEN_ID.index) return true; if (decl->name_token.index == NO_TOKEN_ID.index) return true;
Decl *other = sema_resolve_normal_symbol(context, decl->name_token, NULL, false); 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); sema_shadow_error(decl, other);
decl_poison(decl); decl_poison(decl);

View File

@@ -724,7 +724,7 @@ bool sema_analyse_local_decl(Context *context, Decl *decl)
} }
if (decl->var.init_expr && decl->var.is_static) 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."); SEMA_ERROR(decl->var.init_expr, "Static variable initialization must be constant.");
return false; return false;
@@ -762,9 +762,9 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
if (decl->var.init_expr) if (decl->var.init_expr)
{ {
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false; 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; return false;
} }
} }
@@ -776,12 +776,13 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
} }
else 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 (!sema_analyse_expr(context, NULL, init)) return false;
if (decl->var.init_expr->expr_kind != EXPR_CONST) 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; return false;
} }
decl->type = decl->var.init_expr->type; decl->type = decl->var.init_expr->type;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "A232" #define COMPILER_VERSION "A233"

View File

@@ -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

View File

@@ -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
}

View File

@@ -355,7 +355,7 @@ entry:
%x = alloca %"int[]", align 8 %x = alloca %"int[]", align 8
%sum = alloca i32, align 4 %sum = alloca i32, align 4
%vararg = alloca %"int[]", align 8 %vararg = alloca %"int[]", align 8
%tempaddr = alloca %"int[]", align 8 %taddr = alloca %"int[]", align 8
%pair = bitcast %"int[]"* %x to { i8*, i64 }* %pair = bitcast %"int[]"* %x to { i8*, i64 }*
%lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0 %lo = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0
store i8* %0, i8** %lo, align 8 store i8* %0, i8** %lo, align 8
@@ -387,8 +387,8 @@ if.exit: ; preds = %entry
%10 = insertvalue %"int[]" %9, i64 %size, 1 %10 = insertvalue %"int[]" %9, i64 %size, 1
%11 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1 %11 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 1
%12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0 %12 = getelementptr inbounds %"int[]", %"int[]"* %vararg, i32 0, i32 0
store %"int[]" %10, %"int[]"* %tempaddr, align 8 store %"int[]" %10, %"int[]"* %taddr, align 8
%casttemp = bitcast %"int[]"* %tempaddr to { i8*, i64 }* %casttemp = bitcast %"int[]"* %taddr to { i8*, i64 }*
%lo1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0 %lo1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 0
%lo2 = load i8*, i8** %lo1, align 8 %lo2 = load i8*, i8** %lo1, align 8
%hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1 %hi3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %casttemp, i32 0, i32 1

View File

@@ -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
}

View File

@@ -105,6 +105,8 @@ func void main(int argc, char **argv)
} }
// #expect: fasta.ll // #expect: fasta.ll
%"char[]" = type { i8*, i64 }
%"double[]" = type { double*, i64 }
@fasta.IM = constant i32 139968, align 1 @fasta.IM = constant i32 139968, align 1
@fasta.IA = constant i32 3877, 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 @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 @.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 @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 @.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[]"* bitcast ([15 x double]* @.__const to %"double[]"*), i64 15 }, 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 @.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 @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 @.taddr.13 = private hidden global [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 @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 @fasta.LINELEN = constant i32 60, align 1
@.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", 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 @.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 %mul10 = mul i32 %11, 5
call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10) call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
ret void ret void
} }

View File

@@ -1,4 +1,4 @@
// #skip // #target: x64-darwin
union Baz union Baz
{ {
@@ -16,7 +16,11 @@ func int test()
Baz ffe = { .x = 1 }; Baz ffe = { .x = 1 };
int[1] azz = {}; int[1] azz = {};
int[*] a = {}; 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 }; bool x = ! int[] { 1, 2, 3 };
Bar b = {}; Bar b = {};
Baz z = {}; Baz z = {};
@@ -24,4 +28,81 @@ func int test()
Bar[] foo = {}; Bar[] foo = {};
Baz[3] baz = {}; Baz[3] baz = {};
return 1; return 1;
} }
// #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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -24,6 +24,15 @@ func int test()
// #expect: zero_init.ll // #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 { define i32 @zero_init.test() #0 {
entry: entry:
%azz = alloca [1 x i32], align 4 %azz = alloca [1 x i32], align 4
@@ -31,7 +40,9 @@ entry:
%b = alloca %Bar, align 4 %b = alloca %Bar, align 4
%z = alloca %Baz, align 8 %z = alloca %Baz, align 8
%sub = alloca %"int[]", align 8 %sub = alloca %"int[]", align 8
%literal = alloca [0 x i32], align 4
%foo = alloca %"Bar[]", align 8 %foo = alloca %"Bar[]", align 8
%literal1 = alloca [0 x %Bar], align 4
%baz = alloca [3 x %Baz], align 16 %baz = alloca [3 x %Baz], align 16
%0 = bitcast [1 x i32]* %azz to i8* %0 = bitcast [1 x i32]* %azz to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) 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) call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 8, i1 false)
%3 = bitcast %Baz* %z to i8* %3 = bitcast %Baz* %z to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false) call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
%4 = bitcast %"int[]"* %sub to i8* store [0 x i32] zeroinitializer, [0 x i32]* %literal, align 4
call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 16, i1 false) %4 = bitcast [0 x i32]* %literal to i32*
%5 = bitcast %"Bar[]"* %foo to i8* %5 = insertvalue %"int[]" undef, i32* %4, 0
call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 16, i1 false) %6 = insertvalue %"int[]" %5, i64 0, 1
%6 = bitcast [3 x %Baz]* %baz to i8* store %"int[]" %6, %"int[]"* %sub, align 8
call void @llvm.memset.p0i8.i64(i8* align 16 %6, i8 0, i64 24, i1 false) 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 ret i32 1
} }

View File

@@ -15,10 +15,17 @@ func Event test(int x)
// #expect: test.ll // #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 %x = alloca i32, align 4
%foo = alloca %Event, align 4 %foo = alloca %Event, align 4
%bar = 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 store i32 %0, i32* %x, align 4
%1 = bitcast %Event* %foo to i8* %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) 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 %intbool = icmp ne i32 %3, 0
br i1 %intbool, label %cond.lhs, label %cond.rhs br i1 %intbool, label %cond.lhs, label %cond.rhs
cond.lhs: cond.lhs: ; preds = %entry
%4 = load %Event, %Event* %foo, align 4 %4 = load %Event, %Event* %foo, align 4
br label %cond.phi br label %cond.phi
cond.rhs: cond.rhs: ; preds = %entry
%5 = load %Event, %Event* %bar, align 4 %5 = load %Event, %Event* %bar, align 4
br label %cond.phi br label %cond.phi
cond.phi: cond.phi: ; preds = %cond.rhs, %cond.lhs
%val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ]
store %Event %val, %Event* %tempaddr, align 4 store %Event %val, %Event* %taddr, align 4
%dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0 %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0
%6 = load i32, i32* %dive, align 4 %6 = load i32, i32* %dive, align 4
ret i32 %6 ret i32 %6
}

View File

@@ -18,7 +18,7 @@ func Event test(int x)
%x = alloca i32, align 4 %x = alloca i32, align 4
%foo = alloca %Event, align 4 %foo = alloca %Event, align 4
%bar = 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 store i32 %0, i32* %x, align 4
%1 = bitcast %Event* %foo to i8* %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) 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: cond.phi:
%val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ] %val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ]
store %Event %val, %Event* %tempaddr, align 4 store %Event %val, %Event* %taddr, align 4
%dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0 %dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0
%6 = load i32, i32* %dive, align 4 %6 = load i32, i32* %dive, align 4
%7 = zext i32 %6 to i64 %7 = zext i32 %6 to i64
ret i64 %7 ret i64 %7

View File

@@ -1,5 +1,19 @@
// #target: x64-darwin
module test; 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 struct Blend_Map_Entry
{ {
union vals { union vals {
@@ -23,6 +37,8 @@ func void test(Blend_Map_Entry* foo)
%Blend_Map_Entry = type { %vals } %Blend_Map_Entry = type { %vals }
%vals = type { [2 x double], [8 x i8] } %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.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.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 @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