Merge pull request #4152 from ziglang/ir-clean-up-vars

pay off some result location technical debt with regards to "mem slots"
master
Andrew Kelley 2020-01-28 16:21:41 -05:00 committed by GitHub
commit 76fba5baf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 869 additions and 487 deletions

View File

@ -1978,6 +1978,9 @@ pub const LibExeObjStep = struct {
const all_features = self.target.getArch().allFeaturesList(); const all_features = self.target.getArch().allFeaturesList();
var populated_cpu_features = cross.cpu_features.cpu.features; var populated_cpu_features = cross.cpu_features.cpu.features;
if (self.target.getArch().subArchFeature()) |sub_arch_index| {
populated_cpu_features.addFeature(sub_arch_index);
}
populated_cpu_features.populateDependencies(all_features); populated_cpu_features.populateDependencies(all_features);
if (populated_cpu_features.eql(cross.cpu_features.features)) { if (populated_cpu_features.eql(cross.cpu_features.features)) {

View File

@ -15,7 +15,7 @@ pub const Murmur2_32 = struct {
const m: u32 = 0x5bd1e995; const m: u32 = 0x5bd1e995;
const len = @truncate(u32, str.len); const len = @truncate(u32, str.len);
var h1: u32 = seed ^ len; var h1: u32 = seed ^ len;
for (@ptrCast([*]allowzero align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
var k1: u32 = v; var k1: u32 = v;
if (builtin.endian == builtin.Endian.Big) if (builtin.endian == builtin.Endian.Big)
k1 = @byteSwap(u32, k1); k1 = @byteSwap(u32, k1);
@ -100,7 +100,7 @@ pub const Murmur2_64 = struct {
const m: u64 = 0xc6a4a7935bd1e995; const m: u64 = 0xc6a4a7935bd1e995;
const len = @as(u64, str.len); const len = @as(u64, str.len);
var h1: u64 = seed ^ (len *% m); var h1: u64 = seed ^ (len *% m);
for (@ptrCast([*]allowzero align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
var k1: u64 = v; var k1: u64 = v;
if (builtin.endian == builtin.Endian.Big) if (builtin.endian == builtin.Endian.Big)
k1 = @byteSwap(u64, k1); k1 = @byteSwap(u64, k1);
@ -180,7 +180,7 @@ pub const Murmur3_32 = struct {
const c2: u32 = 0x1b873593; const c2: u32 = 0x1b873593;
const len = @truncate(u32, str.len); const len = @truncate(u32, str.len);
var h1: u32 = seed; var h1: u32 = seed;
for (@ptrCast([*]allowzero align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
var k1: u32 = v; var k1: u32 = v;
if (builtin.endian == builtin.Endian.Big) if (builtin.endian == builtin.Endian.Big)
k1 = @byteSwap(u32, k1); k1 = @byteSwap(u32, k1);

View File

@ -317,6 +317,7 @@ struct ConstErrValue {
struct ConstBoundFnValue { struct ConstBoundFnValue {
ZigFn *fn; ZigFn *fn;
IrInstGen *first_arg; IrInstGen *first_arg;
IrInst *first_arg_src;
}; };
struct ConstArgTuple { struct ConstArgTuple {
@ -502,6 +503,9 @@ struct ZigValue {
// uncomment these to find bugs. can't leave them uncommented because of a gcc-9 warning // uncomment these to find bugs. can't leave them uncommented because of a gcc-9 warning
//ZigValue(const ZigValue &other) = delete; // plz zero initialize with {} //ZigValue(const ZigValue &other) = delete; // plz zero initialize with {}
//ZigValue& operator= (const ZigValue &other) = delete; // use copy_const_val //ZigValue& operator= (const ZigValue &other) = delete; // use copy_const_val
// for use in debuggers
void dump();
}; };
enum ReturnKnowledge { enum ReturnKnowledge {
@ -1256,6 +1260,7 @@ static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1;
struct InferredStructField { struct InferredStructField {
ZigType *inferred_struct_type; ZigType *inferred_struct_type;
Buf *field_name; Buf *field_name;
bool already_resolved;
}; };
struct ZigTypePointer { struct ZigTypePointer {
@ -2262,7 +2267,6 @@ struct ZigVar {
Scope *parent_scope; Scope *parent_scope;
Scope *child_scope; Scope *child_scope;
LLVMValueRef param_value_ref; LLVMValueRef param_value_ref;
size_t mem_slot_index;
IrExecutableSrc *owner_exec; IrExecutableSrc *owner_exec;
Buf *section_name; Buf *section_name;
@ -2283,6 +2287,7 @@ struct ZigVar {
bool is_thread_local; bool is_thread_local;
bool is_comptime_memoized; bool is_comptime_memoized;
bool is_comptime_memoized_value; bool is_comptime_memoized_value;
bool did_the_decl_codegen;
}; };
struct ErrorTableEntry { struct ErrorTableEntry {

View File

@ -593,9 +593,9 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con
} }
if (inferred_struct_field != nullptr) { if (inferred_struct_field != nullptr) {
entry->abi_size = g->builtin_types.entry_usize->abi_size; entry->abi_size = SIZE_MAX;
entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; entry->size_in_bits = SIZE_MAX;
entry->abi_align = g->builtin_types.entry_usize->abi_align; entry->abi_align = UINT32_MAX;
} else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { } else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) {
if (type_has_bits(child_type)) { if (type_has_bits(child_type)) {
entry->abi_size = g->builtin_types.entry_usize->abi_size; entry->abi_size = g->builtin_types.entry_usize->abi_size;
@ -1102,11 +1102,28 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
Buf *type_name, UndefAllowed undef) Buf *type_name, UndefAllowed undef)
{ {
Error err;
ZigValue *result = create_const_vals(1);
ZigValue *result_ptr = create_const_vals(1);
result->special = ConstValSpecialUndef;
result->type = (type_entry == nullptr) ? g->builtin_types.entry_var : type_entry;
result_ptr->special = ConstValSpecialStatic;
result_ptr->type = get_pointer_to_type(g, result->type, false);
result_ptr->data.x_ptr.mut = ConstPtrMutComptimeVar;
result_ptr->data.x_ptr.special = ConstPtrSpecialRef;
result_ptr->data.x_ptr.data.ref.pointee = result;
size_t backward_branch_count = 0; size_t backward_branch_count = 0;
size_t backward_branch_quota = default_backward_branch_quota; size_t backward_branch_quota = default_backward_branch_quota;
return ir_eval_const_value(g, scope, node, type_entry, if ((err = ir_eval_const_value(g, scope, node, result_ptr,
&backward_branch_count, &backward_branch_quota, &backward_branch_count, &backward_branch_quota,
nullptr, nullptr, node, type_name, nullptr, nullptr, undef); nullptr, nullptr, node, type_name, nullptr, nullptr, undef)))
{
return g->invalid_inst_gen->value;
}
destroy(result_ptr, "ZigValue");
return result;
} }
Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type, Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent_type,
@ -3829,7 +3846,6 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
variable_entry->var_type = var_type; variable_entry->var_type = var_type;
variable_entry->parent_scope = parent_scope; variable_entry->parent_scope = parent_scope;
variable_entry->shadowable = false; variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->src_arg_index = SIZE_MAX; variable_entry->src_arg_index = SIZE_MAX;
assert(name); assert(name);
@ -3930,7 +3946,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
// TODO more validation for types that can't be used for export/extern variables // TODO more validation for types that can't be used for export/extern variables
ZigType *implicit_type = nullptr; ZigType *implicit_type = nullptr;
if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { if (explicit_type != nullptr && explicit_type->id == ZigTypeIdInvalid) {
implicit_type = explicit_type; implicit_type = explicit_type;
} else if (var_decl->expr) { } else if (var_decl->expr) {
init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type,
@ -4718,8 +4734,14 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
assert(!fn_type->data.fn.is_generic); assert(!fn_type->data.fn.is_generic);
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
if (fn->analyzed_executable.begin_scope == nullptr) {
fn->analyzed_executable.begin_scope = &fn->def_scope->base;
}
if (fn->analyzed_executable.source_node == nullptr) {
fn->analyzed_executable.source_node = fn->body_node;
}
ZigType *block_return_type = ir_analyze(g, fn->ir_executable, ZigType *block_return_type = ir_analyze(g, fn->ir_executable,
&fn->analyzed_executable, fn_type_id->return_type, return_type_node); &fn->analyzed_executable, fn_type_id->return_type, return_type_node, nullptr);
fn->src_implicit_return_type = block_return_type; fn->src_implicit_return_type = block_return_type;
if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) { if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) {
@ -5619,6 +5641,8 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
return OnePossibleValueYes; return OnePossibleValueYes;
return type_has_one_possible_value(g, type_entry->data.array.child_type); return type_has_one_possible_value(g, type_entry->data.array.child_type);
case ZigTypeIdStruct: case ZigTypeIdStruct:
// If the recursive function call asks, then we are not one possible value.
type_entry->one_possible_value = OnePossibleValueNo;
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *field = type_entry->data.structure.fields[i]; TypeStructField *field = type_entry->data.structure.fields[i];
OnePossibleValue opv = (field->type_entry != nullptr) ? OnePossibleValue opv = (field->type_entry != nullptr) ?
@ -5626,6 +5650,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
type_val_resolve_has_one_possible_value(g, field->type_val); type_val_resolve_has_one_possible_value(g, field->type_val);
switch (opv) { switch (opv) {
case OnePossibleValueInvalid: case OnePossibleValueInvalid:
type_entry->one_possible_value = OnePossibleValueInvalid;
return OnePossibleValueInvalid; return OnePossibleValueInvalid;
case OnePossibleValueNo: case OnePossibleValueNo:
return OnePossibleValueNo; return OnePossibleValueNo;
@ -5633,6 +5658,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
continue; continue;
} }
} }
type_entry->one_possible_value = OnePossibleValueYes;
return OnePossibleValueYes; return OnePossibleValueYes;
case ZigTypeIdErrorSet: case ZigTypeIdErrorSet:
case ZigTypeIdEnum: case ZigTypeIdEnum:
@ -5678,6 +5704,9 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
assert(field_type != nullptr); assert(field_type != nullptr);
result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type); result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type);
} }
} else if (result->type->id == ZigTypeIdPointer) {
result->data.x_ptr.special = ConstPtrSpecialRef;
result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type);
} }
g->one_possible_values.put(type_entry, result); g->one_possible_values.put(type_entry, result);
return result; return result;
@ -6452,7 +6481,21 @@ static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) {
} }
ty->data.pointer.resolve_loop_flag_zero_bits = true; ty->data.pointer.resolve_loop_flag_zero_bits = true;
ZigType *elem_type = ty->data.pointer.child_type; ZigType *elem_type;
InferredStructField *isf = ty->data.pointer.inferred_struct_field;
if (isf != nullptr) {
TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name);
assert(field != nullptr);
if (field->is_comptime) {
ty->abi_size = 0;
ty->size_in_bits = 0;
ty->abi_align = 0;
return ErrorNone;
}
elem_type = field->type_entry;
} else {
elem_type = ty->data.pointer.child_type;
}
bool has_bits; bool has_bits;
if ((err = type_has_bits2(g, elem_type, &has_bits))) if ((err = type_has_bits2(g, elem_type, &has_bits)))
@ -6875,6 +6918,7 @@ static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ZigValu
} }
case ConstArraySpecialNone: { case ConstArraySpecialNone: {
ZigValue *base = &array->data.s_none.elements[start]; ZigValue *base = &array->data.s_none.elements[start];
assert(base != nullptr);
assert(start + len <= const_val->type->data.array.len); assert(start + len <= const_val->type->data.array.len);
buf_appendf(buf, "%s{", buf_ptr(type_name)); buf_appendf(buf, "%s{", buf_ptr(type_name));
@ -6890,6 +6934,10 @@ static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ZigValu
} }
void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) { void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) {
if (const_val == nullptr) {
buf_appendf(buf, "(invalid nullptr value)");
return;
}
switch (const_val->special) { switch (const_val->special) {
case ConstValSpecialRuntime: case ConstValSpecialRuntime:
buf_appendf(buf, "(runtime value)"); buf_appendf(buf, "(runtime value)");
@ -9295,10 +9343,13 @@ bool type_has_optional_repr(ZigType *ty) {
} }
void copy_const_val(ZigValue *dest, ZigValue *src) { void copy_const_val(ZigValue *dest, ZigValue *src) {
uint32_t prev_align = dest->llvm_align;
ConstParent prev_parent = dest->parent;
memcpy(dest, src, sizeof(ZigValue)); memcpy(dest, src, sizeof(ZigValue));
dest->llvm_align = prev_align;
if (src->special != ConstValSpecialStatic) if (src->special != ConstValSpecialStatic)
return; return;
dest->parent.id = ConstParentIdNone; dest->parent = prev_parent;
if (dest->type->id == ZigTypeIdStruct) { if (dest->type->id == ZigTypeIdStruct) {
dest->data.x_struct.fields = alloc_const_vals_ptrs(dest->type->data.structure.src_field_count); dest->data.x_struct.fields = alloc_const_vals_ptrs(dest->type->data.structure.src_field_count);
for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) {
@ -9307,6 +9358,16 @@ void copy_const_val(ZigValue *dest, ZigValue *src) {
dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest;
dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i; dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i;
} }
} else if (dest->type->id == ZigTypeIdArray) {
if (dest->data.x_array.special == ConstArraySpecialNone) {
dest->data.x_array.data.s_none.elements = create_const_vals(dest->type->data.array.len);
for (uint64_t i = 0; i < dest->type->data.array.len; i += 1) {
copy_const_val(&dest->data.x_array.data.s_none.elements[i], &src->data.x_array.data.s_none.elements[i]);
dest->data.x_array.data.s_none.elements[i].parent.id = ConstParentIdArray;
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.array_val = dest;
dest->data.x_array.data.s_none.elements[i].parent.data.p_array.elem_index = i;
}
}
} else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) {
dest->data.x_optional = create_const_vals(1); dest->data.x_optional = create_const_vals(1);
copy_const_val(dest->data.x_optional, src->data.x_optional); copy_const_val(dest->data.x_optional, src->data.x_optional);
@ -9353,6 +9414,171 @@ bool type_is_numeric(ZigType *ty) {
zig_unreachable(); zig_unreachable();
} }
static void dump_value_indent(ZigValue *val, int indent) {
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, "Value@%p(", val);
if (val->type != nullptr) {
fprintf(stderr, "%s)", buf_ptr(&val->type->name));
} else {
fprintf(stderr, "type=nullptr)");
}
switch (val->special) {
case ConstValSpecialUndef:
fprintf(stderr, "[undefined]\n");
return;
case ConstValSpecialLazy:
fprintf(stderr, "[lazy]\n");
return;
case ConstValSpecialRuntime:
fprintf(stderr, "[runtime]\n");
return;
case ConstValSpecialStatic:
break;
}
if (val->type == nullptr)
return;
switch (val->type->id) {
case ZigTypeIdInvalid:
fprintf(stderr, "<invalid>\n");
return;
case ZigTypeIdUnreachable:
fprintf(stderr, "<unreachable>\n");
return;
case ZigTypeIdUndefined:
fprintf(stderr, "<undefined>\n");
return;
case ZigTypeIdVoid:
fprintf(stderr, "<{}>\n");
return;
case ZigTypeIdMetaType:
fprintf(stderr, "<%s>\n", buf_ptr(&val->data.x_type->name));
return;
case ZigTypeIdBool:
fprintf(stderr, "<%s>\n", val->data.x_bool ? "true" : "false");
return;
case ZigTypeIdComptimeInt:
case ZigTypeIdInt: {
Buf *tmp_buf = buf_alloc();
bigint_append_buf(tmp_buf, &val->data.x_bigint, 10);
fprintf(stderr, "<%s>\n", buf_ptr(tmp_buf));
buf_destroy(tmp_buf);
return;
}
case ZigTypeIdComptimeFloat:
case ZigTypeIdFloat:
fprintf(stderr, "<TODO dump number>\n");
return;
case ZigTypeIdStruct:
fprintf(stderr, "<struct\n");
for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) {
for (int j = 0; j < indent; j += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, "%s: ", buf_ptr(val->type->data.structure.fields[i]->name));
if (val->data.x_struct.fields == nullptr) {
fprintf(stderr, "<null>\n");
} else {
dump_value_indent(val->data.x_struct.fields[i], 1);
}
}
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, ">\n");
return;
case ZigTypeIdOptional:
fprintf(stderr, "<\n");
dump_value_indent(val->data.x_optional, indent + 1);
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, ">\n");
return;
case ZigTypeIdErrorUnion:
if (val->data.x_err_union.payload != nullptr) {
fprintf(stderr, "<\n");
dump_value_indent(val->data.x_err_union.payload, indent + 1);
} else {
fprintf(stderr, "<\n");
dump_value_indent(val->data.x_err_union.error_set, 0);
}
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, ">\n");
return;
case ZigTypeIdPointer:
switch (val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
fprintf(stderr, "<!invalid ptr!>\n");
return;
case ConstPtrSpecialRef:
fprintf(stderr, "<ref\n");
dump_value_indent(val->data.x_ptr.data.ref.pointee, indent + 1);
break;
case ConstPtrSpecialBaseStruct: {
ZigValue *struct_val = val->data.x_ptr.data.base_struct.struct_val;
size_t field_index = val->data.x_ptr.data.base_struct.field_index;
fprintf(stderr, "<struct %p field %zu\n", struct_val, field_index);
if (struct_val != nullptr) {
ZigValue *field_val = struct_val->data.x_struct.fields[field_index];
if (field_val != nullptr) {
dump_value_indent(field_val, indent + 1);
} else {
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, "(invalid null field)\n");
}
}
break;
}
case ConstPtrSpecialBaseOptionalPayload: {
ZigValue *optional_val = val->data.x_ptr.data.base_optional_payload.optional_val;
fprintf(stderr, "<optional %p payload\n", optional_val);
if (optional_val != nullptr) {
dump_value_indent(optional_val, indent + 1);
}
break;
}
default:
fprintf(stderr, "TODO dump more pointer things\n");
}
for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, ">\n");
return;
case ZigTypeIdVector:
case ZigTypeIdArray:
case ZigTypeIdNull:
case ZigTypeIdErrorSet:
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
case ZigTypeIdOpaque:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
case ZigTypeIdEnumLiteral:
fprintf(stderr, "<TODO dump value>\n");
return;
}
zig_unreachable();
}
void ZigValue::dump() {
dump_value_indent(this, 0);
}
// float ops that take a single argument // float ops that take a single argument
//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, lround, llround, lrint, llrint //TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, lround, llround, lrint, llrint
const char *float_op_to_name(BuiltinFnId op) { const char *float_op_to_name(BuiltinFnId op) {

View File

@ -20,6 +20,7 @@
#include "zig_llvm.h" #include "zig_llvm.h"
#include "userland.h" #include "userland.h"
#include "dump_analysis.hpp" #include "dump_analysis.hpp"
#include "softfloat.hpp"
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
@ -3119,8 +3120,14 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutableGen *executab
static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutableGen *executable, static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutableGen *executable,
IrInstGenCast *cast_instruction) IrInstGenCast *cast_instruction)
{ {
Error err;
ZigType *actual_type = cast_instruction->value->value->type; ZigType *actual_type = cast_instruction->value->value->type;
ZigType *wanted_type = cast_instruction->base.value->type; ZigType *wanted_type = cast_instruction->base.value->type;
bool wanted_type_has_bits;
if ((err = type_has_bits2(g, wanted_type, &wanted_type_has_bits)))
codegen_report_errors_and_exit(g);
if (!wanted_type_has_bits)
return nullptr;
LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value); LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value);
ir_assert(expr_val, &cast_instruction->base); ir_assert(expr_val, &cast_instruction->base);
@ -3498,6 +3505,7 @@ static void render_decl_var(CodeGen *g, ZigVar *var) {
static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutableGen *executable, IrInstGenDeclVar *instruction) { static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutableGen *executable, IrInstGenDeclVar *instruction) {
instruction->var->ptr_instruction = instruction->var_ptr; instruction->var->ptr_instruction = instruction->var_ptr;
instruction->var->did_the_decl_codegen = true;
render_decl_var(g, instruction->var); render_decl_var(g, instruction->var);
return nullptr; return nullptr;
} }
@ -3966,7 +3974,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
return; return;
case ScopeIdVarDecl: { case ScopeIdVarDecl: {
ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var; ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
if (var->ptr_instruction != nullptr) { if (var->did_the_decl_codegen) {
render_decl_var(g, var); render_decl_var(g, var);
} }
// fallthrough // fallthrough
@ -4723,6 +4731,10 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutableGen *e
LLVMPositionBuilderAtEnd(g->builder, ok_block); LLVMPositionBuilderAtEnd(g->builder, ok_block);
} }
if (!type_has_bits(child_type)) { if (!type_has_bits(child_type)) {
if (instruction->initializing) {
LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false);
gen_store_untyped(g, non_null_bit, base_ptr, 0, false);
}
return nullptr; return nullptr;
} else { } else {
bool is_scalar = !handle_is_ptr(maybe_type); bool is_scalar = !handle_is_ptr(maybe_type);
@ -7529,7 +7541,7 @@ static void do_code_gen(CodeGen *g) {
} else { } else {
if (want_sret) { if (want_sret) {
g->cur_ret_ptr = LLVMGetParam(fn, 0); g->cur_ret_ptr = LLVMGetParam(fn, 0);
} else if (handle_is_ptr(fn_type_id->return_type)) { } else if (type_has_bits(fn_type_id->return_type)) {
g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0); g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
// TODO add debug info variable for this // TODO add debug info variable for this
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@ -16,15 +16,15 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
ZigType *var_type, const char *name_hint); ZigType *var_type, const char *name_hint);
ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigValue *return_ptr, size_t *backward_branch_count, size_t *backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutableGen *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef); IrExecutableGen *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef);
Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val); Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val);
ZigType *ir_analyze(CodeGen *g, IrExecutableSrc *old_executable, IrExecutableGen *new_executable, ZigType *ir_analyze(CodeGen *g, IrExecutableSrc *old_executable, IrExecutableGen *new_executable,
ZigType *expected_type, AstNode *expected_type_source_node); ZigType *expected_type, AstNode *expected_type_source_node, ZigValue *return_ptr);
bool ir_inst_gen_has_side_effects(IrInstGen *inst); bool ir_inst_gen_has_side_effects(IrInstGen *inst);
bool ir_inst_src_has_side_effects(IrInstSrc *inst); bool ir_inst_src_has_side_effects(IrInstSrc *inst);

View File

@ -12,4 +12,21 @@ extern "C" {
#include "softfloat.h" #include "softfloat.h"
} }
static inline float16_t zig_double_to_f16(double x) {
float64_t y;
static_assert(sizeof(x) == sizeof(y), "");
memcpy(&y, &x, sizeof(x));
return f64_to_f16(y);
}
// Return value is safe to coerce to float even when |x| is NaN or Infinity.
static inline double zig_f16_to_double(float16_t x) {
float64_t y = f16_to_f64(x);
double z;
static_assert(sizeof(y) == sizeof(z), "");
memcpy(&z, &y, sizeof(y));
return z;
}
#endif #endif

View File

@ -38,6 +38,8 @@
#if defined(__MINGW32__) || defined(__MINGW64__) #if defined(__MINGW32__) || defined(__MINGW64__)
#define BREAKPOINT __debugbreak() #define BREAKPOINT __debugbreak()
#elif defined(__i386__) || defined(__x86_64__)
#define BREAKPOINT __asm__ volatile("int $0x03");
#elif defined(__clang__) #elif defined(__clang__)
#define BREAKPOINT __builtin_debugtrap() #define BREAKPOINT __builtin_debugtrap()
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -49,8 +51,6 @@
#endif #endif
#include "softfloat.hpp"
ATTRIBUTE_COLD ATTRIBUTE_COLD
ATTRIBUTE_NORETURN ATTRIBUTE_NORETURN
ATTRIBUTE_PRINTF(1, 2) ATTRIBUTE_PRINTF(1, 2)
@ -244,23 +244,6 @@ static inline uint8_t log2_u64(uint64_t x) {
return (63 - clzll(x)); return (63 - clzll(x));
} }
static inline float16_t zig_double_to_f16(double x) {
float64_t y;
static_assert(sizeof(x) == sizeof(y), "");
memcpy(&y, &x, sizeof(x));
return f64_to_f16(y);
}
// Return value is safe to coerce to float even when |x| is NaN or Infinity.
static inline double zig_f16_to_double(float16_t x) {
float64_t y = f16_to_f64(x);
double z;
static_assert(sizeof(y) == sizeof(z), "");
memcpy(&z, &y, sizeof(y));
return z;
}
void zig_pretty_print_bytes(FILE *f, double n); void zig_pretty_print_bytes(FILE *f, double n);
template<typename T> template<typename T>

View File

@ -1658,7 +1658,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest("return invalid type from test", cases.addTest("return invalid type from test",
\\test "example" { return 1; } \\test "example" { return 1; }
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:1:25: error: integer value 1 cannot be coerced to type 'void'", "tmp.zig:1:25: error: expected type 'void', found 'comptime_int'",
}); });
cases.add("threadlocal qualifier on const", cases.add("threadlocal qualifier on const",
@ -2487,7 +2487,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var rule_set = try Foo.init(); \\ var rule_set = try Foo.init();
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:2:10: error: expected type 'i32', found 'type'", "tmp.zig:2:19: error: expected type 'i32', found 'type'",
}); });
cases.add("slicing single-item pointer", cases.add("slicing single-item pointer",
@ -3393,7 +3393,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ \\
\\fn b() void {} \\fn b() void {}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:3:6: error: unreachable code", "tmp.zig:3:5: error: unreachable code",
}); });
cases.add("bad import", cases.add("bad import",
@ -4011,8 +4011,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ \\
\\export fn entry() usize { return @sizeOf(@TypeOf(Foo)); } \\export fn entry() usize { return @sizeOf(@TypeOf(Foo)); }
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:5:25: error: unable to evaluate constant expression", "tmp.zig:5:25: error: cannot store runtime value in compile time variable",
"tmp.zig:2:12: note: referenced here", "tmp.zig:2:12: note: called from here",
}); });
cases.add("addition with non numbers", cases.add("addition with non numbers",
@ -4652,7 +4652,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn something() anyerror!void { } \\fn something() anyerror!void { }
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:2:5: error: expected type 'void', found 'anyerror'", "tmp.zig:2:5: error: expected type 'void', found 'anyerror'",
"tmp.zig:1:15: note: return type declared here",
}); });
cases.add("invalid pointer for var type", cases.add("invalid pointer for var type",
@ -5743,7 +5742,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ @export(entry, .{.name = "entry", .linkage = @as(u32, 1234) }); \\ @export(entry, .{.name = "entry", .linkage = @as(u32, 1234) });
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
"tmp.zig:3:50: error: expected type 'std.builtin.GlobalLinkage', found 'u32'", "tmp.zig:3:59: error: expected type 'std.builtin.GlobalLinkage', found 'comptime_int'",
}); });
cases.add("struct with invalid field", cases.add("struct with invalid field",

View File

@ -167,3 +167,23 @@ test "nested bitcast" {
S.foo(42); S.foo(42);
comptime S.foo(42); comptime S.foo(42);
} }
test "bitcast passed as tuple element" {
const S = struct {
fn foo(args: var) void {
comptime expect(@TypeOf(args[0]) == f32);
expect(args[0] == 12.34);
}
};
S.foo(.{@bitCast(f32, @as(u32, 0x414570A4))});
}
test "triple level result location with bitcast sandwich passed as tuple element" {
const S = struct {
fn foo(args: var) void {
comptime expect(@TypeOf(args[0]) == f64);
expect(args[0] > 12.33 and args[0] < 12.35);
}
};
S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))});
}

View File

@ -804,3 +804,16 @@ test "comptime assign int to optional int" {
expectEqual(20, x.?); expectEqual(20, x.?);
} }
} }
test "return 0 from function that has u0 return type" {
const S = struct {
fn foo_zero() u0 {
return 0;
}
};
comptime {
if (S.foo_zero() != 0) {
@compileError("test failed");
}
}
}

View File

@ -72,7 +72,7 @@ test "const result loc, runtime if cond, else unreachable" {
var t = true; var t = true;
const x = if (t) Num.Two else unreachable; const x = if (t) Num.Two else unreachable;
if (x != .Two) @compileError("bad"); expect(x == .Two);
} }
test "if prongs cast to expected type instead of peer type resolution" { test "if prongs cast to expected type instead of peer type resolution" {

View File

@ -781,3 +781,16 @@ test "pointer to thread local array" {
std.mem.copy(u8, buffer[0..], s); std.mem.copy(u8, buffer[0..], s);
std.testing.expectEqualSlices(u8, buffer[0..], s); std.testing.expectEqualSlices(u8, buffer[0..], s);
} }
test "auto created variables have correct alignment" {
const S = struct {
fn foo(str: [*]const u8) u32 {
for (@ptrCast([*]align(1) const u32, str)[0..1]) |v| {
return v;
}
return 0;
}
};
expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
}

View File

@ -153,3 +153,25 @@ test "optional with void type" {
var x = Foo{ .x = null }; var x = Foo{ .x = null };
expect(x.x == null); expect(x.x == null);
} }
test "0-bit child type coerced to optional return ptr result location" {
const S = struct {
fn doTheTest() void {
var y = Foo{};
var z = y.thing();
expect(z != null);
}
const Foo = struct {
pub const Bar = struct {
field: *Foo,
};
pub fn thing(self: *Foo) ?Bar {
return Bar{ .field = self };
}
};
};
S.doTheTest();
comptime S.doTheTest();
}

View File

@ -1,5 +1,6 @@
const expect = @import("std").testing.expect; const std = @import("std");
const mem = @import("std").mem; const expect = std.testing.expect;
const mem = std.mem;
fn initStaticArray() [10]i32 { fn initStaticArray() [10]i32 {
var array: [10]i32 = undefined; var array: [10]i32 = undefined;