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;
}
func void copy(char* dst, char* src, usize size)
{
for (usize i = 0; i < size; i++) dst[i] = src[i];
}
func void! system_malloc_function(void *unused, void** pointer, usize bytes, usize alignment, AllocationKind kind) @inline
{
switch (kind)
@@ -47,6 +52,37 @@ func void! system_malloc_function(void *unused, void** pointer, usize bytes, usi
$unreachable;
}
struct SlotAllocator
{
void* pages;
usize page_size;
usize page_count;
usize bitmask;
usize current_page;
}
func void*! SlotAllocator.alloc(SlotAllocator *allocator, usize size)
{
void* active_page = (char*)(allocator.pages) + allocator.current_page * allocator.page_size;
void** page_pointer = (void**)(active_page);
if (*page_pointer)
{
mem::free(*page_pointer);
*page_pointer = null;
}
if (size > allocator.page_size - $sizeof(page_pointer))
{
void* mem = mem::_malloc(size);
if (!mem) return AllocationFailure.OUT_OF_MEMORY!;
*page_pointer = mem;
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
return mem;
}
allocator.current_page = (allocator.current_page + 1) & (allocator.bitmask);
return &page_pointer[1];
}
struct RingAllocator
{
char *data;
@@ -131,4 +167,24 @@ func void* realloc(void *ptr, usize size) @inline
func void free(void* ptr) @inline
{
_free(ptr);
}
const TEMP_BLOCK_SIZE = 1024;
const TEMP_PAGES = 64;
private char[TEMP_BLOCK_SIZE * TEMP_PAGES] allocator_static_storage;
private void*[TEMP_PAGES] allocator_static_page_storage;
SlotAllocator default_allocator = {
.pages = &allocator_static_storage,
.page_size = TEMP_BLOCK_SIZE,
.page_count = TEMP_PAGES,
.bitmask = TEMP_PAGES - 1,
.current_page = 0,
};
func void*! talloc(usize size)
{
return default_allocator.alloc(size);
}

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

View File

@@ -653,8 +653,6 @@ typedef struct
Expr *left;
Expr *right;
BinaryOp operator;
bool left_maybe : 1;
bool right_maybe : 1;
} ExprBinary;
typedef struct
@@ -923,7 +921,6 @@ struct Expr_
ResolveStatus resolve_status : 3;
bool failable : 1;
bool pure : 1;
bool constant : 1;
SourceSpan span;
Type *type;
Type *original_type;
@@ -1796,10 +1793,18 @@ void expr_const_set_null(ExprConst *expr);
bool expr_const_int_overflowed(const ExprConst *expr);
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
ByteSize expr_const_list_size(const ConstInitializer *list);
void expr_insert_addr(Expr *original);
void expr_insert_deref(Expr *expr);
Expr *expr_variable(Decl *decl);
bool expr_is_constant_eval(Expr *expr);
typedef enum
{
CONSTANT_EVAL_ANY,
CONSTANT_EVAL_FOLDABLE,
CONSTANT_EVAL_NO_LINKTIME,
} ConstantEvalKind;
bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind);
const char *expr_const_to_error_string(const ExprConst *expr);
static inline bool expr_is_init_list(Expr *expr)
{

View File

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

View File

@@ -179,7 +179,6 @@ typedef enum
EXPR_POISONED,
EXPR_ACCESS,
EXPR_BINARY,
EXPR_BYTES,
EXPR_MACRO_BODY_EXPANSION,
EXPR_CALL,
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 target = bitcast ? LLVMBuildBitCast(c->builder, ref, llvm_get_type(c, type_get_ptr(type_char)), "") : ref;
return LLVMBuildMemSet(c->builder, target, LLVMConstInt(llvm_get_type(c, type_char), 0, false),
LLVMConstInt(llvm_get_type(c, type_ulong), size, false), align);
@@ -78,7 +79,7 @@ LLVMValueRef llvm_emit_const_array_padding(LLVMTypeRef element_type, IndexDiff d
return LLVMConstNull(padding_type);
}
LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool *modified)
LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init)
{
switch (const_init->kind)
{
@@ -93,18 +94,16 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
Type *element_type = array_type->array.base;
LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type);
ConstInitializer **elements = const_init->init_array_full;
assert(array_type->type_kind == TYPE_ARRAY);
ArrayIndex size = array_type->array.len;
if (array_type->type_kind == TYPE_SUBARRAY)
{
size = vec_size(elements);
}
assert(size > 0);
LLVMValueRef *parts = VECNEW(LLVMValueRef, size);
for (ArrayIndex i = 0; i < size; i++)
{
vec_add(parts, llvm_emit_const_initializer(c, elements[i], &was_modified));
LLVMValueRef element = llvm_emit_const_initializer(c, elements[i]);
if (element_type_llvm != LLVMTypeOf(element)) was_modified = true;
vec_add(parts, element);
}
if (was_modified) *modified = was_modified;
if (was_modified)
{
return LLVMConstStructInContext(c->context, parts, vec_size(parts), true);
@@ -118,6 +117,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
Type *array_type = const_init->type;
Type *element_type = array_type->array.base;
LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type);
AlignSize expected_align = llvm_abi_alignment(c, element_type_llvm);
ConstInitializer **elements = const_init->init_array.elements;
unsigned element_count = vec_size(elements);
assert(element_count > 0 && "Array should always have gotten at least one element.");
@@ -131,18 +131,19 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
assert(element->kind == CONST_INIT_ARRAY_VALUE);
ArrayIndex element_index = element->init_array_value.index;
IndexDiff diff = element_index - current_index;
unsigned curr_alignment = type_abi_alignment(element->type);
if (alignment && curr_alignment != alignment)
if (alignment && expected_align != alignment)
{
pack = true;
}
alignment = curr_alignment;
alignment = expected_align;
// Add zeroes
if (diff > 0)
{
vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, diff, &was_modified));
}
vec_add(parts, llvm_emit_const_initializer(c, element->init_array_value.element, &was_modified));
LLVMValueRef value = llvm_emit_const_initializer(c, element->init_array_value.element);
if (LLVMTypeOf(value) == element_type_llvm) was_modified = true;
vec_add(parts, value);
current_index = element_index + 1;
}
@@ -151,7 +152,6 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
{
vec_add(parts, llvm_emit_const_array_padding(element_type_llvm, end_diff, &was_modified));
}
if (was_modified) *modified = was_modified;
if (was_modified)
{
return LLVMConstStructInContext(c->context, parts, vec_size(parts), pack);
@@ -161,13 +161,10 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
case CONST_INIT_UNION:
{
Decl *decl = const_init->type->decl;
// Get the type of the member that is used for this particular
// constant value, for example if this is a union { double, int }
// then the type may be double or int.
Type *member_type = decl->strukt.members[const_init->init_union.index]->type->canonical;
// Emit our value.
LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element, modified);
LLVMValueRef result = llvm_emit_const_initializer(c, const_init->init_union.element);
LLVMTypeRef result_type = LLVMTypeOf(result);
// Get the union value
LLVMTypeRef union_type_llvm = llvm_get_type(c, decl->type);
@@ -177,7 +174,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
// We need to calculate some possible padding.
ByteSize union_size = type_size(const_init->type);
ByteSize member_size = type_size(member_type);
ByteSize member_size = llvm_abi_size(c, result_type);
ByteSize padding = union_size - member_size;
// Create the resulting values:
@@ -192,15 +189,9 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
}
// Is this another type than usual for the union?
if (first_type != llvm_get_type(c, member_type))
if (first_type != result_type)
{
// Yes, so the type needs to be modified.
*modified = true;
}
// If it is modified we simply create a packed struct for representation.
if (*modified)
{
return LLVMConstStructInContext(c->context, values, value_count, false);
}
@@ -212,21 +203,36 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
Decl **members = decl->strukt.members;
MemberIndex count = vec_size(members);
LLVMValueRef *entries = NULL;
bool was_modified = false;
for (MemberIndex i = 0; i < count; i++)
{
if (members[i]->padding)
{
vec_add(entries, llvm_emit_const_padding(c, members[i]->padding));
}
vec_add(entries, llvm_emit_const_initializer(c, const_init->init_struct[i], modified));
LLVMTypeRef expected_type = llvm_get_type(c, const_init->init_struct[i]->type);
LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i]);
LLVMTypeRef element_type = LLVMTypeOf(element);
if (expected_type != element_type)
{
was_modified = true;
}
AlignSize new_align = llvm_abi_alignment(c, element_type);
AlignSize expected_align = llvm_abi_alignment(c, expected_type);
if (i != 0 && new_align < expected_align)
{
vec_add(entries, llvm_emit_const_padding(c, expected_align - new_align));
}
vec_add(entries, element);
}
if (decl->strukt.padding)
{
vec_add(entries, llvm_emit_const_padding(c, decl->strukt.padding));
}
if (*modified)
if (was_modified)
{
return LLVMConstStructInContext(c->context, entries, vec_size(entries), decl->is_packed);
LLVMValueRef value = LLVMConstStructInContext(c->context, entries, vec_size(entries), decl->is_packed);
return value;
}
return LLVMConstNamedStruct(llvm_get_type(c, const_init->type), entries, vec_size(entries));
}
@@ -234,47 +240,12 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
{
BEValue value;
llvm_emit_expr(c, &value, const_init->init_value);
LLVMValueRef llvm_value = llvm_value_rvalue_store(c, &value);
LLVMTypeRef expected_type = llvm_get_type(c, const_init->type);
if (expected_type != LLVMTypeOf(llvm_value)) *modified = true;
return llvm_value;
return llvm_value_rvalue_store(c, &value);
}
}
UNREACHABLE
}
static LLVMValueRef llvm_emit_const_initializer_simple(GenContext *c, Expr *expr, bool *modified)
{
Expr **elements = expr->initializer_list;
unsigned element_count = vec_size(elements);
LLVMValueRef* values = malloc_arena(element_count * sizeof(LLVMValueRef));
Type *expr_type = expr->type->canonical;
LLVMTypeRef array_type = expr_type->type_kind == TYPE_ARRAY ? llvm_get_type(c, expr_type->array.base) : NULL;
assert(array_type || type_is_structlike(expr_type));
for (unsigned i = 0; i < element_count; i++)
{
BEValue value;
llvm_emit_expr(c, &value, elements[i]);
LLVMValueRef llvm_value = llvm_value_rvalue_store(c, &value);
LLVMTypeRef expected_type = array_type ? array_type : llvm_get_type(c, expr_type->decl->strukt.members[0]->type);
if (expected_type != LLVMTypeOf(llvm_value)) *modified = true;
values[i] = llvm_value;
}
if (array_type)
{
if (*modified)
{
return LLVMConstStructInContext(c->context, values, element_count, true);
}
return LLVMConstArray(array_type, values, element_count);
}
if (*modified)
{
return LLVMConstStructInContext(c->context, values, element_count, true);
}
return LLVMConstNamedStruct(llvm_get_type(c, expr_type), values, element_count);
}
static void gencontext_emit_global_variable_definition(GenContext *c, Decl *decl)
{
@@ -334,7 +305,6 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
// Skip real constants.
if (!decl->type) return;
bool modified = false;
LLVMValueRef init_value;
ByteSize alignment = type_alloca_alignment(decl->type);
@@ -345,46 +315,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
if (init_expr->expr_kind == EXPR_CONST && init_expr->const_expr.const_kind == CONST_LIST)
{
ConstInitializer *list = init_expr->const_expr.list;
init_value = llvm_emit_const_initializer(c, list, &modified);
Type *type = type_lowering(init_expr->type);
if (type->type_kind == TYPE_SUBARRAY)
{
LLVMTypeRef const_type = LLVMTypeOf(init_value);
LLVMValueRef global_copy = LLVMAddGlobal(c->module, const_type, ".__const");
LLVMSetLinkage(global_copy, LLVMPrivateLinkage);
// Set a nice alignment
Type *ptr = type_get_ptr(type);
llvm_set_alignment(global_copy, type_alloca_alignment(ptr));
// Set the value and make it constant
LLVMSetInitializer(global_copy, init_value);
LLVMSetGlobalConstant(global_copy, true);
LLVMValueRef value = LLVMConstBitCast(global_copy, llvm_get_type(c, ptr));
ByteSize size;
switch (list->kind)
{
case CONST_INIT_ZERO:
size = 0;
break;
case CONST_INIT_ARRAY:
size = VECLAST(list->init_array.elements)->init_array_value.index + 1;
break;
case CONST_INIT_ARRAY_FULL:
size = vec_size(list->init_array_full);
break;
default:
UNREACHABLE
}
LLVMTypeRef subarray_type = llvm_get_type(c, type);
LLVMValueRef result = LLVMGetUndef(subarray_type);
LLVMValueRef len = llvm_const_int(c, type_usize, size);
unsigned id = 0;
result = LLVMConstInsertValue(result, value, &id, 1);
id = 1;
init_value = LLVMConstInsertValue(result, len, &id, 1);
}
init_value = llvm_emit_const_initializer(c, list);
}
else
{
@@ -459,7 +390,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
break;
}
if (modified)
if (init_value && LLVMTypeOf(init_value) != llvm_get_type(c, decl->type))
{
decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type));
}
@@ -513,6 +444,7 @@ void gencontext_print_llvm_ir(GenContext *context)
LLVMValueRef llvm_emit_alloca(GenContext *c, LLVMTypeRef type, unsigned alignment, const char *name)
{
assert(c->builder);
assert(alignment > 0);
LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder);
LLVMPositionBuilderBefore(c->builder, c->alloca_point);
@@ -925,9 +857,23 @@ void llvm_value_addr(GenContext *c, BEValue *value)
{
llvm_value_fold_failable(c, value);
if (value->kind == BE_ADDRESS) return;
LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "tempaddr");
llvm_store_self_aligned(c, temp, value->value, value->type);
llvm_value_set_address(value, temp, value->type);
if (!c->builder)
{
LLVMValueRef val = llvm_value_rvalue_store(c, value);
LLVMValueRef ref = LLVMAddGlobal(c->module, LLVMTypeOf(val), ".taddr");
llvm_set_alignment(ref, llvm_abi_alignment(c, LLVMTypeOf(val)));
LLVMSetLinkage(ref, LLVMPrivateLinkage);
LLVMSetVisibility(ref, LLVMHiddenVisibility);
LLVMSetInitializer(ref, val);
llvm_emit_bitcast(c, ref, type_get_ptr(value->type));
llvm_value_set_address(value, ref, value->type);
}
else
{
LLVMValueRef temp = llvm_emit_alloca_aligned(c, value->type, "taddr");
llvm_store_self_aligned(c, temp, value->value, value->type);
llvm_value_set_address(value, temp, value->type);
}
}
void llvm_value_rvalue(GenContext *c, BEValue *value)
@@ -1261,6 +1207,7 @@ void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, un
LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name)
{
assert(c->builder);
LLVMValueRef value = LLVMBuildLoad2(c->builder, type, pointer, name);
assert(LLVMGetTypeContext(type) == c->context);
llvm_set_alignment(value, alignment ? alignment : llvm_abi_alignment(c, type));

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");
}
LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...)
{
LLVMValueRef result = LLVMGetUndef(llvm_get_type(c, type));
va_list args;
va_start(args, type);
LLVMValueRef val;
bool is_constant = true;
while (is_constant && (val = va_arg(args, LLVMValueRef)) != NULL)
{
if (!LLVMIsConstant(val)) is_constant = false;
}
va_end(args);
va_start(args, type);
unsigned index = 0;
if (is_constant)
{
while ((val = va_arg(args, LLVMValueRef)) != NULL)
{
result = LLVMConstInsertValue(result, val, &index, 1);
index++;
}
}
else
{
assert(c->builder);
while ((val = va_arg(args, LLVMValueRef)) != NULL)
{
result = LLVMBuildInsertValue(c->builder, result, val, index++, "");
}
}
va_end(args);
return result;
}
LLVMTypeRef llvm_const_padding_type(GenContext *c, ByteSize size)
{
assert(size > 0);
@@ -480,22 +515,10 @@ static void llvm_emit_arr_to_subarray_cast(GenContext *c, BEValue *value, Type *
ByteSize size = value->type->pointer->array.len;
Type *array_type = value->type->pointer->array.base;
LLVMTypeRef subarray_type = llvm_get_type(c, to_type);
LLVMValueRef result = LLVMGetUndef(subarray_type);
LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_get_ptr(array_type));
LLVMValueRef len = llvm_const_int(c, type_usize, size);
value->type = to_type;
if (!c->builder)
{
unsigned id = 0;
result = LLVMConstInsertValue(result, pointer, &id, 1);
id = 1;
value->value = LLVMConstInsertValue(result, len, &id, 1);
}
else
{
result = LLVMBuildInsertValue(c->builder, result, pointer, 0, "");
value->value = LLVMBuildInsertValue(c->builder, result, len, 1, "");
}
value->value = llvm_emit_aggregate_value(c, to_type, pointer, len, NULL);
}
@@ -571,7 +594,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
}
else
{
value->value = LLVMConstBitCast(value->value, llvm_get_type(c, to_type));
value->value = LLVMConstPtrToInt(value->value, llvm_get_type(c, to_type));
}
break;
case CAST_APTSA:
@@ -665,6 +688,12 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
break;
case CAST_XIPTR:
llvm_value_rvalue(c, value);
if (LLVMIsConstant(value->value))
{
value->value = LLVMConstIntToPtr(value->value, llvm_get_type(c, to_type));
break;
}
assert(c->builder);
value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr");
break;
case CAST_UISI:
@@ -790,10 +819,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref,
Type *canonical = expr->type->canonical;
assert(expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST);
LLVMValueRef value = llvm_emit_const_initializer(c, expr->const_expr.list, &modified);
LLVMValueRef value = llvm_emit_const_initializer(c, expr->const_expr.list);
LLVMTypeRef expected_type = llvm_get_type(c, canonical);
// Create a global const.
LLVMTypeRef type = modified ? LLVMTypeOf(value) : llvm_get_type(c, canonical);
LLVMTypeRef type = LLVMTypeOf(value);
LLVMValueRef global_copy = LLVMAddGlobal(c->module, type, ".__const");
LLVMSetLinkage(global_copy, LLVMPrivateLinkage);
@@ -808,6 +838,11 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref,
// Ensure we have a reference.
llvm_value_addr(c, ref);
if (expected_type != type)
{
global_copy = LLVMConstBitCast(global_copy, LLVMPointerType(expected_type, 0));
}
// Perform the memcpy.
llvm_emit_memcpy(c, ref->value, ref->alignment, global_copy, alignment, type_size(expr->type));
}
@@ -944,10 +979,6 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r
VECEACH(elements, i)
{
Expr *element = elements[i];
if (element->expr_kind == EXPR_COMPOUND_LITERAL)
{
element = element->expr_compound_literal.initializer;
}
unsigned offset = 0;
BEValue pointer;
if (is_struct)
@@ -1234,22 +1265,18 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
llvm_emit_inc_dec_change(c, use_mod, &addr, NULL, value, expr, diff);
}
static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{
Type *type = type_reduced_from_expr(expr->unary_expr.expr);
Expr *inner = expr->unary_expr.expr;
LLVMValueRef llvm_value;
switch (expr->unary_expr.operator)
{
case UNARYOP_ERROR:
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
case UNARYOP_TADDR:
llvm_value = llvm_emit_alloca_aligned(c, expr->unary_expr.expr->type, "taddr");
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_store_bevalue_dest_aligned(c, llvm_value, value);
llvm_value_set(value, llvm_value, type);
return;
case UNARYOP_NOT:
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
if (type_is_float(type))
{
@@ -1266,12 +1293,12 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
llvm_value_set_bool(value, llvm_value);
return;
case UNARYOP_BITNEG:
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
value->value = LLVMBuildNot(c->builder, value->value, "bnot");
return;
case UNARYOP_NEG:
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
if (type_is_float(type))
{
@@ -1296,8 +1323,9 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
}
value->value = LLVMBuildNeg(c->builder, value->value, "neg");
return;
case UNARYOP_TADDR:
case UNARYOP_ADDR:
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_emit_expr(c, value, inner);
// Create an addr
llvm_value_addr(c, value);
// Transform to value
@@ -1305,7 +1333,7 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
value->type = type_lowering(expr->type);
return;
case UNARYOP_DEREF:
llvm_emit_expr(c, value, expr->unary_expr.expr);
llvm_emit_expr(c, value, inner);
// Load the pointer value.
llvm_value_rvalue(c, value);
// Convert pointer to address
@@ -1313,10 +1341,10 @@ static void gencontext_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr
value->type = type_lowering(expr->type);
return;
case UNARYOP_INC:
llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, 1, false);
llvm_emit_pre_inc_dec(c, value, inner, 1, false);
return;
case UNARYOP_DEC:
llvm_emit_pre_inc_dec(c, value, expr->unary_expr.expr, -1, false);
llvm_emit_pre_inc_dec(c, value, inner, -1, false);
return;
}
UNREACHABLE
@@ -1522,7 +1550,7 @@ llvm_emit_slice_values(GenContext *c, Expr *slice, Type **parent_type_ref, LLVMV
*parent_type_ref = parent_type;
}
static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *expr)
static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
{
Type *parent_type;
Type *end_type;
@@ -1531,13 +1559,13 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
Type *start_type;
LLVMValueRef start_index;
// Use general function to get all the values we need (a lot!)
llvm_emit_slice_values(context, expr, &parent_type,
llvm_emit_slice_values(c, expr, &parent_type,
&parent_base,
&start_type, &start_index, &end_type, &end_index);
// Calculate the size
LLVMValueRef size = LLVMBuildSub(context->builder, LLVMBuildAdd(context->builder, end_index, llvm_const_int(context, start_type, 1), ""), start_index, "size");
LLVMValueRef size = LLVMBuildSub(c->builder, LLVMBuildAdd(c->builder, end_index, llvm_const_int(c, start_type, 1), ""), start_index, "size");
LLVMValueRef start_pointer;
switch (parent_type->type_kind)
{
@@ -1545,20 +1573,20 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
{
Type *pointer_type = type_get_ptr(parent_type->array.base);
// Change pointer from Foo[x] to Foo*
parent_base = llvm_emit_bitcast(context, parent_base, pointer_type);
parent_base = llvm_emit_bitcast(c, parent_base, pointer_type);
// Move pointer
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, pointer_type), parent_base, &start_index, 1, "offset");
start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, pointer_type), parent_base, &start_index, 1, "offset");
break;
}
case TYPE_SUBARRAY:
{
start_pointer = LLVMBuildInBoundsGEP(context->builder, parent_base, &start_index, 1, "offsetsub");
start_pointer = LLVMBuildInBoundsGEP(c->builder, parent_base, &start_index, 1, "offsetsub");
break;
}
case TYPE_POINTER:
{
// Move pointer
start_pointer = LLVMBuildInBoundsGEP2(context->builder, llvm_get_pointee_type(context, parent_type), parent_base, &start_index, 1, "offset");
start_pointer = LLVMBuildInBoundsGEP2(c->builder, llvm_get_pointee_type(c, parent_type), parent_base, &start_index, 1, "offset");
break;
}
default:
@@ -1566,9 +1594,7 @@ static void gencontext_emit_slice(GenContext *context, BEValue *be_value, Expr *
}
// Create a new subarray type
LLVMValueRef result = LLVMGetUndef(llvm_get_type(context, expr->type));
result = LLVMBuildInsertValue(context->builder, result, start_pointer, 0, "");
llvm_value_set(be_value, LLVMBuildInsertValue(context->builder, result, size, 1, ""), expr->type);
llvm_value_set(be_value, llvm_emit_aggregate_value(c, expr->type, start_pointer, size, NULL), expr->type);
}
static void gencontext_emit_slice_assign(GenContext *c, BEValue *be_value, Expr *expr)
@@ -2103,6 +2129,7 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
case BINARYOP_SUB:
if (lhs_type->type_kind == TYPE_POINTER)
{
bool is_constant = LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value);
if (lhs_type == rhs_type)
{
LLVMTypeRef int_type = llvm_get_type(c, type_iptrdiff);
@@ -2111,8 +2138,17 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
val = LLVMBuildExactSDiv(c->builder, val, llvm_const_int(c, type_iptrdiff, type_abi_alignment(lhs_type->pointer)), "");
break;
}
rhs_value = LLVMBuildNeg(c->builder, rhs_value, "");
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub");
if (is_constant)
{
rhs_value = LLVMConstNeg(rhs_value);
// TODO use GEP2
val = LLVMConstGEP(lhs_value, &rhs_value, 1);
}
else
{
rhs_value = LLVMBuildNeg(c->builder, rhs_value, "");
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptrsub");
}
break;
}
if (is_float)
@@ -2126,7 +2162,16 @@ void gencontext_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValu
if (lhs_type->type_kind == TYPE_POINTER)
{
assert(type_is_integer(rhs_type));
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd");
if (LLVMIsConstant(lhs_value) && LLVMIsConstant(rhs_value))
{
// TODO use LLVMConstGEP2
// val = LLVMConstGEP2(llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1);
val = LLVMConstGEP(lhs_value, &rhs_value, 1);
}
else
{
val = LLVMBuildGEP2(c->builder, llvm_get_pointee_type(c, lhs_type), lhs_value, &rhs_value, 1, "ptradd");
}
break;
}
if (is_float)
@@ -2639,6 +2684,11 @@ static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Real f)
static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue *value, Expr *expr)
{
if (!c->builder)
{
llvm_value_set(value, llvm_emit_const_initializer(c, expr->const_expr.list), expr->type);
return;
}
llvm_value_set_address(value, llvm_emit_alloca_aligned(c, expr->type, "literal"), expr->type);
llvm_emit_initialize_reference_const(c, value, expr);
}
@@ -3577,7 +3627,6 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *expr, LLVMValue
}
}
BEValue value;
if (expr->expr_kind == EXPR_COMPOUND_LITERAL) expr = expr->expr_compound_literal.initializer;
if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_LIST)
{
llvm_emit_const_initialize_reference(c, ref, expr);
@@ -3827,7 +3876,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_try_assign_expr(c, value, expr);
return;
case EXPR_NOP:
case EXPR_BYTES:
return;
case EXPR_ELSE:
gencontext_emit_else_expr(c, value, expr);

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_defer(GenContext *c, AstId defer_start, AstId defer_end);
void llvm_emit_extern_decl(GenContext *context, Decl *decl);
LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init, bool *modified);
LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init);
void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr);
void llvm_emit_typeid(GenContext *c, BEValue *be_value, Type *type);
void llvm_emit_global_variable_init(GenContext *c, Decl *decl);
@@ -250,6 +250,7 @@ void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_l
LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name);
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_aggregate_value(GenContext *c, Type *type, ...);
LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned align, bool bitcast);
LLVMValueRef llvm_emit_memclear(GenContext *c, BEValue *ref);
void llvm_emit_memcpy(GenContext *c, LLVMValueRef dest, unsigned dest_align, LLVMValueRef source, unsigned src_align, uint64_t len);
@@ -324,11 +325,14 @@ static inline LLVMValueRef llvm_emit_store(GenContext *context, Decl *decl, LLVM
static inline LLVMValueRef llvm_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type)
{
assert(type->type_kind == TYPE_POINTER);
if (!context->builder)
LLVMTypeRef result_type = llvm_get_type(context, type);
if (result_type == LLVMTypeOf(value)) return value;
if (LLVMIsConstant(value))
{
return LLVMConstBitCast(value, llvm_get_type(context, type));
return LLVMConstBitCast(value, result_type);
}
return LLVMBuildBitCast(context->builder, value, llvm_get_type(context, type), "");
assert(context->builder);
return LLVMBuildBitCast(context->builder, value, result_type, "");
}
static inline bool llvm_use_debug(GenContext *context) { return context->debug.builder != NULL; }

View File

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

View File

@@ -277,5 +277,20 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind)
expr->float_type = kind;
}
ByteSize expr_const_list_size(const ConstInitializer *list)
{
switch (list->kind)
{
case CONST_INIT_ZERO:
return 0;
case CONST_INIT_ARRAY:
return VECLAST(list->init_array.elements)->init_array_value.index + 1;
case CONST_INIT_ARRAY_FULL:
return vec_size(list->init_array_full);
default:
UNREACHABLE
}
}

View File

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

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)
{
Type *to_type_flat = type_flatten(to_type);
Real limit;
Real hi_limit;
Real lo_limit;
switch (to_type_flat->type_kind)
{
case TYPE_F16:
limit = FLOAT16_LIMIT;
lo_limit = hi_limit = FLOAT16_LIMIT;
break;
case TYPE_F32:
limit = FLOAT32_LIMIT;
lo_limit = hi_limit = FLOAT32_LIMIT;
break;
case TYPE_F64:
limit = FLOAT64_LIMIT;
lo_limit = hi_limit = FLOAT64_LIMIT;
break;
case TYPE_F128:
// Assume this to be true
return true;
case TYPE_BOOL:
return true;
default:
UNREACHABLE
}
if (expr->const_expr.f < -limit || expr->const_expr.f > limit)
if (expr->const_expr.f < -lo_limit || expr->const_expr.f > hi_limit)
{
#if LONG_DOUBLE
SEMA_ERROR(expr, "The value '%Lg' is out of range for %s, so you need an explicit cast to truncate the value.", expr->const_expr.f, type_quoted_error_string(to_type));

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;
// 2. Check const-ness
if ((is_global || decl->var.is_static) && !init_expr->constant)
if ((is_global || decl->var.is_static) && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_ANY))
{
// 3. Special case is when the init expression is the reference
// to a constant global structure.
if (init_expr->expr_kind == EXPR_CONST_IDENTIFIER)
{
// 4. If so we copy the init expression, which should always be constant.
*init_expr = *init_expr->identifier_expr.decl->var.init_expr;
assert(init_expr->constant);
}
else
{
if (init_expr->expr_kind == EXPR_CAST)
{
SEMA_ERROR(init_expr, "The expression may not be a non constant cast.");
}
else
{
SEMA_ERROR(init_expr, "The expression must be a constant value.");
}
return false;
}
SEMA_ERROR(init_expr, "The expression must be a constant value.");
}
else
{

View File

@@ -84,7 +84,6 @@ void expr_copy_properties(Expr *to, Expr *from)
{
to->failable = from->failable;
to->pure = from->pure;
to->constant = from->constant;
}
void expr_copy_types(Expr *to, Expr *from)
@@ -107,9 +106,6 @@ void expr_insert_addr(Expr *original)
expr_set_type(original, type_get_ptr(inner->type));
original->unary_expr.operator = UNARYOP_ADDR;
original->unary_expr.expr = inner;
original->pure = false;
original->constant = false;
original->failable = inner->failable;
}
Expr *expr_variable(Decl *decl)
@@ -117,12 +113,251 @@ Expr *expr_variable(Decl *decl)
Expr *expr = expr_new(EXPR_IDENTIFIER, decl->span);
expr->identifier_expr.decl = decl;
expr->pure = true;
expr->constant = false;
expr->resolve_status = RESOLVE_DONE;
expr_set_type(expr, decl->type);
return expr;
}
static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
{
if (eval_kind != CONSTANT_EVAL_ANY) return false;
Expr *inner = expr->unary_expr.expr;
switch (inner->expr_kind)
{
case EXPR_CONST:
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
return expr_is_constant_eval(inner, eval_kind);
case EXPR_IDENTIFIER:
case EXPR_CONST_IDENTIFIER:
{
Decl *decl = inner->identifier_expr.decl;
if (decl->decl_kind == DECL_FUNC) return true;
if (decl->decl_kind != DECL_VAR) return false;
switch (decl->var.kind)
{
case VARDECL_CONST:
case VARDECL_GLOBAL:
return true;
case VARDECL_LOCAL:
return decl->var.is_static;
case VARDECL_PARAM:
case VARDECL_MEMBER:
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_PARAM_REF:
case VARDECL_PARAM_EXPR:
case VARDECL_LOCAL_CT:
case VARDECL_LOCAL_CT_TYPE:
case VARDECL_UNWRAPPED:
case VARDECL_ERASE:
case VARDECL_REWRAPPED:
return false;
}
}
default:
return false;
}
}
bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
{
switch (expr->cast_expr.kind)
{
case CAST_ERROR:
return false;
case CAST_ERBOOL:
case CAST_EUBOOL:
case CAST_EUER:
case CAST_EREU:
case CAST_XIERR:
case CAST_PTRPTR:
case CAST_ARRPTR:
case CAST_STRPTR:
case CAST_PTRBOOL:
case CAST_BOOLINT:
case CAST_BOOLFP:
case CAST_BOOLBOOL:
case CAST_FPBOOL:
case CAST_INTBOOL:
case CAST_FPFP:
case CAST_FPSI:
case CAST_FPUI:
case CAST_SISI:
case CAST_SIUI:
case CAST_SIFP:
case CAST_XIPTR:
case CAST_UISI:
case CAST_UIUI:
case CAST_UIFP:
case CAST_APTSA:
case CAST_SAPTR:
case CAST_SABOOL:
case CAST_STST:
case CAST_VRPTR:
case CAST_PTRVR:
case CAST_VRBOOL:
case CAST_ENUMLOW:
if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false;
return expr_is_constant_eval(expr->cast_expr.expr, eval_kind);
case CAST_EUINT:
case CAST_ERINT:
case CAST_PTRXI:
if (eval_kind != CONSTANT_EVAL_ANY) return false;
return expr_is_constant_eval(expr->cast_expr.expr, eval_kind);
}
UNREACHABLE
}
static bool expr_binary_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
{
if (expr->binary_expr.operator >= BINARYOP_ASSIGN) return false;
if (eval_kind == CONSTANT_EVAL_FOLDABLE) return false;
Expr *left = expr->binary_expr.left;
Expr *right = expr->binary_expr.right;
int pointers = type_flatten(left->type)->type_kind == TYPE_POINTER ? 1 : 0;
pointers += type_flatten(right->type)->type_kind == TYPE_POINTER ? 1 : 0;
switch (expr->binary_expr.operator)
{
case BINARYOP_ERROR:
UNREACHABLE
case BINARYOP_SUB:
// Pointer diffs are not compile time resolved.
if (pointers == 2) return false;
if (pointers == 0) eval_kind = CONSTANT_EVAL_NO_LINKTIME;
break;
case BINARYOP_ADD:
assert(pointers != 2);
if (pointers == 0) eval_kind = CONSTANT_EVAL_NO_LINKTIME;
break;
default:
// For the default operations we don't accept linktime resolution
eval_kind = CONSTANT_EVAL_NO_LINKTIME;
break;
}
if (!expr_is_constant_eval(left, eval_kind)) return false;
if (!expr_is_constant_eval(right, eval_kind)) return false;
return true;
}
static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind)
{
VECEACH(exprs, i)
{
if (!expr_is_constant_eval(exprs[i], eval_kind)) return false;
}
return true;
}
bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
{
RETRY:
switch (expr->expr_kind)
{
case EXPR_ACCESS:
expr = expr->access_expr.parent;
goto RETRY;
case EXPR_BINARY:
return expr_binary_is_constant_eval(expr, eval_kind);
case EXPR_CAST:
return expr_cast_is_constant_eval(expr, eval_kind);
case EXPR_CONST:
return true;
case EXPR_CONST_IDENTIFIER:
expr = expr->identifier_expr.decl->var.init_expr;
goto RETRY;
case EXPR_COND:
return expr_list_is_constant_eval(expr->cond_expr, eval_kind);
case EXPR_DESIGNATOR:
expr = expr->designator_expr.value;
goto RETRY;
case EXPR_ELSE:
if (expr->else_expr.is_jump) return false;
assert(!expr_is_constant_eval(expr->else_expr.expr, eval_kind));
return false;
case EXPR_EXPR_BLOCK:
case EXPR_DECL:
case EXPR_CALL:
case EXPR_CATCH_UNWRAP:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TRY_ASSIGN:
case EXPR_POST_UNARY:
case EXPR_SCOPED_EXPR:
case EXPR_SLICE_ASSIGN:
case EXPR_MACRO_BLOCK:
case EXPR_IDENTIFIER:
case EXPR_GUARD:
case EXPR_UNDEF:
return false;
case EXPR_EXPRESSION_LIST:
return expr_list_is_constant_eval(expr->expression_list, eval_kind);
case EXPR_FAILABLE:
expr = expr->failable_expr;
goto RETRY;
case EXPR_GROUP:
expr = expr->group_expr;
goto RETRY;
case EXPR_INITIALIZER_LIST:
return expr_list_is_constant_eval(expr->initializer_list, eval_kind);
case EXPR_DESIGNATED_INITIALIZER_LIST:
return expr_list_is_constant_eval(expr->designated_init_list, eval_kind);
case EXPR_LEN:
expr = expr->len_expr.inner;
goto RETRY;
case EXPR_SLICE:
if (expr->slice_expr.start && !expr_is_constant_eval(expr->slice_expr.start, CONSTANT_EVAL_FOLDABLE)) return false;
if (expr->slice_expr.end && !expr_is_constant_eval(expr->slice_expr.end, CONSTANT_EVAL_FOLDABLE)) return false;
return expr_is_constant_eval(expr->slice_expr.expr, eval_kind);
case EXPR_SUBSCRIPT:
if (!expr_is_constant_eval(expr->subscript_expr.index, eval_kind)) return false;
expr = expr->subscript_expr.expr;
goto RETRY;
case EXPR_TERNARY:
assert(!expr_is_constant_eval(expr->ternary_expr.cond, eval_kind));
return false;
case EXPR_TRY:
expr = expr->try_expr.expr;
goto RETRY;
case EXPR_TYPEID:
return eval_kind == CONSTANT_EVAL_ANY;
case EXPR_UNARY:
switch (expr->unary_expr.operator)
{
case UNARYOP_ERROR:
case UNARYOP_DEREF:
return false;
case UNARYOP_ADDR:
return expr_unary_addr_is_constant_eval(expr, eval_kind);
case UNARYOP_NEG:
case UNARYOP_BITNEG:
case UNARYOP_NOT:
case UNARYOP_TADDR:
expr = expr->unary_expr.expr;
goto RETRY;
case UNARYOP_INC:
case UNARYOP_DEC:
return false;
}
UNREACHABLE
case EXPR_CT_CALL:
case EXPR_TYPEOF:
case EXPR_TYPEINFO:
case EXPR_HASH_IDENT:
case EXPR_CT_IDENT:
case EXPR_FLATPATH:
case EXPR_COMPOUND_LITERAL:
case EXPR_MACRO_EXPANSION:
case EXPR_PLACEHOLDER:
case EXPR_POISONED:
UNREACHABLE
case EXPR_NOP:
return true;
}
UNREACHABLE
}
void expr_insert_deref(Expr *original)
{
assert(original->resolve_status == RESOLVE_DONE);
@@ -141,7 +376,6 @@ void expr_insert_deref(Expr *original)
original->unary_expr.operator = UNARYOP_DEREF;
original->unary_expr.expr = inner;
original->pure = false;
original->constant = false;
original->failable = inner->failable;
}
@@ -149,7 +383,6 @@ void expr_insert_deref(Expr *original)
static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right)
{
expr->pure = left->pure & right->pure;
expr->constant = left->constant & right->constant;
expr->failable = left->failable | right->failable;
}
@@ -310,7 +543,10 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
switch (decl->var.kind)
{
case VARDECL_CONST:
if (!type_is_builtin(decl->type->type_kind)) break;
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
{
UNREACHABLE
}
expr_replace(expr, copy_expr(decl->var.init_expr));
return sema_analyse_expr(context, to, expr);
case VARDECL_PARAM_EXPR:
@@ -402,6 +638,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
{
Expr *left = expr->ternary_expr.then_expr;
Expr *cond = expr->ternary_expr.cond;
int path = -1;
// Normal
if (left)
{
@@ -409,6 +646,10 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
if (!cast_implicit(cond, type_bool)) return expr_poison(expr);
if (!sema_analyse_expr(context, to, left)) return expr_poison(expr);
expr->failable = left->failable | cond->failable;
if (cond->expr_kind == EXPR_CONST)
{
path = cond->const_expr.b ? 1 : 0;
}
}
else
{
@@ -421,6 +662,13 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
SEMA_ERROR(cond, "Cannot convert expression to boolean.");
return false;
}
if (expr_is_constant_eval(cond, true))
{
Expr *copy = copy_expr(cond);
cast(copy, type_bool);
assert(cond->expr_kind == EXPR_CONST);
path = cond->const_expr.b ? 1 : 0;
}
left = cond;
}
@@ -428,7 +676,6 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
if (!sema_analyse_expr(context, to, right)) return expr_poison(expr);
expr->pure = cond->pure & left->pure & right->pure;
expr->constant = cond->constant & left->constant & right->pure;
expr->failable |= right->failable;
Type *left_canonical = left->type->canonical;
@@ -458,8 +705,12 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e
if (!cast_implicit(left, max) || !cast_implicit(right, max)) return false;
}
expr_unify_binary(expr, left, right);
if (path > -1)
{
expr_replace(expr, path ? left : right);
}
expr_unify_binary(expr, left, right);
return true;
}
@@ -487,7 +738,6 @@ static inline bool sema_expr_analyse_enum_constant(Expr *expr, TokenId name, Dec
assert(enum_constant->resolve_status == RESOLVE_DONE);
expr_set_type(expr, decl->type);
expr->expr_kind = EXPR_CONST;
expr->constant = true;
expr->pure = true;
if (enum_constant->decl_kind == DECL_ENUM_CONSTANT)
{
@@ -522,37 +772,6 @@ static inline bool find_possible_inferred_identifier(Type *to, Expr *expr)
}
bool expr_is_constant_eval(Expr *expr)
{
// TODO rethink this.
switch (expr->expr_kind)
{
case EXPR_CONST:
return true;
case EXPR_COMPOUND_LITERAL:
return expr_is_constant_eval(expr->expr_compound_literal.initializer);
case EXPR_INITIALIZER_LIST:
{
Expr** init_exprs = expr->initializer_list;
VECEACH(init_exprs, i)
{
if (!expr_is_constant_eval(init_exprs[i])) return false;
}
return true;
}
case EXPR_DESIGNATED_INITIALIZER_LIST:
{
Expr** init_exprs = expr->designated_init_list;
VECEACH(init_exprs, i)
{
if (!expr_is_constant_eval(init_exprs[i])) return false;
}
return true;
}
default:
return false;
}
}
static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr *expr)
{
@@ -605,7 +824,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
{
Expr *copy = copy_expr(decl->var.init_expr);
if (!sema_analyse_expr(context, to, copy)) return false;
if (!expr_is_constant_eval(copy))
if (!expr_is_constant_eval(copy, false))
{
SEMA_ERROR(expr, "Constant value did not evaluate to a constant.");
return false;
@@ -627,7 +846,6 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
expr->identifier_expr.decl = decl;
expr_set_type(expr, decl->type);
expr->pure = true;
expr->constant = false;
DEBUG_LOG("Resolution successful of %s.", decl->name);
return true;
}
@@ -693,7 +911,6 @@ static inline bool sema_expr_analyse_ct_identifier(Context *context, Expr *expr)
expr->ct_ident_expr.decl = decl;
expr_set_type(expr, decl->type);
expr->pure = true;
expr->constant = true;
return true;
}
@@ -1156,7 +1373,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal
// $foo
assert(callee.macro);
if (!sema_analyse_expr_of_required_type(context, param->type, arg, false)) return false;
if (!expr_is_constant_eval(arg))
if (!expr_is_constant_eval(arg, CONSTANT_EVAL_ANY))
{
SEMA_ERROR(arg, "A compile time parameter must always be a constant, did you mistake it for a normal paramter?");
return false;
@@ -1338,7 +1555,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast)
return true;
case AST_RETURN_STMT:
if (!ast->return_stmt.expr) return true;
return expr_is_constant_eval(ast->return_stmt.expr);
return expr_is_constant_eval(ast->return_stmt.expr, CONSTANT_EVAL_ANY);
case AST_EXPR_STMT:
return sema_check_expr_compile_time(context, ast->expr_stmt);
case AST_CT_COMPOUND_STMT:
@@ -1492,7 +1709,7 @@ static bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_
if (vec_size(context->returns) == 1)
{
Expr *result = context->returns[0]->return_stmt.expr;
if (result && expr_is_constant_eval(result))
if (result && expr_is_constant_eval(result, CONSTANT_EVAL_ANY))
{
if (sema_check_stmt_compile_time(context, body))
{
@@ -1727,7 +1944,6 @@ bool sema_expr_analyse_general_call(Context *context, Type *to, Expr *expr, Decl
static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr)
{
expr->constant = false;
expr->pure = false;
Expr *func_expr = expr->call_expr.function;
@@ -1858,24 +2074,59 @@ static Type *sema_expr_find_indexable_type_recursively(Type **type, Expr **paren
}
static inline bool sema_expr_analyse_subscript(Context *context, Expr *expr)
{
if (!sema_analyse_expr(context, NULL, expr->subscript_expr.expr)) return false;
Expr *subscripted = expr->subscript_expr.expr;
if (!sema_analyse_expr_value(context, NULL, subscripted)) return false;
Expr *index = expr->subscript_expr.index;
if (!sema_analyse_expr(context, NULL, index)) return false;
expr->failable = expr->subscript_expr.expr->failable;
assert(expr->expr_kind == EXPR_SUBSCRIPT);
Expr *subscripted = expr->subscript_expr.expr;
Type *type = type_flatten(subscripted->type);
Expr *index = expr->subscript_expr.index;
Type *current_type = type;
Expr *current_expr = subscripted;
if (type == type_complist)
{
assert(current_expr->expr_kind == EXPR_CT_IDENT);
current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
assert(current_expr->expr_kind == EXPR_INITIALIZER_LIST);
if (index->expr_kind != EXPR_CONST || index->const_expr.const_kind != CONST_INTEGER)
{
SEMA_ERROR(index, "To subscript a compile time list a compile time integer index is needed.");
return false;
}
if (!bigint_fits_in_bits(&index->const_expr.i, 64, true))
{
SEMA_ERROR(index, "Index does not fit into an 64-signed integer.");
return false;
}
int64_t i = bigint_as_signed(&index->const_expr.i);
unsigned count = vec_size(current_expr->initializer_list);
if (expr->subscript_expr.from_back)
{
i = count - i;
}
if (i < 0 || i >= count)
{
SEMA_ERROR(index, "Index %lld is out of range.", (long long)i);
return false;
}
Expr *indexed_expr = current_expr->initializer_list[i];
if (!sema_cast_rvalue(context, NULL, indexed_expr)) return false;
expr_replace(expr, indexed_expr);
return true;
}
if (!sema_cast_rvalue(context, NULL, current_expr)) return false;
Type *inner_type = sema_expr_find_indexable_type_recursively(&current_type, &current_expr);
if (!inner_type)
{
SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(type));
return false;
}
if (!sema_analyse_expr(context, NULL, index)) return false;
expr->constant = index->constant & subscripted->constant;
expr->pure = index->pure & subscripted->pure;
// Cast to an appropriate type for index.
@@ -1897,7 +2148,6 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
assert(expr->expr_kind == EXPR_SLICE);
Expr *subscripted = expr->slice_expr.expr;
expr->pure = subscripted->pure;
expr->constant = subscripted->constant;
Type *type = type_flatten(subscripted->type);
Expr *start = expr->slice_expr.start;
Expr *end = expr->slice_expr.end;
@@ -1914,10 +2164,8 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
if (!sema_analyse_expr(context, type_int, start)) return false;
expr->pure &= start->pure;
expr->constant &= start->constant;
if (end && !sema_analyse_expr(context, type_int, end)) return false;
expr->pure &= !end || end->pure;
expr->constant &= !end || end->constant;
// Fix index sizes
if (!expr_cast_to_index(start)) return false;
@@ -2002,7 +2250,6 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type,
expr_to_rewrite->expr_kind = EXPR_CONST;
expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind);
expr_set_type(expr_to_rewrite, type);
expr_to_rewrite->constant = true;
expr_to_rewrite->pure = true;
expr_to_rewrite->resolve_status = RESOLVE_DONE;
}
@@ -2011,7 +2258,6 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type,
static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string)
{
expr_to_rewrite->expr_kind = EXPR_CONST;
expr_to_rewrite->constant = true;
expr_to_rewrite->const_expr.const_kind = CONST_STRING;
expr_to_rewrite->const_expr.string.chars = (char *)string;
expr_to_rewrite->const_expr.string.len = (int)strlen(string);
@@ -2023,7 +2269,6 @@ static inline void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *str
static bool sema_expr_analyse_typeinfo(Context *context, Expr *expr)
{
expr->constant = true;
expr->pure = true;
TypeInfo *type_info = expr->type_expr;
@@ -2139,7 +2384,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T
return false;
}
expr->constant = true;
expr->pure = true;
TokenType type = TOKTYPE(identifier_token);
@@ -2171,7 +2415,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T
expr->const_expr.f = nan("");
#endif
expr_set_type(expr, parent->type);
expr->constant = true;
expr->pure = true;
expr->resolve_status = RESOLVE_DONE;
return true;
@@ -2183,7 +2426,6 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T
expr->const_expr.const_kind = CONST_FLOAT;
expr->const_expr.f = INFINITY;
expr_set_type(expr, parent->type->canonical);
expr->constant = true;
expr->pure = true;
expr->resolve_status = RESOLVE_DONE;
return true;
@@ -2317,7 +2559,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Expr *expr, T
expr->type_expr->type = member->type;
expr->type_expr->resolve_status = RESOLVE_DONE;
expr_set_type(expr, type_typeinfo);
expr->constant = expr->pure = true;
expr->pure = true;
return true;
}
@@ -2460,7 +2702,6 @@ CHECK_DEEPER:
// 13. Copy properties.
expr->access_expr.parent = current_parent;
expr->constant = expr->access_expr.parent->constant;
expr->pure = expr->access_expr.parent->pure;
expr_set_type(expr, member->type);
expr->access_expr.ref = member;
@@ -2621,7 +2862,6 @@ static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr
}
current = new_current;
}
expr->constant = is_constant;
expr->pure = is_constant;
return current;
}
@@ -2926,7 +3166,6 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
bool is_structlike = type_is_structlike(assigned->canonical);
initializer->pure = true;
initializer->constant = true;
ArrayIndex max_index = -1;
VECEACH(init_expressions, i)
{
@@ -2935,18 +3174,17 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
if (!result) return false;
if (!sema_analyse_expr_of_required_type(context, result, expr->designator_expr.value, true)) return false;
expr->pure &= expr->designator_expr.value->pure;
expr->constant &= expr->designator_expr.value->constant;
expr->failable |= expr->designator_expr.value->failable;
expr->resolve_status = RESOLVE_DONE;
initializer->pure &= expr->pure;
initializer->constant &= expr->constant;
}
if (!is_structlike && initializer->type->type_kind == TYPE_INFERRED_ARRAY)
{
initializer->type = sema_type_lower_by_size(initializer->type, max_index + 1);
}
if (initializer->constant)
if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
{
ConstInitializer *const_init = MALLOC(sizeof(ConstInitializer));
sema_create_const_initializer(const_init, initializer);
@@ -2963,7 +3201,6 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
{
initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list;
Decl **members = assigned->strukt.members;
@@ -3000,7 +3237,6 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
// 5. We know the required type, so resolve the expression.
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i], 0)) return false;
initializer->pure &= element->pure;
initializer->constant &= element->constant;
initializer->failable |= element->failable;
}
@@ -3011,7 +3247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
return false;
}
if (initializer->constant)
if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
{
ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_STRUCT;
@@ -3045,7 +3281,6 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer)
{
initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list;
@@ -3075,7 +3310,6 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
if (!sema_analyse_expr_of_required_type(context, inner_type, element, true)) return false;
initializer->failable |= element->failable;
initializer->pure &= element->pure;
initializer->constant &= element->constant;
}
if (expected_members > size)
@@ -3084,7 +3318,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
return false;
}
if (initializer->constant)
if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
{
ConstInitializer *const_init = CALLOCS(ConstInitializer);
const_init->kind = CONST_INIT_ARRAY_FULL;
@@ -3113,21 +3347,18 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
static inline bool sema_expr_analyse_untyped_initializer(Context *context, Expr *initializer)
{
initializer->pure = true;
initializer->constant = true;
Expr **elements = initializer->initializer_list;
unsigned size = vec_size(elements);
Type *element_type = NULL;
bool no_common_elements = false;
VECEACH(elements, i)
unsigned element_count = vec_size(elements);
for (unsigned i = 0; i < element_count; i++)
{
Expr *element = elements[i];
if (!sema_analyse_expr(context, NULL, element)) return false;
initializer->failable |= element->failable;
initializer->pure &= element->pure;
initializer->constant &= element->constant;
if (no_common_elements) continue;
if (element_type == NULL)
{
@@ -3137,7 +3368,13 @@ static inline bool sema_expr_analyse_untyped_initializer(Context *context, Expr
element_type = type_find_max_type(element->type, element_type);
if (!element_type) no_common_elements = true;
}
TODO
if (no_common_elements || type_is_ct(element_type))
{
expr_set_type(initializer, type_complist);
return true;
}
expr_set_type(initializer, type_get_array(element_type, element_count));
return true;
}
static inline bool sema_expr_analyse_initializer(Context *context, Type *external_type, Type *assigned, Expr *expr)
@@ -3167,7 +3404,6 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *externa
initializer->kind = CONST_INIT_ZERO;
initializer->type = type_flatten(expr->type);
expr_set_as_const_list(expr, initializer);
expr->constant = true;
expr->pure = true;
return true;
}
@@ -3203,8 +3439,20 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
case TYPE_UNION:
case TYPE_ARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_SUBARRAY:
return sema_expr_analyse_initializer(context, to, assigned, expr);
case TYPE_SUBARRAY:
{
// Resolve this as an inferred array.
Type *type = type_get_inferred_array(assigned->array.base);
if (!sema_expr_analyse_initializer(context, type, type, expr)) return false;
expr->resolve_status = RESOLVE_DONE;
expr_insert_addr(expr);
if (!sema_analyse_expr(context, NULL, expr)) return false;
return cast(expr, to);
}
case TYPE_POINTER:
SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array.");
return false;
default:
break;
}
@@ -3226,11 +3474,9 @@ static inline bool sema_expr_analyse_expr_list(Context *context, Type *to, Expr
Expr *checked_expr = expr->expression_list[i];
success &= sema_analyse_expr_of_required_type(context, i == last ? to : NULL, checked_expr, 0);
expr->failable |= checked_expr->failable;
constant &= checked_expr->constant;
pure &= checked_expr->pure;
}
expr->pure = pure;
expr->constant = constant;
return success;
}
@@ -3240,7 +3486,6 @@ static inline bool sema_expr_analyse_cast(Context *context, Type *to, Expr *expr
bool success = sema_resolve_type_info(context, expr->cast_expr.type_info);
success &= sema_analyse_expr(context, NULL, inner);
expr->pure = inner->pure;
expr->constant = inner->constant;
if (!success) return false;
Type *target_type = expr->cast_expr.type_info->type;
@@ -3413,7 +3658,6 @@ static bool sema_expr_analyse_ct_type_identifier_assign(Context *context, Expr *
*/
static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, Expr *right)
{
expr->constant = false;
expr->pure = false;
@@ -3493,7 +3737,6 @@ static bool sema_expr_analyse_ct_common_assign(Context *context, Expr *expr, Exp
static bool sema_expr_analyse_common_assign(Context *context, Expr *expr, Expr *left, Expr *right, bool int_only)
{
expr->pure = false;
expr->constant = false;
if (left->expr_kind == EXPR_CT_IDENT)
{
@@ -3604,7 +3847,6 @@ static bool sema_expr_analyse_add_sub_assign(Context *context, Expr *expr, Expr
// 3. Copy type & set properties.
expr_copy_types(expr, left);
expr->pure = false;
expr->constant = false;
expr->failable = left->failable | right->failable;
@@ -3701,6 +3943,24 @@ static void unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type **
*right_type_ref = *left_type_ref;
}
}
static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff)
{
// Do we have (iptr)(ptr) +- rhs? If so we change it to
// (iptr)((char*)(ptr) +- 1)
if (maybe_pointer->expr_kind == EXPR_CAST
&& maybe_pointer->cast_expr.kind == CAST_PTRXI
&& type_flatten(maybe_pointer->type) == type_flatten(type_iptr)
&& cast_may_implicit(maybe_diff->type, maybe_diff->type))
{
Type *cast_to_iptr = maybe_pointer->type;
maybe_pointer->cast_expr.kind = CAST_PTRPTR;
maybe_pointer->type = type_get_ptr(type_char);
return cast_to_iptr;
}
return NULL;
}
/**
* Analyse a - b
* @return true if analysis succeeded
@@ -3710,6 +3970,10 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
// 1. Analyse a and b.
if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false;
// Do we have (iptr)(ptr) - rhs? If so we change it to
// (iptr)((char*)(ptr) - 1)
Type *cast_to_iptr = defer_iptr_cast(left, right);
Type *left_type = left->type->canonical;
Type *right_type = right->type->canonical;
@@ -3759,7 +4023,11 @@ static bool sema_expr_analyse_sub(Context *context, Type *to, Expr *expr, Expr *
// 7. Assign the type of the left side.
expr_copy_types(expr, left);
expr_unify_binary_properties(expr, left, right);
if (cast_to_iptr)
{
expr->resolve_status = RESOLVE_DONE;
return cast(expr, cast_to_iptr);
}
return true;
}
@@ -3804,6 +4072,9 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
// this is safe in the pointer case actually.
if (!sema_expr_analyse_binary_sub_expr(context, to, left, right)) return false;
Type *cast_to_iptr = defer_iptr_cast(left, right);
if (!cast_to_iptr) cast_to_iptr = defer_iptr_cast(right, left);
Type *left_type = left->type->canonical;
Type *right_type = right->type->canonical;
@@ -3843,9 +4114,16 @@ static bool sema_expr_analyse_add(Context *context, Type *to, Expr *expr, Expr *
// 3c. Set the type and other properties.
expr_copy_types(expr, left);
expr_unify_binary_properties(expr, left, right);
if (cast_to_iptr)
{
expr->resolve_status = RESOLVE_DONE;
return cast(expr, cast_to_iptr);
}
return true;
}
assert(!cast_to_iptr);
// 4. Do an binary arithmetic promotion
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s."))
{
@@ -4095,7 +4373,6 @@ static bool sema_expr_analyse_shift(Context *context, Type *to, Expr *expr, Expr
if (!cast_implicit(left, numeric_arithmetic_promotion(left->type))) return false;
expr->pure = left->pure & right->pure;
expr->constant = left->constant & right->constant;
expr->failable = left->failable | right->failable;
// 5. For a constant right hand side we will make a series of checks.
@@ -4178,7 +4455,6 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l
if (!sema_expr_analyse_binary_sub_expr(context, NULL, left, right)) return false;
expr->pure = false;
expr->constant = false;
expr->failable = left->failable | right->failable;
// 2. Ensure the left hand side is assignable
@@ -4487,7 +4763,6 @@ static bool sema_take_addr_of(Expr *inner, bool *is_constant)
case EXPR_CONST_IDENTIFIER:
return sema_take_addr_of_ident(inner, is_constant);
case EXPR_UNARY:
*is_constant = inner->constant;
if (inner->unary_expr.operator == UNARYOP_DEREF) return true;
break;
case EXPR_ACCESS:
@@ -4498,12 +4773,10 @@ static bool sema_take_addr_of(Expr *inner, bool *is_constant)
{
bool index_was_const = false;
if (!sema_take_addr_of(inner->subscript_expr.expr, &index_was_const)) return false;
*is_constant = index_was_const && inner->constant;
return true;
}
case EXPR_SLICE:
{
*is_constant = false;
bool dummy;
return sema_take_addr_of(inner->slice_expr.expr, &dummy);
}
@@ -4540,7 +4813,6 @@ static bool sema_expr_analyse_addr(Context *context, Type *to, Expr *expr, Expr
// 3. Get the pointer of the underlying type.
expr_set_type(expr, type_get_ptr(inner->type));
expr->constant = is_constant;
expr->pure = inner->pure;
expr->failable = inner->failable;
@@ -4697,8 +4969,7 @@ static inline bool sema_expr_analyse_ct_incdec(Context *context, Expr *expr, Exp
* @return false if analysis fails.
*/
static inline bool sema_expr_analyse_incdec(Context *context, Expr *expr, Expr *inner)
{
expr->constant = false;
{;
expr->pure = false;
expr->failable = inner->failable;
@@ -4865,7 +5136,6 @@ static inline bool sema_expr_analyse_post_unary(Context *context, Type *to, Expr
static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bool implicitly_create_variable)
{
expr->constant = false;
Expr *init = expr->try_assign_expr.init;
Expr *lhs = expr->try_assign_expr.expr;
@@ -4935,7 +5205,7 @@ static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bo
if (!sema_analyse_expr_value(context, NULL, lhs)) return false;
}
expr->constant = false;
expr->pure = init->pure & lhs->pure;
expr_set_type(expr, type_bool);
return true;
@@ -4945,7 +5215,7 @@ static inline bool sema_expr_analyse_try(Context *context, Expr *expr)
Expr *inner = expr->try_expr.expr;
if (!sema_analyse_expr(context, NULL, inner)) return false;
expr->pure = inner->pure;
expr->constant = false;
if (!inner->failable)
{
SEMA_ERROR(expr->try_expr.expr, "Expected a failable expression to '%s'.", expr->expr_kind == EXPR_TRY ? "try" : "catch");
@@ -4960,7 +5230,7 @@ static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr
Expr *inner = expr->else_expr.expr;
bool success = sema_analyse_expr(context, to, inner);
expr->pure = inner->pure;
expr->constant = false;
if (!success) return false;
Type *type = inner->type;
if (!inner->failable)
@@ -4997,7 +5267,7 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp
if (!success) return false;
expr_copy_types(expr, inner);
expr->pure = false;
expr->constant = false;
if (!inner->failable)
{
SEMA_ERROR(expr, "No failable to rethrow before '!!' in the expression, please remove '!!'.");
@@ -5013,7 +5283,6 @@ static inline bool sema_expr_analyse_guard(Context *context, Type *to, Expr *exp
static inline bool sema_expr_analyse_const(Type *to, Expr *expr)
{
expr->constant = true;
expr->pure = true;
return true;
}
@@ -5089,7 +5358,7 @@ static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr
expr->failable = context->expr_failable_return;
context->expr_failable_return = saved_expr_failable_return;
context->expected_block_type = prev_expected_block_type;
expr->constant = false;
expr->pure = false;
return success;
}
@@ -5109,7 +5378,7 @@ static inline bool sema_expr_analyse_typeof(Context *context, Expr *expr)
TODO
if (!sema_analyse_expr(context, NULL, expr->typeof_expr)) return false;
expr->pure = expr->typeof_expr->pure;
expr->constant = expr->typeof_expr->constant;
Type *type = expr->typeof_expr->type->canonical;
expr->expr_kind = EXPR_TYPEID;
expr->typeid_expr = type_info_new_base(type, expr->typeof_expr->span);
@@ -5125,7 +5394,7 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr *
if (!sema_analyse_expr(context, NULL, inner)) return false;
expr->pure = inner->pure;
expr->constant = inner->constant;
if (inner->failable)
{
SEMA_ERROR(inner, "The inner expression is already a failable.");
@@ -5984,7 +6253,7 @@ static inline bool sema_expr_analyse_decl(Context *context, Type *to, Expr *expr
if (!sema_analyse_var_decl(context, expr->decl_expr)) return false;
expr_set_type(expr, expr->decl_expr->type);
expr->pure = !expr->decl_expr->var.init_expr || expr->decl_expr->var.init_expr->pure;
expr->constant = expr->decl_expr->var.kind == VARDECL_CONST;
return true;
}
static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *expr)
@@ -6041,7 +6310,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
case EXPR_GUARD:
return sema_expr_analyse_guard(context, to, expr);
case EXPR_CONST:
case EXPR_BYTES:
return sema_expr_analyse_const(to, expr);
case EXPR_BINARY:
if (!sema_expr_analyse_binary(context, to, expr)) return false;

View File

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

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 (!expr_is_constant_eval(decl->var.init_expr))
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
{
SEMA_ERROR(decl->var.init_expr, "Static variable initialization must be constant.");
return false;
@@ -762,9 +762,9 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
if (decl->var.init_expr)
{
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false;
if (decl->var.init_expr->expr_kind != EXPR_CONST)
if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_ANY))
{
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here.");
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
return false;
}
}
@@ -776,12 +776,13 @@ static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
}
else
{
if (decl->var.init_expr)
Expr *init = decl->var.init_expr;
if (init)
{
if (!sema_analyse_expr(context, NULL, decl->var.init_expr)) return false;
if (decl->var.init_expr->expr_kind != EXPR_CONST)
if (!sema_analyse_expr(context, NULL, init)) return false;
if (!expr_is_constant_eval(init, CONSTANT_EVAL_ANY))
{
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here.");
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression assigned to %s.", decl->name);
return false;
}
decl->type = decl->var.init_expr->type;

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

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
%"char[]" = type { i8*, i64 }
%"double[]" = type { double*, i64 }
@fasta.IM = constant i32 139968, align 1
@fasta.IA = constant i32 3877, align 1
@@ -115,12 +117,12 @@ func void main(int argc, char **argv)
@fasta.alu = protected global %"char[]" { i8* getelementptr inbounds ([288 x i8], [288 x i8]* @.str, i32 0, i32 0), i64 287 }, align 8
@.str.11 = private constant [16 x i8] c"acgtBDHKMNRSVWY\00", align 1
@fasta.iub = global %"char[]" { i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.11, i32 0, i32 0), i64 15 }, align 8
@.__const = private constant [15 x double] [double 2.700000e-01, double 1.200000e-01, double 1.200000e-01, double 2.700000e-01, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02], align 8
@fasta.iub_p = global %"double[]" { %"double[]"* bitcast ([15 x double]* @.__const to %"double[]"*), i64 15 }, align 8
@.taddr = private hidden global [15 x double] [double 2.700000e-01, double 1.200000e-01, double 1.200000e-01, double 2.700000e-01, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02, double 2.000000e-02], align 8
@fasta.iub_p = global %"double[]" { double* getelementptr inbounds ([15 x double], [15 x double]* @.taddr, i32 0, i32 0), i64 15 }, align 8
@.str.12 = private constant [5 x i8] c"acgt\00", align 1
@fasta.homosapiens = global %"char[]" { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0), i64 4 }, align 8
@.__const.13 = private constant [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8
@fasta.homosapiens_p = global %"double[]" { %"double[]"* bitcast ([4 x double]* @.__const.13 to %"double[]"*), i64 4 }, align 8
@.taddr.13 = private hidden global [4 x double] [double 0x3FD3639D20BAEB5B, double 0x3FC957AE3DCD561B, double 0x3FC9493AEAB6C2BF, double 0x3FD34BEE4B030838], align 8
@fasta.homosapiens_p = global %"double[]" { double* getelementptr inbounds ([4 x double], [4 x double]* @.taddr.13, i32 0, i32 0), i64 4 }, align 8
@fasta.LINELEN = constant i32 60, align 1
@.str.14 = private constant [23 x i8] c">ONE Homo sapiens alu\0A\00", align 1
@.str.15 = private constant [26 x i8] c">TWO IUB ambiguity codes\0A\00", align 1
@@ -381,4 +383,4 @@ if.exit: ; preds = %if.then, %entry
%mul10 = mul i32 %11, 5
call void @fasta.random_fasta(i8* %lo6, i64 %hi7, i8* %lo8, i64 %hi9, i32 %mul10)
ret void
}
}

View File

@@ -1,4 +1,4 @@
// #skip
// #target: x64-darwin
union Baz
{
@@ -16,7 +16,11 @@ func int test()
Baz ffe = { .x = 1 };
int[1] azz = {};
int[*] a = {};
var $foo = { 1, 2, 3 };
var $foo = { 11, 22, 33 };
static int foo1 = $foo[1];
int foo2 = $foo[2];
var $foos = { "Hello!" };
char* str = $foos[0];
bool x = ! int[] { 1, 2, 3 };
Bar b = {};
Baz z = {};
@@ -24,4 +28,81 @@ func int test()
Bar[] foo = {};
Baz[3] baz = {};
return 1;
}
}
// #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
%Bar = type { i32, i32 }
%Baz = type { double }
%"int[]" = type { i32*, i64 }
%"Bar[]" = type { %Bar*, i64 }
@Baz = linkonce_odr constant i8 1
@Bar = linkonce_odr constant i8 1
; Function Attrs: nounwind
define i32 @zero_init.test() #0 {
entry:
%azz = alloca [1 x i32], align 4
@@ -31,7 +40,9 @@ entry:
%b = alloca %Bar, align 4
%z = alloca %Baz, align 8
%sub = alloca %"int[]", align 8
%literal = alloca [0 x i32], align 4
%foo = alloca %"Bar[]", align 8
%literal1 = alloca [0 x %Bar], align 4
%baz = alloca [3 x %Baz], align 16
%0 = bitcast [1 x i32]* %azz to i8*
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
@@ -41,11 +52,17 @@ entry:
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 8, i1 false)
%3 = bitcast %Baz* %z to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
%4 = bitcast %"int[]"* %sub to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 16, i1 false)
%5 = bitcast %"Bar[]"* %foo to i8*
call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 16, i1 false)
%6 = bitcast [3 x %Baz]* %baz to i8*
call void @llvm.memset.p0i8.i64(i8* align 16 %6, i8 0, i64 24, i1 false)
store [0 x i32] zeroinitializer, [0 x i32]* %literal, align 4
%4 = bitcast [0 x i32]* %literal to i32*
%5 = insertvalue %"int[]" undef, i32* %4, 0
%6 = insertvalue %"int[]" %5, i64 0, 1
store %"int[]" %6, %"int[]"* %sub, align 8
store [0 x %Bar] zeroinitializer, [0 x %Bar]* %literal1, align 4
%7 = bitcast [0 x %Bar]* %literal1 to %Bar*
%8 = insertvalue %"Bar[]" undef, %Bar* %7, 0
%9 = insertvalue %"Bar[]" %8, i64 0, 1
store %"Bar[]" %9, %"Bar[]"* %foo, align 8
%10 = bitcast [3 x %Baz]* %baz to i8*
call void @llvm.memset.p0i8.i64(i8* align 16 %10, i8 0, i64 24, i1 false)
ret i32 1
}
}

View File

@@ -15,10 +15,17 @@ func Event test(int x)
// #expect: test.ll
@Event = linkonce_odr constant i8 1
@.__const = private constant %Event { i32 1 }, align 4
@.__const.1 = private constant %Event { i32 2 }, align 4
; Function Attrs: nounwind
define i32 @test.test(i32 %0) #0 {
entry:
%x = alloca i32, align 4
%foo = alloca %Event, align 4
%bar = alloca %Event, align 4
%tempaddr = alloca %Event, align 4
%taddr = alloca %Event, align 4
store i32 %0, i32* %x, align 4
%1 = bitcast %Event* %foo to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 bitcast (%Event* @.__const to i8*), i32 4, i1 false)
@@ -28,17 +35,18 @@ func Event test(int x)
%intbool = icmp ne i32 %3, 0
br i1 %intbool, label %cond.lhs, label %cond.rhs
cond.lhs:
cond.lhs: ; preds = %entry
%4 = load %Event, %Event* %foo, align 4
br label %cond.phi
cond.rhs:
cond.rhs: ; preds = %entry
%5 = load %Event, %Event* %bar, align 4
br label %cond.phi
cond.phi:
cond.phi: ; preds = %cond.rhs, %cond.lhs
%val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ]
store %Event %val, %Event* %tempaddr, align 4
%dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0
store %Event %val, %Event* %taddr, align 4
%dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0
%6 = load i32, i32* %dive, align 4
ret i32 %6
ret i32 %6
}

View File

@@ -18,7 +18,7 @@ func Event test(int x)
%x = alloca i32, align 4
%foo = alloca %Event, align 4
%bar = alloca %Event, align 4
%tempaddr = alloca %Event, align 4
%taddr = alloca %Event, align 4
store i32 %0, i32* %x, align 4
%1 = bitcast %Event* %foo to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 bitcast (%Event* @.__const to i8*), i32 4, i1 false)
@@ -38,8 +38,8 @@ cond.rhs:
cond.phi:
%val = phi %Event [ %4, %cond.lhs ], [ %5, %cond.rhs ]
store %Event %val, %Event* %tempaddr, align 4
%dive = getelementptr inbounds %Event, %Event* %tempaddr, i32 0, i32 0
store %Event %val, %Event* %taddr, align 4
%dive = getelementptr inbounds %Event, %Event* %taddr, i32 0, i32 0
%6 = load i32, i32* %dive, align 4
%7 = zext i32 %6 to i64
ret i64 %7

View File

@@ -1,5 +1,19 @@
// #target: x64-darwin
module test;
struct Foo
{
char c;
union {
int a;
double b;
}
int z;
}
Foo foo1 = { .a = 3, .z = 4 };
Foo foo2 = { .b = 3, .z = 4 };
struct Blend_Map_Entry
{
union vals {
@@ -23,6 +37,8 @@ func void test(Blend_Map_Entry* foo)
%Blend_Map_Entry = type { %vals }
%vals = type { [2 x double], [8 x i8] }
@test.foo1 = global { i8, [4 x i8], { i32, [4 x i8] }, i32 } { i8 0, [4 x i8] undef, { i32, [4 x i8] } { i32 3, [4 x i8] undef }, i32 4 }, align 8
@test.foo2 = global %Foo { i8 0, %anon { double 3.000000e+00 }, i32 4 }, align 8
@test.a = global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8
@test.b = global %Blend_Map_Entry { %vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8
@test.c = global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8