authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 14:46:22-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-29 14:46:22-04:00
log0512beca9d694a667e3ad12a656835b44457fbcd
tree66f1751961a0432cb0ac804f4b4a324b82b85942
parentd9f0446b1f993c1b3c1bf5cc410b6d5f8a2f94fe
signaturelock-open Commit is signed but in an unrecognized format.

comparing against zero participates in lazy values


6 files changed, 109 insertions(+), 1 deletions(-)

src/analyze.cpp+1-1
......@@ -973,7 +973,7 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig
973973 nullptr, nullptr, node, type_name, nullptr, nullptr, undef);
974974}
975975
976static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
976Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
977977 ConstExprValue *parent_type_val, bool *is_zero_bits)
978978{
979979 Error err;
src/analyze.hpp+2
......@@ -249,6 +249,8 @@ bool fn_is_async(ZigFn *fn);
249249Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
250250Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
251251 size_t *abi_size, size_t *size_in_bits);
252Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
253 ConstExprValue *parent_type_val, bool *is_zero_bits);
252254ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);
253255ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
254256
src/error.cpp+1
......@@ -55,6 +55,7 @@ const char *err_str(Error err) {
5555 case ErrorBrokenPipe: return "broken pipe";
5656 case ErrorNoSpaceLeft: return "no space left";
5757 case ErrorNoCCompilerInstalled: return "no C compiler installed";
58 case ErrorNotLazy: return "not lazy";
5859 }
5960 return "(invalid error)";
6061}
src/ir.cpp+89
......@@ -12932,7 +12932,52 @@ static bool optional_value_is_null(ConstExprValue *val) {
1293212932 }
1293312933}
1293412934
12935// Returns ErrorNotLazy when the value cannot be determined
12936static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {
12937 Error err;
12938
12939 switch (val->special) {
12940 case ConstValSpecialRuntime:
12941 case ConstValSpecialUndef:
12942 return ErrorNotLazy;
12943 case ConstValSpecialStatic:
12944 switch (val->type->id) {
12945 case ZigTypeIdComptimeInt:
12946 case ZigTypeIdInt:
12947 *result = bigint_cmp_zero(&val->data.x_bigint);
12948 return ErrorNone;
12949 default:
12950 return ErrorNotLazy;
12951 }
12952 case ConstValSpecialLazy:
12953 switch (val->data.x_lazy->id) {
12954 case LazyValueIdInvalid:
12955 zig_unreachable();
12956 case LazyValueIdAlignOf:
12957 *result = CmpGT;
12958 return ErrorNone;
12959 case LazyValueIdSizeOf: {
12960 LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy);
12961 IrAnalyze *ira = lazy_size_of->ira;
12962 bool is_zero_bits;
12963 if ((err = type_val_resolve_zero_bits(ira->codegen, &lazy_size_of->target_type->value,
12964 nullptr, nullptr, &is_zero_bits)))
12965 {
12966 return err;
12967 }
12968 *result = is_zero_bits ? CmpEQ : CmpGT;
12969 return ErrorNone;
12970 }
12971 default:
12972 return ErrorNotLazy;
12973 }
12974 }
12975 zig_unreachable();
12976}
12977
1293512978static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
12979 Error err;
12980
1293612981 IrInstruction *op1 = bin_op_instruction->op1->child;
1293712982 if (type_is_invalid(op1->value.type))
1293812983 return ira->codegen->invalid_instruction;
......@@ -13182,6 +13227,50 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1318213227 }
1318313228
1318413229 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
13230 {
13231 // Before resolving the values, we special case comparisons against zero. These can often be done
13232 // without resolving lazy values, preventing potential dependency loops.
13233 Cmp op1_cmp_zero;
13234 if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op1->value, &op1_cmp_zero))) {
13235 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
13236 return ira->codegen->invalid_instruction;
13237 }
13238 Cmp op2_cmp_zero;
13239 if ((err = lazy_cmp_zero(bin_op_instruction->base.source_node, &casted_op2->value, &op2_cmp_zero))) {
13240 if (err == ErrorNotLazy) goto never_mind_just_calculate_it_normally;
13241 return ira->codegen->invalid_instruction;
13242 }
13243 bool can_cmp_zero = false;
13244 Cmp cmp_result;
13245 if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpEQ) {
13246 can_cmp_zero = true;
13247 cmp_result = CmpEQ;
13248 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpEQ) {
13249 can_cmp_zero = true;
13250 cmp_result = CmpGT;
13251 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpGT) {
13252 can_cmp_zero = true;
13253 cmp_result = CmpLT;
13254 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpEQ) {
13255 can_cmp_zero = true;
13256 cmp_result = CmpLT;
13257 } else if (op1_cmp_zero == CmpEQ && op2_cmp_zero == CmpLT) {
13258 can_cmp_zero = true;
13259 cmp_result = CmpGT;
13260 } else if (op1_cmp_zero == CmpLT && op2_cmp_zero == CmpGT) {
13261 can_cmp_zero = true;
13262 cmp_result = CmpLT;
13263 } else if (op1_cmp_zero == CmpGT && op2_cmp_zero == CmpLT) {
13264 can_cmp_zero = true;
13265 cmp_result = CmpGT;
13266 }
13267 if (can_cmp_zero) {
13268 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13269 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13270 }
13271 }
13272never_mind_just_calculate_it_normally:
13273
1318513274 ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
1318613275 if (op1_val == nullptr)
1318713276 return ira->codegen->invalid_instruction;
src/userland.h+1
......@@ -75,6 +75,7 @@ enum Error {
7575 ErrorOperationAborted,
7676 ErrorBrokenPipe,
7777 ErrorNoSpaceLeft,
78 ErrorNotLazy,
7879};
7980
8081// ABI warning
test/stage1/behavior/sizeof_and_typeof.zig+15
......@@ -74,3 +74,18 @@ test "@sizeOf on compile-time types" {
7474 expect(@sizeOf(@typeOf(.hi)) == 0);
7575 expect(@sizeOf(@typeOf(type)) == 0);
7676}
77
78test "@sizeOf(T) == 0 doesn't force resolving struct size" {
79 const S = struct {
80 const Foo = struct {
81 y: if (@sizeOf(Foo) == 0) u64 else u32,
82 };
83 const Bar = struct {
84 x: i32,
85 y: if (0 == @sizeOf(Bar)) u64 else u32,
86 };
87 };
88
89 expect(@sizeOf(S.Foo) == 4);
90 expect(@sizeOf(S.Bar) == 8);
91}