authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-07-31 10:55:53-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 10:36:10-04:00
log74ce5e9e13014d2657bf00b5893fd4687c7f0359
tree7d635c5ebb7082af3f74237df4d94355fab1d003
parent558b4ac1f0fd7123ebe25f3e59eef275b066c50a
signature Commit is signed but in an unrecognized format.

stage1: proper return type on vector comparisons


2 files changed, 92 insertions(+), 46 deletions(-)

src/ir.cpp+75-46
...@@ -13092,6 +13092,59 @@ static bool optional_value_is_null(ConstExprValue *val) {...@@ -13092,6 +13092,59 @@ static bool optional_value_is_null(ConstExprValue *val) {
13092 }13092 }
13093}13093}
1309413094
13095static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type,
13096 ConstExprValue *op1_val, ConstExprValue *op2_val, IrInstructionBinOp *bin_op_instruction, IrBinOp op_id,
13097 bool one_possible_value) {
13098 if (op1_val->special == ConstValSpecialUndef ||
13099 op2_val->special == ConstValSpecialUndef)
13100 return ir_const_undef(ira, &bin_op_instruction->base, resolved_type);
13101 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
13102 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {
13103 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);
13104 }
13105 Cmp cmp_result = float_cmp(op1_val, op2_val);
13106 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13107 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13108 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
13109 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
13110 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13111 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13112 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
13113 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
13114 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
13115 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
13116 op2_val->data.x_ptr.special == ConstPtrSpecialNull))
13117 {
13118 uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
13119 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
13120 uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
13121 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
13122 Cmp cmp_result;
13123 if (op1_addr > op2_addr) {
13124 cmp_result = CmpGT;
13125 } else if (op1_addr < op2_addr) {
13126 cmp_result = CmpLT;
13127 } else {
13128 cmp_result = CmpEQ;
13129 }
13130 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13131 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13132 }
13133 } else {
13134 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
13135 bool answer;
13136 if (op_id == IrBinOpCmpEq) {
13137 answer = are_equal;
13138 } else if (op_id == IrBinOpCmpNotEq) {
13139 answer = !are_equal;
13140 } else {
13141 zig_unreachable();
13142 }
13143 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13144 }
13145 zig_unreachable();
13146}
13147
13095// Returns ErrorNotLazy when the value cannot be determined13148// Returns ErrorNotLazy when the value cannot be determined
13096static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {13149static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {
13097 Error err;13150 Error err;
...@@ -13427,7 +13480,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13427,7 +13480,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13427 }13480 }
1342813481
13429 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {13482 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
13430 {13483 // TODO do we need lazy values on vector comparisons?
13484 if (resolved_type->id != ZigTypeIdVector) {
13431 // Before resolving the values, we special case comparisons against zero. These can often be done13485 // Before resolving the values, we special case comparisons against zero. These can often be done
13432 // without resolving lazy values, preventing potential dependency loops.13486 // without resolving lazy values, preventing potential dependency loops.
13433 Cmp op1_cmp_zero;13487 Cmp op1_cmp_zero;
...@@ -13477,51 +13531,22 @@ never_mind_just_calculate_it_normally:...@@ -13477,51 +13531,22 @@ never_mind_just_calculate_it_normally:
13477 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);13531 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
13478 if (op2_val == nullptr)13532 if (op2_val == nullptr)
13479 return ira->codegen->invalid_instruction;13533 return ira->codegen->invalid_instruction;
1348013534 if (resolved_type->id != ZigTypeIdVector)
13481 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {13535 return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, bin_op_instruction, op_id, one_possible_value);
13482 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {13536 IrInstruction *result = ir_const(ira, &bin_op_instruction->base,
13483 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);13537 get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool));
13484 }13538 result->value.data.x_array.data.s_none.elements =
13485 Cmp cmp_result = float_cmp(op1_val, op2_val);13539 create_const_vals(resolved_type->data.vector.len);
13486 bool answer = resolve_cmp_op_id(op_id, cmp_result);13540
13487 return ir_const_bool(ira, &bin_op_instruction->base, answer);13541 expand_undef_array(ira->codegen, &result->value);
13488 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {13542 for (size_t i = 0;i < resolved_type->data.vector.len;i++) {
13489 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);13543 IrInstruction *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type,
13490 bool answer = resolve_cmp_op_id(op_id, cmp_result);13544 &op1_val->data.x_array.data.s_none.elements[i],
13491 return ir_const_bool(ira, &bin_op_instruction->base, answer);13545 &op2_val->data.x_array.data.s_none.elements[i],
13492 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {13546 bin_op_instruction, op_id, one_possible_value);
13493 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||13547 copy_const_val(&result->value.data.x_array.data.s_none.elements[i], &cur_res->value, false);
13494 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
13495 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
13496 op2_val->data.x_ptr.special == ConstPtrSpecialNull))
13497 {
13498 uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
13499 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
13500 uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
13501 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
13502 Cmp cmp_result;
13503 if (op1_addr > op2_addr) {
13504 cmp_result = CmpGT;
13505 } else if (op1_addr < op2_addr) {
13506 cmp_result = CmpLT;
13507 } else {
13508 cmp_result = CmpEQ;
13509 }
13510 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13511 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13512 }
13513 } else {
13514 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
13515 bool answer;
13516 if (op_id == IrBinOpCmpEq) {
13517 answer = are_equal;
13518 } else if (op_id == IrBinOpCmpNotEq) {
13519 answer = !are_equal;
13520 } else {
13521 zig_unreachable();
13522 }
13523 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13524 }13548 }
13549 return result;
13525 }13550 }
1352613551
13527 // some comparisons with unsigned numbers can be evaluated13552 // some comparisons with unsigned numbers can be evaluated
...@@ -13564,7 +13589,11 @@ never_mind_just_calculate_it_normally:...@@ -13564,7 +13589,11 @@ never_mind_just_calculate_it_normally:
13564 IrInstruction *result = ir_build_bin_op(&ira->new_irb,13589 IrInstruction *result = ir_build_bin_op(&ira->new_irb,
13565 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,13590 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
13566 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);13591 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);
13567 result->value.type = ira->codegen->builtin_types.entry_bool;13592 if (resolved_type->id == ZigTypeIdVector)
13593 result->value.type = get_vector_type(ira->codegen, resolved_type->data.vector.len,
13594 ira->codegen->builtin_types.entry_bool);
13595 else
13596 result->value.type = ira->codegen->builtin_types.entry_bool;
13568 return result;13597 return result;
13569}13598}
1357013599
test/stage1/behavior/vector.zig+17
...@@ -30,6 +30,23 @@ test "vector wrap operators" {...@@ -30,6 +30,23 @@ test "vector wrap operators" {
30 comptime S.doTheTest();30 comptime S.doTheTest();
31}31}
3232
33test "vector bin compares with mem.eql" {
34 const S = struct {
35 fn doTheTest() void {
36 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
37 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };
38 expect(mem.eql(bool, ([4]bool)(v == x), [4]bool{ false, false, true, false}));
39 expect(mem.eql(bool, ([4]bool)(v != x), [4]bool{ true, true, false, true}));
40 expect(mem.eql(bool, ([4]bool)(v < x), [4]bool{ false, true, false, false}));
41 expect(mem.eql(bool, ([4]bool)(v > x), [4]bool{ true, false, false, true}));
42 expect(mem.eql(bool, ([4]bool)(v <= x), [4]bool{ false, true, true, false}));
43 expect(mem.eql(bool, ([4]bool)(v >= x), [4]bool{ true, false, true, true}));
44 }
45 };
46 S.doTheTest();
47 comptime S.doTheTest();
48}
49
33test "vector int operators" {50test "vector int operators" {
34 const S = struct {51 const S = struct {
35 fn doTheTest() void {52 fn doTheTest() void {