IR: support compile time global pointer reinterpret

this required moving the place we store types to ConstExprValue
This commit is contained in:
Andrew Kelley 2016-12-25 04:15:23 -05:00
parent 6f91fb4c37
commit f47dea2a2e
9 changed files with 1092 additions and 940 deletions

View File

@ -131,6 +131,7 @@ enum RuntimeHintMaybe {
};
struct ConstExprValue {
TypeTableEntry *type;
ConstValSpecial special;
bool depends_on_compile_var;
LLVMValueRef llvm_value;
@ -429,8 +430,6 @@ enum CastOp {
CastOpPtrToInt,
CastOpIntToPtr,
CastOpWidenOrShorten,
CastOpToUnknownSizeArray,
CastOpPointerReinterpret,
CastOpErrToInt,
CastOpIntToFloat,
CastOpFloatToInt,
@ -749,14 +748,9 @@ struct FnTypeParamInfo {
TypeTableEntry *type;
};
struct GenericParamValue {
TypeTableEntry *type;
ConstExprValue *value;
};
struct GenericFnTypeId {
FnTableEntry *fn_entry;
GenericParamValue *params;
ConstExprValue *params;
size_t param_count;
};
@ -1238,7 +1232,7 @@ struct CodeGen {
// TODO after merging IR branch, we can probably delete some of these fields
struct VariableTableEntry {
Buf name;
TypeTableEntry *type;
ConstExprValue value;
LLVMValueRef value_ref;
bool src_is_const;
bool gen_is_const;
@ -1254,7 +1248,6 @@ struct VariableTableEntry {
bool shadowable;
size_t mem_slot_index;
size_t ref_count;
ConstExprValue *value;
bool is_extern;
};
@ -1460,14 +1453,14 @@ enum IrInstructionId {
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
IrInstructionIdInitEnum,
IrInstructionIdPointerReinterpret,
};
struct IrInstruction {
IrInstructionId id;
Scope *scope;
AstNode *source_node;
ConstExprValue static_value;
TypeTableEntry *type_entry;
ConstExprValue value;
size_t debug_id;
LLVMValueRef llvm_value;
// if ref_count is zero, instruction can be omitted in codegen
@ -1986,6 +1979,7 @@ struct IrInstructionSlice {
IrInstruction *start;
IrInstruction *end;
bool is_const;
bool safety_check_on;
LLVMValueRef tmp_ptr;
};
@ -2096,6 +2090,12 @@ struct IrInstructionInitEnum {
LLVMValueRef tmp_ptr;
};
struct IrInstructionPointerReinterpret {
IrInstruction base;
IrInstruction *ptr;
};
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,

View File

@ -876,11 +876,11 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
if (result->type_entry->id == TypeTableEntryIdInvalid)
if (result->value.type->id == TypeTableEntryIdInvalid)
return g->builtin_types.entry_invalid;
assert(result->static_value.special != ConstValSpecialRuntime);
return result->static_value.data.x_type;
assert(result->value.special != ConstValSpecialRuntime);
return result->value.data.x_type;
}
static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
@ -1708,41 +1708,42 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
// Set name to nullptr to make the variable anonymous (not visible to programmer).
// TODO merge with definition of add_local_var in ir.cpp
VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value)
bool is_const, ConstExprValue *value)
{
assert(value);
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
variable_entry->type = type_entry;
variable_entry->value = *value;
variable_entry->parent_scope = parent_scope;
variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->value = init_value;
variable_entry->src_arg_index = SIZE_MAX;
assert(name);
buf_init_from_buf(&variable_entry->name, name);
if (type_entry->id != TypeTableEntryIdInvalid) {
if (value->type->id != TypeTableEntryIdInvalid) {
VariableTableEntry *existing_var = find_variable(g, parent_scope, name);
if (existing_var && !existing_var->shadowable) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
variable_entry->type = g->builtin_types.entry_invalid;
variable_entry->value.type = g->builtin_types.entry_invalid;
} else {
auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
if (primitive_table_entry) {
TypeTableEntry *type = primitive_table_entry->value;
add_node_error(g, source_node,
buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
variable_entry->type = g->builtin_types.entry_invalid;
variable_entry->value.type = g->builtin_types.entry_invalid;
} else {
Tld *tld = find_decl(parent_scope, name);
if (tld && tld->id != TldIdVar) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
variable_entry->type = g->builtin_types.entry_invalid;
variable_entry->value.type = g->builtin_types.entry_invalid;
}
}
}
@ -1789,7 +1790,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
} else if (var_decl->expr) {
init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
assert(init_value);
implicit_type = init_value->type_entry;
implicit_type = init_value->value.type;
if (implicit_type->id == TypeTableEntryIdUnreachable) {
add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
@ -1807,7 +1808,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
implicit_type = g->builtin_types.entry_invalid;
}
assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->static_value.special != ConstValSpecialRuntime);
assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->value.special != ConstValSpecialRuntime);
} else if (!is_extern) {
add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
implicit_type = g->builtin_types.entry_invalid;
@ -1816,8 +1817,9 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
TypeTableEntry *type = explicit_type ? explicit_type : implicit_type;
assert(type != nullptr); // should have been caught by the parser
tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope,
var_decl->symbol, type, is_const, &init_value->static_value);
ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, is_const, init_val);
tld_var->var->is_extern = is_extern;
g->global_vars.append(tld_var->var);
@ -2231,7 +2233,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
buf_sprintf("byvalue types not yet supported on extern function parameters"));
}
VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, param_decl->name, param_type, true, nullptr);
VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
param_decl->name, true, create_const_runtime(param_type));
var->src_arg_index = i;
fn_table_entry->child_scope = var->child_scope;
@ -2287,14 +2290,14 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
static void add_symbols_from_import(CodeGen *g, AstNode *dst_use_node) {
IrInstruction *use_target_value = dst_use_node->data.use.value;
if (use_target_value->type_entry->id == TypeTableEntryIdInvalid) {
if (use_target_value->value.type->id == TypeTableEntryIdInvalid) {
dst_use_node->owner->any_imports_failed = true;
return;
}
dst_use_node->data.use.resolution = TldResolutionOk;
ConstExprValue *const_val = &use_target_value->static_value;
ConstExprValue *const_val = &use_target_value->value;
assert(const_val->special != ConstValSpecialRuntime);
ImportTableEntry *target_import = const_val->data.x_import;
@ -2351,7 +2354,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
if (result->type_entry->id == TypeTableEntryIdInvalid)
if (result->value.type->id == TypeTableEntryIdInvalid)
node->owner->any_imports_failed = true;
node->data.use.value = result;
@ -2620,8 +2623,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
return true;
}
static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) {
switch (type->id) {
static uint32_t hash_const_val(ConstExprValue *const_val) {
assert(const_val->special == ConstValSpecialStatic);
switch (const_val->type->id) {
case TypeTableEntryIdBool:
return const_val->data.x_bool ? 127863866 : 215080464;
case TypeTableEntryIdMetaType:
@ -2630,6 +2634,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
return 4149439618;
case TypeTableEntryIdInt:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdEnumTag:
return ((uint32_t)(bignum_to_twos_complement(&const_val->data.x_bignum) % UINT32_MAX)) * 1331471175;
case TypeTableEntryIdFloat:
case TypeTableEntryIdNumLitFloat:
@ -2651,8 +2656,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
return 2709806591;
case TypeTableEntryIdMaybe:
if (const_val->data.x_maybe) {
TypeTableEntry *child_type = type->data.maybe.child_type;
return hash_const_val(child_type, const_val->data.x_maybe) * 1992916303;
return hash_const_val(const_val->data.x_maybe) * 1992916303;
} else {
return 4016830364;
}
@ -2673,8 +2677,6 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
return hash_ptr(const_val->data.x_import);
case TypeTableEntryIdBlock:
return hash_ptr(const_val->data.x_block);
case TypeTableEntryIdEnumTag:
return 983996406 + hash_const_val(type->data.enum_tag.int_type, const_val);
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdUnreachable:
@ -2688,9 +2690,9 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {
uint32_t result = 0;
result += hash_ptr(id->fn_entry);
for (size_t i = 0; i < id->param_count; i += 1) {
GenericParamValue *generic_param = &id->params[i];
if (generic_param->value) {
result += hash_const_val(generic_param->type, generic_param->value);
ConstExprValue *generic_param = &id->params[i];
if (generic_param->special != ConstValSpecialRuntime) {
result += hash_const_val(generic_param);
result += hash_ptr(generic_param->type);
}
}
@ -2702,17 +2704,17 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
if (a->fn_entry != b->fn_entry) return false;
assert(a->param_count == b->param_count);
for (size_t i = 0; i < a->param_count; i += 1) {
GenericParamValue *a_val = &a->params[i];
GenericParamValue *b_val = &b->params[i];
ConstExprValue *a_val = &a->params[i];
ConstExprValue *b_val = &b->params[i];
if (a_val->type != b_val->type) return false;
if (a_val->value && b_val->value) {
assert(a_val->value->special == ConstValSpecialStatic);
assert(b_val->value->special == ConstValSpecialStatic);
if (!const_values_equal(a_val->value, b_val->value, a_val->type)) {
if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
assert(a_val->special == ConstValSpecialStatic);
assert(b_val->special == ConstValSpecialStatic);
if (!const_values_equal(a_val, b_val)) {
return false;
}
} else {
assert(!a_val->value && !b_val->value);
assert(a_val->special == ConstValSpecialRuntime && b_val->special == ConstValSpecialRuntime);
}
}
return true;
@ -2723,7 +2725,7 @@ uint32_t fn_eval_hash(Scope* scope) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
result += hash_const_val(var_scope->var->type, var_scope->var->value);
result += hash_const_val(&var_scope->var->value);
} else if (scope->id == ScopeIdFnDef) {
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
result += hash_ptr(fn_scope->fn_entry);
@ -2745,9 +2747,9 @@ bool fn_eval_eql(Scope *a, Scope *b) {
if (a->id == ScopeIdVarDecl) {
ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
if (a_var_scope->var->type != b_var_scope->var->type)
if (a_var_scope->var->value.type != b_var_scope->var->value.type)
return false;
if (!const_values_equal(a_var_scope->var->value, b_var_scope->var->value, a_var_scope->var->type))
if (!const_values_equal(&a_var_scope->var->value, &b_var_scope->var->value))
return false;
} else if (a->id == ScopeIdFnDef) {
ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
@ -2865,77 +2867,187 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) {
return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref);
}
void init_const_str_lit(ConstExprValue *const_val, Buf *str) {
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
const_val->special = ConstValSpecialStatic;
const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
const_val->data.x_array.elements = allocate<ConstExprValue>(buf_len(str));
const_val->data.x_array.size = buf_len(str);
for (size_t i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &const_val->data.x_array.elements[i];
this_char->special = ConstValSpecialStatic;
this_char->type = g->builtin_types.entry_u8;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
}
}
ConstExprValue *create_const_str_lit(Buf *str) {
ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_str_lit(const_val, str);
init_const_str_lit(g, const_val, str);
return const_val;
}
void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative) {
void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
// first we build the underlying array
size_t len_with_null = buf_len(str) + 1;
ConstExprValue *array_val = allocate<ConstExprValue>(1);
array_val->special = ConstValSpecialStatic;
array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null);
array_val->data.x_array.elements = allocate<ConstExprValue>(len_with_null);
array_val->data.x_array.size = len_with_null;
for (size_t i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &array_val->data.x_array.elements[i];
this_char->special = ConstValSpecialStatic;
this_char->type = g->builtin_types.entry_u8;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
}
ConstExprValue *null_char = &array_val->data.x_array.elements[len_with_null - 1];
null_char->special = ConstValSpecialStatic;
null_char->type = g->builtin_types.entry_u8;
bignum_init_unsigned(&null_char->data.x_bignum, 0);
// then make the pointer point to it
const_val->special = ConstValSpecialStatic;
const_val->type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
const_val->data.x_ptr.base_ptr = array_val;
const_val->data.x_ptr.index = 0;
const_val->data.x_ptr.special = ConstPtrSpecialCStr;
}
ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_c_str_lit(g, const_val, str);
return const_val;
}
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
bignum_init_unsigned(&const_val->data.x_bignum, x);
const_val->data.x_bignum.is_negative = negative;
}
ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative) {
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_unsigned_negative(const_val, x, negative);
init_const_unsigned_negative(const_val, type, x, negative);
return const_val;
}
void init_const_signed(ConstExprValue *const_val, int64_t x) {
void init_const_usize(CodeGen *g, ConstExprValue *const_val, uint64_t x) {
return init_const_unsigned_negative(const_val, g->builtin_types.entry_usize, x, false);
}
ConstExprValue *create_const_usize(CodeGen *g, uint64_t x) {
return create_const_unsigned_negative(g->builtin_types.entry_usize, x, false);
}
void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
bignum_init_signed(&const_val->data.x_bignum, x);
}
ConstExprValue *create_const_signed(int64_t x) {
ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_signed(const_val, x);
init_const_signed(const_val, type, x);
return const_val;
}
void init_const_float(ConstExprValue *const_val, double value) {
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
bignum_init_float(&const_val->data.x_bignum, value);
}
ConstExprValue *create_const_float(double value) {
ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_float(const_val, value);
init_const_float(const_val, type, value);
return const_val;
}
void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag) {
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
const_val->data.x_enum.tag = tag;
}
ConstExprValue *create_const_enum_tag(uint64_t tag) {
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_enum_tag(const_val, tag);
init_const_enum_tag(const_val, type, tag);
return const_val;
}
void init_const_bool(ConstExprValue *const_val, bool value) {
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) {
const_val->special = ConstValSpecialStatic;
const_val->type = g->builtin_types.entry_bool;
const_val->data.x_bool = value;
}
ConstExprValue *create_const_bool(bool value) {
ConstExprValue *create_const_bool(CodeGen *g, bool value) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_bool(const_val, value);
init_const_bool(g, const_val, value);
return const_val;
}
void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type) {
const_val->special = ConstValSpecialRuntime;
const_val->type = type;
}
ConstExprValue *create_const_runtime(TypeTableEntry *type) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_runtime(const_val, type);
return const_val;
}
void init_const_type(CodeGen *g, ConstExprValue *const_val, TypeTableEntry *type_value) {
const_val->special = ConstValSpecialStatic;
const_val->type = g->builtin_types.entry_type;
const_val->data.x_type = type_value;
}
ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_type(g, const_val, type_value);
return const_val;
}
void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
size_t start, size_t len, bool is_const)
{
assert(array_val->type->id == TypeTableEntryIdArray);
const_val->special = ConstValSpecialStatic;
const_val->type = get_slice_type(g, array_val->type->data.array.child_type, is_const);
const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
init_const_ptr(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);
init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
}
ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_slice(g, const_val, array_val, start, len, is_const);
return const_val;
}
void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const) {
TypeTableEntry *child_type;
if (index == SIZE_MAX) {
child_type = base_ptr->type;
} else {
assert(base_ptr->type->id == TypeTableEntryIdArray);
child_type = base_ptr->type->data.array.child_type;
}
const_val->special = ConstValSpecialStatic;
const_val->type = get_pointer_to_type(g, child_type, is_const);
const_val->data.x_ptr.base_ptr = base_ptr;
const_val->data.x_ptr.index = index;
}
ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t index, bool is_const) {
ConstExprValue *const_val = allocate<ConstExprValue>(1);
init_const_ptr(g, const_val, base_ptr, index, is_const);
return const_val;
}
@ -2956,18 +3068,21 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
if (!var->is_comptime)
return false;
if (var->is_comptime->other)
return var->is_comptime->other->static_value.data.x_bool;
return var->is_comptime->static_value.data.x_bool;
return var->is_comptime->other->value.data.x_bool;
return var->is_comptime->value.data.x_bool;
}
bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
switch (type_entry->id) {
bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
assert(a->type == b->type);
assert(a->special == ConstValSpecialStatic);
assert(b->special == ConstValSpecialStatic);
switch (a->type->id) {
case TypeTableEntryIdEnum:
{
ConstEnumValue *enum1 = &a->data.x_enum;
ConstEnumValue *enum2 = &b->data.x_enum;
if (enum1->tag == enum2->tag) {
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
TypeEnumField *enum_field = &a->type->data.enumeration.fields[enum1->tag];
if (type_has_bits(enum_field->type_entry)) {
zig_panic("TODO const expr analyze enum special value for equality");
} else {
@ -2990,9 +3105,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
case TypeTableEntryIdFloat:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
case TypeTableEntryIdEnumTag:
return const_values_equal(a, b, type_entry->data.enum_tag.int_type);
return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
case TypeTableEntryIdPointer:
zig_panic("TODO");
case TypeTableEntryIdArray:

View File

@ -66,7 +66,7 @@ FnTableEntry *scope_fn_entry(Scope *scope);
ImportTableEntry *get_scope_import(Scope *scope);
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value);
bool is_const, ConstExprValue *init_value);
TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
FnTableEntry *create_fn(AstNode *proto_node);
FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage);
@ -77,7 +77,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry);
void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry);
void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
bool ir_get_var_is_comptime(VariableTableEntry *var);
bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
@ -88,22 +88,42 @@ Scope *create_loop_scope(AstNode *node, Scope *parent);
ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
void init_const_str_lit(ConstExprValue *const_val, Buf *str);
ConstExprValue *create_const_str_lit(Buf *str);
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative);
ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative);
void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
void init_const_signed(ConstExprValue *const_val, int64_t x);
ConstExprValue *create_const_signed(int64_t x);
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative);
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative);
void init_const_float(ConstExprValue *const_val, double value);
ConstExprValue *create_const_float(double value);
void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x);
ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x);
void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag);
ConstExprValue *create_const_enum_tag(uint64_t tag);
void init_const_usize(CodeGen *g, ConstExprValue *const_val, uint64_t x);
ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
void init_const_bool(ConstExprValue *const_val, bool value);
ConstExprValue *create_const_bool(bool value);
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
ConstExprValue *create_const_float(TypeTableEntry *type, double value);
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag);
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag);
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
ConstExprValue *create_const_bool(CodeGen *g, bool value);
void init_const_type(CodeGen *g, ConstExprValue *const_val, TypeTableEntry *type_value);
ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value);
void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type);
ConstExprValue *create_const_runtime(TypeTableEntry *type);
void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const);
ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr,
size_t index, bool is_const);
void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
size_t start, size_t len, bool is_const);
ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);
#endif

View File

@ -225,8 +225,8 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
g->linker_rdynamic = rdynamic;
}
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
static void render_const_val(CodeGen *g, ConstExprValue *const_val);
static void render_const_val_global(CodeGen *g, ConstExprValue *const_val);
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value)
@ -645,18 +645,14 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
}
static LLVMValueRef gen_assign_raw(CodeGen *g,
LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type)
static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *child_type)
{
if (!type_has_bits(op1_type)) {
if (!type_has_bits(child_type))
return nullptr;
}
if (handle_is_ptr(op1_type)) {
assert(op1_type == op2_type);
return gen_struct_memcpy(g, value, target_ref, op1_type);
}
if (handle_is_ptr(child_type))
return gen_struct_memcpy(g, value, target_ref, child_type);
LLVMBuildStore(g->builder, value, target_ref);
return nullptr;
@ -671,17 +667,17 @@ static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
}
static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
if (!type_has_bits(instruction->type_entry))
if (!type_has_bits(instruction->value.type))
return nullptr;
if (!instruction->llvm_value) {
assert(instruction->static_value.special != ConstValSpecialRuntime);
assert(instruction->type_entry);
render_const_val(g, instruction->type_entry, &instruction->static_value);
if (handle_is_ptr(instruction->type_entry)) {
render_const_val_global(g, instruction->type_entry, &instruction->static_value);
instruction->llvm_value = instruction->static_value.llvm_global;
assert(instruction->value.special != ConstValSpecialRuntime);
assert(instruction->value.type);
render_const_val(g, &instruction->value);
if (handle_is_ptr(instruction->value.type)) {
render_const_val_global(g, &instruction->value);
instruction->llvm_value = instruction->value.llvm_global;
} else {
instruction->llvm_value = instruction->static_value.llvm_value;
instruction->llvm_value = instruction->value.llvm_value;
}
assert(instruction->llvm_value);
}
@ -690,7 +686,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
TypeTableEntry *return_type = return_instruction->value->value.type;
bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
if (handle_is_ptr(return_type)) {
if (is_extern) {
@ -698,7 +694,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
LLVMBuildRet(g->builder, by_val_value);
} else {
assert(g->cur_ret_ptr);
gen_assign_raw(g, g->cur_ret_ptr, value, return_type, return_instruction->value->type_entry);
gen_assign_raw(g, g->cur_ret_ptr, value, return_type);
LLVMBuildRetVoid(g->builder);
}
} else {
@ -809,7 +805,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
assert(op1->type_entry == op2->type_entry);
assert(op1->value.type == op2->value.type);
bool want_debug_safety = bin_op_instruction->safety_check_on &&
ir_want_debug_safety(g, &bin_op_instruction->base);
@ -831,22 +827,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
case IrBinOpCmpGreaterThan:
case IrBinOpCmpLessOrEq:
case IrBinOpCmpGreaterOrEq:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
if (op1->value.type->id == TypeTableEntryIdFloat) {
LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdInt) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->type_entry->data.integral.is_signed);
} else if (op1->value.type->id == TypeTableEntryIdInt) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->value.type->data.integral.is_signed);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdEnum) {
if (op1->type_entry->data.enumeration.gen_field_count == 0) {
} else if (op1->value.type->id == TypeTableEntryIdEnum) {
if (op1->value.type->data.enumeration.gen_field_count == 0) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else {
zig_unreachable();
}
} else if (op1->type_entry->id == TypeTableEntryIdPureError ||
op1->type_entry->id == TypeTableEntryIdPointer ||
op1->type_entry->id == TypeTableEntryIdBool)
} else if (op1->value.type->id == TypeTableEntryIdPureError ||
op1->value.type->id == TypeTableEntryIdPointer ||
op1->value.type->id == TypeTableEntryIdBool)
{
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
@ -855,15 +851,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
}
case IrBinOpAdd:
case IrBinOpAddWrap:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
if (op1->value.type->id == TypeTableEntryIdFloat) {
return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdInt) {
} else if (op1->value.type->id == TypeTableEntryIdInt) {
bool is_wrapping = (op_id == IrBinOpAddWrap);
if (is_wrapping) {
return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety) {
return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return gen_overflow_op(g, op1->value.type, AddSubMulAdd, op1_value, op2_value);
} else if (op1->value.type->data.integral.is_signed) {
return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
} else {
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
@ -880,36 +876,36 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
case IrBinOpBitShiftLeft:
case IrBinOpBitShiftLeftWrap:
{
assert(op1->type_entry->id == TypeTableEntryIdInt);
assert(op1->value.type->id == TypeTableEntryIdInt);
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
if (is_wrapping) {
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety) {
return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return gen_overflow_shl_op(g, op1->value.type, op1_value, op2_value);
} else if (op1->value.type->data.integral.is_signed) {
return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
} else {
return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
}
}
case IrBinOpBitShiftRight:
assert(op1->type_entry->id == TypeTableEntryIdInt);
if (op1->type_entry->data.integral.is_signed) {
assert(op1->value.type->id == TypeTableEntryIdInt);
if (op1->value.type->data.integral.is_signed) {
return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
} else {
return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
}
case IrBinOpSub:
case IrBinOpSubWrap:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
if (op1->value.type->id == TypeTableEntryIdFloat) {
return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdInt) {
} else if (op1->value.type->id == TypeTableEntryIdInt) {
bool is_wrapping = (op_id == IrBinOpSubWrap);
if (is_wrapping) {
return LLVMBuildSub(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety) {
return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return gen_overflow_op(g, op1->value.type, AddSubMulSub, op1_value, op2_value);
} else if (op1->value.type->data.integral.is_signed) {
return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
} else {
return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
@ -919,15 +915,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
}
case IrBinOpMult:
case IrBinOpMultWrap:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
if (op1->value.type->id == TypeTableEntryIdFloat) {
return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
} else if (op1->type_entry->id == TypeTableEntryIdInt) {
} else if (op1->value.type->id == TypeTableEntryIdInt) {
bool is_wrapping = (op_id == IrBinOpMultWrap);
if (is_wrapping) {
return LLVMBuildMul(g->builder, op1_value, op2_value, "");
} else if (want_debug_safety) {
return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
} else if (op1->type_entry->data.integral.is_signed) {
return gen_overflow_op(g, op1->value.type, AddSubMulMul, op1_value, op2_value);
} else if (op1->value.type->data.integral.is_signed) {
return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
} else {
return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
@ -936,13 +932,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
case IrBinOpDiv:
return gen_div(g, want_debug_safety, op1_value, op2_value, op1->type_entry, false);
return gen_div(g, want_debug_safety, op1_value, op2_value, op1->value.type, false);
case IrBinOpMod:
if (op1->type_entry->id == TypeTableEntryIdFloat) {
if (op1->value.type->id == TypeTableEntryIdFloat) {
return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
} else {
assert(op1->type_entry->id == TypeTableEntryIdInt);
if (op1->type_entry->data.integral.is_signed) {
assert(op1->value.type->id == TypeTableEntryIdInt);
if (op1->value.type->data.integral.is_signed) {
return LLVMBuildSRem(g->builder, op1_value, op2_value, "");
} else {
return LLVMBuildURem(g->builder, op1_value, op2_value, "");
@ -955,8 +951,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
IrInstructionCast *cast_instruction)
{
TypeTableEntry *actual_type = cast_instruction->value->type_entry;
TypeTableEntry *wanted_type = cast_instruction->base.type_entry;
TypeTableEntry *actual_type = cast_instruction->value->value.type;
TypeTableEntry *wanted_type = cast_instruction->base.value.type;
LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value);
assert(expr_val);
@ -977,35 +973,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntToPtr:
return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpPointerReinterpret:
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpWidenOrShorten:
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
actual_type, wanted_type, expr_val);
case CastOpToUnknownSizeArray:
{
assert(cast_instruction->tmp_ptr);
assert(wanted_type->id == TypeTableEntryIdStruct);
assert(wanted_type->data.structure.is_slice);
TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
size_t ptr_index = wanted_type->data.structure.fields[0].gen_index;
if (ptr_index != SIZE_MAX) {
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, ptr_index, "");
LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
}
size_t len_index = wanted_type->data.structure.fields[1].gen_index;
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, len_index, "");
LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
actual_type->data.array.len, false);
LLVMBuildStore(g->builder, len_val, len_ptr);
return cast_instruction->tmp_ptr;
}
case CastOpResizeSlice:
{
assert(cast_instruction->tmp_ptr);
@ -1123,6 +1093,15 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
}
static LLVMValueRef ir_render_pointer_reinterpret(CodeGen *g, IrExecutable *executable,
IrInstructionPointerReinterpret *instruction)
{
TypeTableEntry *wanted_type = instruction->base.value.type;
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
}
static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
IrInstructionUnreachable *unreachable_instruction)
{
@ -1152,7 +1131,7 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc
static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) {
IrUnOp op_id = un_op_instruction->op_id;
LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value);
TypeTableEntry *expr_type = un_op_instruction->value->type_entry;
TypeTableEntry *expr_type = un_op_instruction->value->value.type;
switch (op_id) {
case IrUnOpInvalid:
@ -1213,7 +1192,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
{
VariableTableEntry *var = decl_var_instruction->var;
if (!type_has_bits(var->type))
if (!type_has_bits(var->value.type))
return nullptr;
if (var->ref_count == 0)
@ -1224,22 +1203,23 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
bool have_init_expr = false;
bool want_zeroes = false;
ConstExprValue *const_val = &init_value->static_value;
ConstExprValue *const_val = &init_value->value;
if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
have_init_expr = true;
if (const_val->special == ConstValSpecialZeroes)
want_zeroes = true;
if (have_init_expr) {
gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->type, init_value->type_entry);
assert(var->value.type == init_value->value.type);
gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->value.type);
} else {
bool ignore_uninit = false;
// handle runtime stack allocation
bool want_safe = ir_want_debug_safety(g, &decl_var_instruction->base);
if (!ignore_uninit && (want_safe || want_zeroes)) {
TypeTableEntry *usize = g->builtin_types.entry_usize;
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->type->type_ref);
uint64_t align_bytes = get_memcpy_align(g, var->type);
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value.type->type_ref);
uint64_t align_bytes = get_memcpy_align(g, var->value.type);
// memset uninitialized memory to 0xa
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
@ -1265,16 +1245,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
return get_handle_value(g, ptr, instruction->base.type_entry);
return get_handle_value(g, ptr, instruction->base.value.type);
}
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef value = ir_llvm_value(g, instruction->value);
assert(instruction->ptr->type_entry->id == TypeTableEntryIdPointer);
TypeTableEntry *op1_type = instruction->ptr->type_entry->data.pointer.child_type;
TypeTableEntry *op2_type = instruction->value->type_entry;
assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer);
TypeTableEntry *op1_type = instruction->ptr->value.type->data.pointer.child_type;
TypeTableEntry *op2_type = instruction->value->value.type;
if (!type_has_bits(op1_type)) {
return nullptr;
@ -1290,7 +1270,7 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
VariableTableEntry *var = instruction->var;
if (type_has_bits(var->type)) {
if (type_has_bits(var->value.type)) {
assert(var->value_ref);
return var->value_ref;
} else {
@ -1300,7 +1280,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
TypeTableEntry *array_ptr_type = instruction->array_ptr->type_entry;
TypeTableEntry *array_ptr_type = instruction->array_ptr->value.type;
assert(array_ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type);
@ -1361,7 +1341,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
} else {
assert(instruction->fn_ref);
fn_val = ir_llvm_value(g, instruction->fn_ref);
fn_type = instruction->fn_ref->type_entry;
fn_type = instruction->fn_ref->value.type;
}
TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
@ -1377,7 +1357,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
IrInstruction *param_instruction = instruction->args[call_i];
TypeTableEntry *param_type = param_instruction->type_entry;
TypeTableEntry *param_type = param_instruction->value.type;
if (is_var_args || type_has_bits(param_type)) {
LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
assert(param_value);
@ -1526,7 +1506,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
buf_append_char(&constraint_buf, ',');
}
param_types[param_index] = ir_input->type_entry->type_ref;
param_types[param_index] = ir_input->value.type->type_ref;
param_values[param_index] = ir_llvm_value(g, ir_input);
}
for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
@ -1541,7 +1521,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
if (instruction->return_count == 0) {
ret_type = LLVMVoidType();
} else {
ret_type = instruction->base.type_entry->type_ref;
ret_type = instruction->base.value.type->type_ref;
}
LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
@ -1565,13 +1545,13 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLV
static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable,
IrInstructionTestNonNull *instruction)
{
return gen_non_null_bit(g, instruction->value->type_entry, ir_llvm_value(g, instruction->value));
return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
}
static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
IrInstructionUnwrapMaybe *instruction)
{
TypeTableEntry *ptr_type = instruction->value->type_entry;
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == TypeTableEntryIdMaybe);
@ -1617,7 +1597,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
}
static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) {
TypeTableEntry *int_type = instruction->base.type_entry;
TypeTableEntry *int_type = instruction->base.value.type;
LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz);
LLVMValueRef operand = ir_llvm_value(g, instruction->value);
LLVMValueRef params[] {
@ -1628,7 +1608,7 @@ static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstru
}
static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) {
TypeTableEntry *int_type = instruction->base.type_entry;
TypeTableEntry *int_type = instruction->base.value.type;
LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz);
LLVMValueRef operand = ir_llvm_value(g, instruction->value);
LLVMValueRef params[] {
@ -1650,14 +1630,14 @@ static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, Ir
}
static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstructionPhi *instruction) {
if (!type_has_bits(instruction->base.type_entry))
if (!type_has_bits(instruction->base.value.type))
return nullptr;
LLVMTypeRef phi_type;
if (handle_is_ptr(instruction->base.type_entry)) {
phi_type = LLVMPointerType(instruction->base.type_entry->type_ref, 0);
if (handle_is_ptr(instruction->base.value.type)) {
phi_type = LLVMPointerType(instruction->base.value.type->type_ref, 0);
} else {
phi_type = instruction->base.type_entry->type_ref;
phi_type = instruction->base.value.type->type_ref;
}
LLVMValueRef phi = LLVMBuildPhi(g->builder, phi_type, "");
@ -1673,7 +1653,7 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru
static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) {
LLVMValueRef value = ir_llvm_value(g, instruction->value);
if (handle_is_ptr(instruction->value->type_entry)) {
if (handle_is_ptr(instruction->value->value.type)) {
return value;
} else {
assert(instruction->tmp_ptr);
@ -1741,17 +1721,17 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
LLVMValueRef op2_val = ir_llvm_value(g, instruction->op2);
bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);
return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.value.type, true);
}
static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {
TypeTableEntry *dest_type = get_underlying_type(instruction->base.type_entry);
TypeTableEntry *dest_type = get_underlying_type(instruction->base.value.type);
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
}
static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
TypeTableEntry *slice_type = get_underlying_type(instruction->base.type_entry);
TypeTableEntry *slice_type = get_underlying_type(instruction->base.value.type);
TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
LLVMValueRef size_val = ir_llvm_value(g, instruction->count);
@ -1814,12 +1794,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
}
static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
TypeTableEntry *array_type = get_underlying_type(instruction->ptr->type_entry);
assert(instruction->tmp_ptr);
TypeTableEntry *array_type = get_underlying_type(instruction->ptr->value.type);
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
bool want_debug_safety = instruction->safety_check_on && ir_want_debug_safety(g, &instruction->base);
if (array_type->id == TypeTableEntryIdArray) {
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
@ -1997,7 +1979,7 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
}
static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
TypeTableEntry *err_union_type = get_underlying_type(instruction->value->type_entry);
TypeTableEntry *err_union_type = get_underlying_type(instruction->value->value.type);
TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
@ -2014,7 +1996,7 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
TypeTableEntry *ptr_type = get_underlying_type(instruction->value->value.type);
TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
@ -2029,7 +2011,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
}
static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
TypeTableEntry *ptr_type = get_underlying_type(instruction->value->value.type);
TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
@ -2063,7 +2045,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
}
static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
TypeTableEntry *wanted_type = instruction->base.type_entry;
TypeTableEntry *wanted_type = instruction->base.value.type;
assert(wanted_type->id == TypeTableEntryIdMaybe);
@ -2079,7 +2061,8 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
assert(instruction->tmp_ptr);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
gen_assign_raw(g, val_ptr, payload_val, child_type, instruction->value->type_entry);
assert(child_type == instruction->value->value.type);
gen_assign_raw(g, val_ptr, payload_val, child_type);
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
@ -2087,7 +2070,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
}
static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) {
TypeTableEntry *wanted_type = instruction->base.type_entry;
TypeTableEntry *wanted_type = instruction->base.value.type;
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
@ -2106,7 +2089,7 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
}
static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) {
TypeTableEntry *wanted_type = instruction->base.type_entry;
TypeTableEntry *wanted_type = instruction->base.value.type;
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
@ -2125,13 +2108,14 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
gen_assign_raw(g, payload_ptr, payload_val, child_type, instruction->value->type_entry);
assert(child_type == instruction->value->value.type);
gen_assign_raw(g, payload_ptr, payload_val, child_type);
return instruction->tmp_ptr;
}
static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
TypeTableEntry *enum_type = instruction->value->type_entry;
TypeTableEntry *enum_type = instruction->value->value.type;
TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
if (!type_has_bits(tag_type))
return nullptr;
@ -2165,7 +2149,7 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
LLVMPointerType(union_val_type->type_ref, 0), "");
gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type, union_val_type);
gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type);
}
return tmp_struct_ptr;
@ -2180,7 +2164,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, "");
LLVMValueRef value = ir_llvm_value(g, field->value);
gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry, type_struct_field->type_entry);
gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry);
}
return instruction->tmp_ptr;
}
@ -2323,6 +2307,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
case IrInstructionIdStructInit:
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
case IrInstructionIdPointerReinterpret:
return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction);
case IrInstructionIdSwitchVar:
zig_panic("TODO render switch var instruction to LLVM");
case IrInstructionIdContainerInitList:
@ -2350,37 +2336,40 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
}
}
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
TypeTableEntry *canon_type = get_underlying_type(const_val->type);
switch (const_val->special) {
case ConstValSpecialRuntime:
zig_unreachable();
case ConstValSpecialUndef:
return LLVMGetUndef(type_entry->type_ref);
return LLVMGetUndef(canon_type->type_ref);
case ConstValSpecialZeroes:
return LLVMConstNull(type_entry->type_ref);
return LLVMConstNull(canon_type->type_ref);
case ConstValSpecialStatic:
break;
}
switch (type_entry->id) {
switch (canon_type->id) {
case TypeTableEntryIdTypeDecl:
return gen_const_val(g, type_entry->data.type_decl.canonical_type, const_val);
zig_unreachable();
case TypeTableEntryIdInt:
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
case TypeTableEntryIdEnumTag:
return LLVMConstInt(canon_type->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
case TypeTableEntryIdPureError:
assert(const_val->data.x_pure_err);
return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
const_val->data.x_pure_err->value, false);
case TypeTableEntryIdFloat:
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
return LLVMConstReal(canon_type->type_ref, const_val->data.x_bignum.data.x_float);
} else {
int64_t x = const_val->data.x_bignum.data.x_uint;
if (const_val->data.x_bignum.is_negative) {
x = -x;
}
return LLVMConstReal(type_entry->type_ref, x);
return LLVMConstReal(canon_type->type_ref, x);
}
case TypeTableEntryIdBool:
if (const_val->data.x_bool) {
@ -2390,12 +2379,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
case TypeTableEntryIdMaybe:
{
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
TypeTableEntry *child_type = canon_type->data.maybe.child_type;
if (child_type->id == TypeTableEntryIdPointer ||
child_type->id == TypeTableEntryIdFn)
{
if (const_val->data.x_maybe) {
return gen_const_val(g, child_type, const_val->data.x_maybe);
return gen_const_val(g, const_val->data.x_maybe);
} else {
return LLVMConstNull(child_type->type_ref);
}
@ -2403,7 +2392,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
LLVMValueRef child_val;
LLVMValueRef maybe_val;
if (const_val->data.x_maybe) {
child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
child_val = gen_const_val(g, const_val->data.x_maybe);
maybe_val = LLVMConstAllOnes(LLVMInt1Type());
} else {
child_val = LLVMConstNull(child_type->type_ref);
@ -2418,17 +2407,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
case TypeTableEntryIdStruct:
{
LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
LLVMValueRef *fields = allocate<LLVMValueRef>(canon_type->data.structure.gen_field_count);
for (uint32_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) {
TypeStructField *type_struct_field = &canon_type->data.structure.fields[i];
if (type_struct_field->gen_index == SIZE_MAX) {
continue;
}
fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
&const_val->data.x_struct.fields[i]);
fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]);
}
return LLVMConstNamedStruct(type_entry->type_ref, fields,
type_entry->data.structure.gen_field_count);
return LLVMConstNamedStruct(canon_type->type_ref, fields,
canon_type->data.structure.gen_field_count);
}
case TypeTableEntryIdUnion:
{
@ -2436,24 +2424,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
case TypeTableEntryIdArray:
{
TypeTableEntry *child_type = type_entry->data.array.child_type;
uint64_t len = type_entry->data.array.len;
TypeTableEntry *child_type = canon_type->data.array.child_type;
uint64_t len = canon_type->data.array.len;
LLVMValueRef *values = allocate<LLVMValueRef>(len);
for (uint64_t i = 0; i < len; i += 1) {
ConstExprValue *elem_value = &const_val->data.x_array.elements[i];
values[i] = gen_const_val(g, child_type, elem_value);
values[i] = gen_const_val(g, elem_value);
}
return LLVMConstArray(child_type->type_ref, values, len);
}
case TypeTableEntryIdEnum:
{
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
LLVMTypeRef tag_type_ref = canon_type->data.enumeration.tag_type->type_ref;
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
if (type_entry->data.enumeration.gen_field_count == 0) {
if (canon_type->data.enumeration.gen_field_count == 0) {
return tag_value;
} else {
TypeTableEntry *union_type = type_entry->data.enumeration.union_type;
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
TypeTableEntry *union_type = canon_type->data.enumeration.union_type;
TypeEnumField *enum_field = &canon_type->data.enumeration.fields[const_val->data.x_enum.tag];
assert(enum_field->value == const_val->data.x_enum.tag);
LLVMValueRef union_value;
if (type_has_bits(enum_field->type_entry)) {
@ -2463,8 +2451,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
enum_field->type_entry->type_ref);
uint64_t pad_bytes = union_type_bytes - field_type_bytes;
LLVMValueRef correctly_typed_value = gen_const_val(g, enum_field->type_entry,
const_val->data.x_enum.payload);
LLVMValueRef correctly_typed_value = gen_const_val(g, const_val->data.x_enum.payload);
if (pad_bytes == 0) {
union_value = correctly_typed_value;
} else {
@ -2481,29 +2468,31 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
tag_value,
union_value,
};
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
return LLVMConstNamedStruct(canon_type->type_ref, fields, 2);
}
}
case TypeTableEntryIdFn:
return fn_llvm_value(g, const_val->data.x_fn);
case TypeTableEntryIdPointer:
{
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
render_const_val_global(g, type_entry, const_val);
render_const_val_global(g, const_val);
size_t index = const_val->data.x_ptr.index;
if (index == SIZE_MAX) {
render_const_val(g, child_type, const_val->data.x_ptr.base_ptr);
render_const_val_global(g, child_type, const_val->data.x_ptr.base_ptr);
const_val->llvm_value = const_val->data.x_ptr.base_ptr->llvm_global;
render_const_val_global(g, type_entry, const_val);
render_const_val(g, const_val->data.x_ptr.base_ptr);
render_const_val_global(g, const_val->data.x_ptr.base_ptr);
ConstExprValue *other_val = const_val->data.x_ptr.base_ptr;
if (other_val->type == const_val->type->data.pointer.child_type) {
const_val->llvm_value = other_val->llvm_global;
} else {
const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref);
}
render_const_val_global(g, const_val);
return const_val->llvm_value;
} else {
ConstExprValue *array_const_val = const_val->data.x_ptr.base_ptr;
TypeTableEntry *array_type = get_array_type(g, child_type,
array_const_val->data.x_array.size);
render_const_val(g, array_type, array_const_val);
render_const_val_global(g, array_type, array_const_val);
assert(array_const_val->type->id == TypeTableEntryIdArray);
render_const_val(g, array_const_val);
render_const_val_global(g, array_const_val);
TypeTableEntry *usize = g->builtin_types.entry_usize;
LLVMValueRef indices[] = {
LLVMConstNull(usize->type_ref),
@ -2511,13 +2500,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
};
LLVMValueRef ptr_val = LLVMConstInBoundsGEP(array_const_val->llvm_global, indices, 2);
const_val->llvm_value = ptr_val;
render_const_val_global(g, type_entry, const_val);
render_const_val_global(g, const_val);
return ptr_val;
}
}
case TypeTableEntryIdErrorUnion:
{
TypeTableEntry *child_type = type_entry->data.error.child_type;
TypeTableEntry *child_type = canon_type->data.error.child_type;
if (!type_has_bits(child_type)) {
uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
@ -2529,7 +2518,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
err_payload_value = LLVMConstNull(child_type->type_ref);
} else {
err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
err_payload_value = gen_const_val(g, child_type, const_val->data.x_err_union.payload);
err_payload_value = gen_const_val(g, const_val->data.x_err_union.payload);
}
LLVMValueRef fields[] = {
err_tag_value,
@ -2540,8 +2529,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
case TypeTableEntryIdVoid:
return nullptr;
case TypeTableEntryIdEnumTag:
return gen_const_val(g, type_entry->data.enum_tag.int_type, const_val);
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
@ -2559,17 +2546,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
zig_unreachable();
}
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
static void render_const_val(CodeGen *g, ConstExprValue *const_val) {
if (!const_val->llvm_value)
const_val->llvm_value = gen_const_val(g, type_entry, const_val);
const_val->llvm_value = gen_const_val(g, const_val);
if (const_val->llvm_global)
LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value);
}
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
static void render_const_val_global(CodeGen *g, ConstExprValue *const_val) {
if (!const_val->llvm_global) {
LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
LLVMValueRef global_value = LLVMAddGlobal(g->module, const_val->type->type_ref, "");
LLVMSetLinkage(global_value, LLVMInternalLinkage);
LLVMSetGlobalConstant(global_value, true);
LLVMSetUnnamedAddr(global_value, true);
@ -2717,9 +2704,9 @@ static void do_code_gen(CodeGen *g) {
for (size_t i = 0; i < g->global_vars.length; i += 1) {
VariableTableEntry *var = g->global_vars.at(i);
if (var->type->id == TypeTableEntryIdNumLitFloat) {
if (var->value.type->id == TypeTableEntryIdNumLitFloat) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = var->value;
ConstExprValue *const_val = &var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = g->builtin_types.entry_f64;
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
@ -2727,9 +2714,9 @@ static void do_code_gen(CodeGen *g) {
continue;
}
if (var->type->id == TypeTableEntryIdNumLitInt) {
if (var->value.type->id == TypeTableEntryIdNumLitInt) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = var->value;
ConstExprValue *const_val = &var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
@ -2739,27 +2726,26 @@ static void do_code_gen(CodeGen *g) {
continue;
}
if (!type_has_bits(var->type)) {
if (!type_has_bits(var->value.type))
continue;
}
assert(var->decl_node);
assert(var->decl_node->type == NodeTypeVariableDeclaration);
LLVMValueRef global_value;
if (var->is_extern) {
global_value = LLVMAddGlobal(g->module, var->type->type_ref, buf_ptr(&var->name));
global_value = LLVMAddGlobal(g->module, var->value.type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage);
} else {
render_const_val(g, var->type, var->value);
render_const_val_global(g, var->type, var->value);
global_value = var->value->llvm_global;
render_const_val(g, &var->value);
render_const_val_global(g, &var->value);
global_value = var->value.llvm_global;
// TODO debug info for function pointers
if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, var->value->llvm_value, var->type);
if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, var->value.llvm_value, var->value.type);
}
}
@ -2890,15 +2876,15 @@ static void do_code_gen(CodeGen *g) {
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
LLVMValueRef *slot;
TypeTableEntry *slot_type = instruction->type_entry;
TypeTableEntry *slot_type = instruction->value.type;
if (instruction->id == IrInstructionIdCast) {
IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction;
slot = &cast_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdRef) {
IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
slot = &ref_instruction->tmp_ptr;
assert(instruction->type_entry->id == TypeTableEntryIdPointer);
slot_type = instruction->type_entry->data.pointer.child_type;
assert(instruction->value.type->id == TypeTableEntryIdPointer);
slot_type = instruction->value.type->data.pointer.child_type;
} else if (instruction->id == IrInstructionIdContainerInitList) {
IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
slot = &container_init_list_instruction->tmp_ptr;
@ -2938,33 +2924,33 @@ static void do_code_gen(CodeGen *g) {
for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
VariableTableEntry *var = fn_table_entry->variable_list.at(var_i);
if (!type_has_bits(var->type)) {
if (!type_has_bits(var->value.type)) {
continue;
}
if (ir_get_var_is_comptime(var))
continue;
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
var->value_ref = LLVMBuildAlloca(g->builder, var->value.type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->value.type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->type->di_type, !g->strip_debug_symbols, 0);
var->value.type->di_type, !g->strip_debug_symbols, 0);
} else {
assert(var->gen_arg_index != SIZE_MAX);
TypeTableEntry *gen_type;
if (handle_is_ptr(var->type)) {
if (handle_is_ptr(var->value.type)) {
gen_type = fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index].type;
var->value_ref = LLVMGetParam(fn, var->gen_arg_index);
} else {
gen_type = var->type;
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
gen_type = var->value.type;
var->value_ref = LLVMBuildAlloca(g->builder, var->value.type->type_ref, buf_ptr(&var->name));
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->value.type->type_ref);
LLVMSetAlignment(var->value_ref, align_bytes);
}
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@ -2991,7 +2977,7 @@ static void do_code_gen(CodeGen *g) {
assert(variable);
assert(variable->value_ref);
if (!handle_is_ptr(variable->type)) {
if (!handle_is_ptr(variable->value.type)) {
clear_debug_source_node(g);
LLVMBuildStore(g->builder, LLVMGetParam(fn, variable->gen_arg_index), variable->value_ref);
}
@ -3627,7 +3613,7 @@ static void init(CodeGen *g, Buf *source_path) {
define_builtin_fns(g);
g->invalid_instruction = allocate<IrInstruction>(1);
g->invalid_instruction->type_entry = g->builtin_types.entry_invalid;
g->invalid_instruction->value.type = g->builtin_types.entry_invalid;
}
void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {

1212
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
* See http://opensource.org/licenses/MIT
*/
#include "analyze.hpp"
#include "ir.hpp"
#include "ir_print.hpp"
@ -24,13 +25,13 @@ static void ir_print_indent(IrPrint *irp) {
static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
ir_print_indent(irp);
const char *type_name = instruction->type_entry ? buf_ptr(&instruction->type_entry->name) : "(unknown)";
const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)";
const char *ref_count = ir_has_side_effects(instruction) ?
"-" : buf_ptr(buf_sprintf("%zu", instruction->ref_count));
fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count);
}
static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, ConstExprValue *const_val) {
static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
switch (const_val->special) {
case ConstValSpecialRuntime:
zig_unreachable();
@ -43,9 +44,12 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
case ConstValSpecialStatic:
break;
}
switch (type_entry->id) {
assert(const_val->type);
TypeTableEntry *canon_type = get_underlying_type(const_val->type);
switch (canon_type->id) {
case TypeTableEntryIdTypeDecl:
return ir_print_const_value(irp, type_entry->data.type_decl.canonical_type, const_val);
zig_unreachable();
case TypeTableEntryIdInvalid:
fprintf(irp->f, "(invalid)");
return;
@ -94,7 +98,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
case TypeTableEntryIdPointer:
fprintf(irp->f, "&");
ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val));
ir_print_const_value(irp, const_ptr_pointee(const_val));
return;
case TypeTableEntryIdFn:
{
@ -110,14 +114,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
case TypeTableEntryIdArray:
{
uint64_t len = type_entry->data.array.len;
fprintf(irp->f, "%s{", buf_ptr(&type_entry->name));
uint64_t len = canon_type->data.array.len;
fprintf(irp->f, "%s{", buf_ptr(&canon_type->name));
for (uint64_t i = 0; i < len; i += 1) {
if (i != 0)
fprintf(irp->f, ",");
ConstExprValue *child_value = &const_val->data.x_array.elements[i];
TypeTableEntry *child_type = type_entry->data.array.child_type;
ir_print_const_value(irp, child_type, child_value);
ir_print_const_value(irp, child_value);
}
fprintf(irp->f, "}");
return;
@ -135,7 +138,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
case TypeTableEntryIdMaybe:
{
if (const_val->data.x_maybe) {
ir_print_const_value(irp, type_entry->data.maybe.child_type, const_val->data.x_maybe);
ir_print_const_value(irp, const_val->data.x_maybe);
} else {
fprintf(irp->f, "null");
}
@ -160,22 +163,22 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
case TypeTableEntryIdStruct:
{
fprintf(irp->f, "(struct %s constant)", buf_ptr(&type_entry->name));
fprintf(irp->f, "(struct %s constant)", buf_ptr(&canon_type->name));
return;
}
case TypeTableEntryIdEnum:
{
fprintf(irp->f, "(enum %s constant)", buf_ptr(&type_entry->name));
fprintf(irp->f, "(enum %s constant)", buf_ptr(&canon_type->name));
return;
}
case TypeTableEntryIdErrorUnion:
{
fprintf(irp->f, "(error union %s constant)", buf_ptr(&type_entry->name));
fprintf(irp->f, "(error union %s constant)", buf_ptr(&canon_type->name));
return;
}
case TypeTableEntryIdUnion:
{
fprintf(irp->f, "(union %s constant)", buf_ptr(&type_entry->name));
fprintf(irp->f, "(union %s constant)", buf_ptr(&canon_type->name));
return;
}
case TypeTableEntryIdPureError:
@ -185,7 +188,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
case TypeTableEntryIdEnumTag:
{
TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
TypeTableEntry *enum_type = canon_type->data.enum_tag.enum_type;
TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint];
fprintf(irp->f, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
return;
@ -194,19 +197,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
zig_unreachable();
}
static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) {
TypeTableEntry *type_entry = instruction->type_entry;
ConstExprValue *const_val = &instruction->static_value;
ir_print_const_value(irp, type_entry, const_val);
}
static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
fprintf(irp->f, "#%zu", instruction->debug_id);
}
static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
if (instruction->static_value.special != ConstValSpecialRuntime) {
ir_print_const_instruction(irp, instruction);
if (instruction->value.special != ConstValSpecialRuntime) {
ir_print_const_value(irp, &instruction->value);
} else {
ir_print_var_instruction(irp, instruction);
}
@ -223,7 +220,7 @@ static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instructio
}
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
ir_print_const_instruction(irp, &const_instruction->base);
ir_print_const_value(irp, &const_instruction->base.value);
}
static const char *ir_bin_op_id_str(IrBinOp op_id) {
@ -925,6 +922,12 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction)
fprintf(irp->f, "}");
}
static void ir_print_pointer_reinterpret(IrPrint *irp, IrInstructionPointerReinterpret *instruction) {
fprintf(irp->f, "(%s)(", buf_ptr(&instruction->base.value.type->name));
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -1164,6 +1167,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdInitEnum:
ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
break;
case IrInstructionIdPointerReinterpret:
ir_print_pointer_reinterpret(irp, (IrInstructionPointerReinterpret *)instruction);
break;
}
fprintf(irp->f, "\n");
}
@ -1188,14 +1194,14 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
static void print_tld_var(IrPrint *irp, TldVar *tld_var) {
const char *const_or_var = tld_var->var->src_is_const ? "const" : "var";
fprintf(irp->f, "%s %s", const_or_var, buf_ptr(tld_var->base.name));
bool omit_type = (tld_var->var->type->id == TypeTableEntryIdNumLitFloat ||
tld_var->var->type->id == TypeTableEntryIdNumLitInt);
bool omit_type = (tld_var->var->value.type->id == TypeTableEntryIdNumLitFloat ||
tld_var->var->value.type->id == TypeTableEntryIdNumLitInt);
if (!omit_type) {
fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->type->name));
fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->value.type->name));
}
if (tld_var->var->value) {
if (tld_var->var->value.special != ConstValSpecialRuntime) {
fprintf(irp->f, " = ");
ir_print_const_value(irp, tld_var->var->type, tld_var->var->value);
ir_print_const_value(irp, &tld_var->var->value);
}
fprintf(irp->f, ";\n");
}

View File

@ -124,51 +124,52 @@ static void parseh_init_tld(Context *c, Tld *tld, TldId id, Buf *name) {
tld->resolution = TldResolutionOk;
}
static TldVar *create_global_var(Context *c, Buf *name, TypeTableEntry *var_type, ConstExprValue *var_value, bool is_const) {
static TldVar *create_global_var(Context *c, Buf *name, ConstExprValue *var_value, bool is_const) {
TldVar *tld_var = allocate<TldVar>(1);
parseh_init_tld(c, &tld_var->base, TldIdVar, name);
tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, var_type, is_const, var_value);
tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, is_const, var_value);
return tld_var;
}
static Tld *create_global_char_lit_var(Context *c, Buf *name, uint8_t value) {
TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_u8,
create_const_unsigned_negative(value, false), true);
ConstExprValue *var_val = create_const_unsigned_negative(c->codegen->builtin_types.entry_u8, value, false);
TldVar *tld_var = create_global_var(c, name, var_val, true);
return &tld_var->base;
}
static Tld *create_global_str_lit_var(Context *c, Buf *name, Buf *value) {
TypeTableEntry *str_type = get_array_type(c->codegen, c->codegen->builtin_types.entry_u8, buf_len(value));
TldVar *tld_var = create_global_var(c, name, str_type, create_const_str_lit(value), true);
TldVar *tld_var = create_global_var(c, name, create_const_str_lit(c->codegen, value), true);
return &tld_var->base;
}
static Tld *create_global_num_lit_unsigned_negative(Context *c, Buf *name, uint64_t x, bool negative) {
TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int,
create_const_unsigned_negative(x, negative), true);
ConstExprValue *var_val = create_const_unsigned_negative(c->codegen->builtin_types.entry_num_lit_int, x, negative);
TldVar *tld_var = create_global_var(c, name, var_val, true);
return &tld_var->base;
}
static Tld *create_global_num_lit_float(Context *c, Buf *name, double value) {
TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_float,
create_const_float(value), true);
ConstExprValue *var_val = create_const_float(c->codegen->builtin_types.entry_num_lit_float, value);
TldVar *tld_var = create_global_var(c, name, var_val, true);
return &tld_var->base;
}
static ConstExprValue *create_const_num_lit_ap(Context *c, const Decl *source_decl, const llvm::APSInt &aps_int) {
static ConstExprValue *create_const_int_ap(Context *c, TypeTableEntry *type, const Decl *source_decl,
const llvm::APSInt &aps_int)
{
if (aps_int.isSigned()) {
if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
emit_warning(c, source_decl, "integer overflow\n");
return nullptr;
} else {
return create_const_signed(aps_int.getExtValue());
return create_const_signed(type, aps_int.getExtValue());
}
} else {
if (aps_int > INT64_MAX) {
emit_warning(c, source_decl, "integer overflow\n");
return nullptr;
} else {
return create_const_unsigned_negative(aps_int.getExtValue(), false);
return create_const_unsigned_negative(type, aps_int.getExtValue(), false);
}
}
}
@ -176,19 +177,18 @@ static ConstExprValue *create_const_num_lit_ap(Context *c, const Decl *source_de
static Tld *create_global_num_lit_ap(Context *c, const Decl *source_decl, Buf *name,
const llvm::APSInt &aps_int)
{
ConstExprValue *const_value = create_const_num_lit_ap(c, source_decl, aps_int);
ConstExprValue *const_value = create_const_int_ap(c, c->codegen->builtin_types.entry_num_lit_int,
source_decl, aps_int);
if (!const_value)
return nullptr;
TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int, const_value, true);
TldVar *tld_var = create_global_var(c, name, const_value, true);
return &tld_var->base;
}
static Tld *add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) {
ConstExprValue *var_value = allocate<ConstExprValue>(1);
var_value->special = ConstValSpecialStatic;
var_value->data.x_type = type_entry;
TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_type, var_value, true);
ConstExprValue *var_value = create_const_type(c->codegen, type_entry);
TldVar *tld_var = create_global_var(c, name, var_value, true);
add_global(c, &tld_var->base);
c->global_type_table.put(name, type_entry);
@ -1025,7 +1025,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
"ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name));
return;
}
init_value = create_const_num_lit_ap(c, var_decl, ap_value->getInt());
init_value = create_const_int_ap(c, var_type, var_decl, ap_value->getInt());
if (!init_value)
return;
@ -1047,13 +1047,13 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
return;
}
TldVar *tld_var = create_global_var(c, name, var_type, init_value, true);
TldVar *tld_var = create_global_var(c, name, init_value, true);
add_global(c, &tld_var->base);
return;
}
if (is_extern) {
TldVar *tld_var = create_global_var(c, name, var_type, nullptr, is_const);
TldVar *tld_var = create_global_var(c, name, create_const_runtime(var_type), is_const);
tld_var->var->is_extern = true;
add_global(c, &tld_var->base);
return;
@ -1199,7 +1199,7 @@ static void process_symbol_macros(Context *c) {
// variable is non-null and calls it.
if (existing_tld->id == TldIdVar) {
TldVar *tld_var = (TldVar *)existing_tld;
TypeTableEntry *var_type = tld_var->var->type;
TypeTableEntry *var_type = tld_var->var->value.type;
if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) {
TypeTableEntry *child_type = var_type->data.maybe.child_type;
if (child_type->id == TypeTableEntryIdFn) {

View File

@ -261,6 +261,16 @@ fn typeEquality() {
assert(&const u8 != &u8);
}
const global_a: i32 = 1234;
const global_b: &const i32 = &global_a;
const global_c: &const f32 = (&const f32)(global_b);
fn compileTimeGlobalReinterpret() {
@setFnTest(this);
const d = (&const i32)(global_c);
assert(*d == 1234);
}
// TODO import from std.str
pub fn memeql(a: []const u8, b: []const u8) -> bool {
sliceEql(u8, a, b)
@ -288,7 +298,6 @@ pub fn cstrcmp(a: &const u8, b: &const u8) -> i8 {
};
}
// TODO const assert = @import("std").debug.assert;
fn assert(ok: bool) {
if (!ok)

View File

@ -9,27 +9,12 @@ const test_enum_with_members = @import("cases/enum_with_members.zig");
fn explicitCastMaybePointers() {
@setFnTest(this, true);
@setFnTest(this);
const a: ?&i32 = undefined;
const b: ?&f32 = (?&f32)(a);
}
fn multilineCString() {
@setFnTest(this);
const s1 =
c\\one
c\\two)
c\\three
;
const s2 = c"one\ntwo)\nthree";
assert(cstr.cmp(s1, s2) == 0);
}
fn genericMallocFree() {
@setFnTest(this, true);