authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-08 15:19:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-08 15:25:31-07:00
log38b2d6209239f0dad7cb38e656d9d38506f126ca
tree93482ff72c52c99608fd5514ee683f3fbec80e30
parent64e2bfaa236c14b403103c92691fa6774e1fdc83

stage1: saturating shl operates using LHS type

Saturating shift left (`<<|`) previously used the `ir_analyze_bin_op_math` codepath rather than the `ir_analyze_bit_shift` codepath, leading to it doing peer type resolution (incorrect) instead of using the LHS type as the number of bits to do the saturating against. This required implementing SIMD vector support for `@truncate`. Additionall, this commit adds a compile error for saturating shift left on a comptime_int. stage2 does not pass these new behavior tests yet. closes #10298

4 files changed, 153 insertions(+), 54 deletions(-)

src/stage1/ir.cpp+116-54
...@@ -9900,6 +9900,100 @@ static Stage1AirInst *ir_analyze_math_op(IrAnalyze *ira, Scope *scope, AstNode *...@@ -9900,6 +9900,100 @@ static Stage1AirInst *ir_analyze_math_op(IrAnalyze *ira, Scope *scope, AstNode *
9900 return ir_implicit_cast(ira, result_instruction, type_entry);9900 return ir_implicit_cast(ira, result_instruction, type_entry);
9901}9901}
99029902
9903static Stage1AirInst *ir_analyze_truncate(IrAnalyze *ira, Scope *scope, AstNode *source_node,
9904 ZigType *dest_scalar_type, AstNode *dest_type_node,
9905 Stage1AirInst *operand, AstNode *operand_node)
9906{
9907 if (dest_scalar_type->id != ZigTypeIdInt &&
9908 dest_scalar_type->id != ZigTypeIdComptimeInt)
9909 {
9910 ir_add_error_node(ira, dest_type_node,
9911 buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_scalar_type->name)));
9912 return ira->codegen->invalid_inst_gen;
9913 }
9914
9915 ZigType *src_type = operand->value->type;
9916 bool is_vector = (src_type->id == ZigTypeIdVector);
9917 ZigType *src_scalar_type = is_vector ?
9918 src_type->data.vector.elem_type : src_type;
9919
9920 ZigType *dest_type = is_vector ?
9921 get_vector_type(ira->codegen, src_type->data.vector.len, dest_scalar_type) :
9922 dest_scalar_type;
9923
9924 if (src_scalar_type->id != ZigTypeIdInt && src_scalar_type->id != ZigTypeIdComptimeInt) {
9925 ir_add_error_node(ira, operand_node,
9926 buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_scalar_type->name)));
9927 return ira->codegen->invalid_inst_gen;
9928 }
9929
9930 if (dest_scalar_type->id == ZigTypeIdComptimeInt) {
9931 return ir_implicit_cast2(ira, scope, operand_node, operand, dest_type);
9932 }
9933
9934 if (src_scalar_type->id != ZigTypeIdComptimeInt) {
9935 if (src_scalar_type->data.integral.is_signed != dest_scalar_type->data.integral.is_signed) {
9936 const char *sign_str = dest_scalar_type->data.integral.is_signed ? "signed" : "unsigned";
9937 ir_add_error_node(ira, operand_node, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_scalar_type->name)));
9938 return ira->codegen->invalid_inst_gen;
9939 } else if (src_scalar_type->data.integral.bit_count > 0 && src_scalar_type->data.integral.bit_count < dest_scalar_type->data.integral.bit_count) {
9940 ir_add_error_node(ira, operand_node, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
9941 buf_ptr(&src_scalar_type->name), buf_ptr(&dest_scalar_type->name)));
9942 return ira->codegen->invalid_inst_gen;
9943 }
9944 }
9945
9946 if (instr_is_comptime(operand)) {
9947 ZigValue *val = ir_resolve_const(ira, operand, UndefBad);
9948 if (val == nullptr)
9949 return ira->codegen->invalid_inst_gen;
9950
9951 if (!is_vector) {
9952 Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type);
9953 bigint_truncate(&result->value->data.x_bigint, &val->data.x_bigint,
9954 dest_scalar_type->data.integral.bit_count,
9955 dest_scalar_type->data.integral.is_signed);
9956 return result;
9957 }
9958
9959 Stage1AirInst *result_instruction = ir_const(ira, scope, source_node, dest_type);
9960 ZigValue *out_val = result_instruction->value;
9961 expand_undef_array(ira->codegen, operand->value);
9962 out_val->special = ConstValSpecialUndef;
9963 expand_undef_array(ira->codegen, out_val);
9964 size_t len = dest_type->data.vector.len;
9965 for (size_t i = 0; i < len; i += 1) {
9966 ZigValue *scalar_operand_val = &operand->value->data.x_array.data.s_none.elements[i];
9967 ZigValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
9968 assert(scalar_operand_val->type == dest_scalar_type);
9969 assert(scalar_out_val->type == dest_scalar_type);
9970
9971 bigint_truncate(&scalar_out_val->data.x_bigint,
9972 &scalar_operand_val->data.x_bigint,
9973 dest_scalar_type->data.integral.bit_count,
9974 dest_scalar_type->data.integral.is_signed);
9975
9976 scalar_out_val->type = dest_scalar_type;
9977 scalar_out_val->special = ConstValSpecialStatic;
9978 }
9979 out_val->type = dest_type;
9980 out_val->special = ConstValSpecialStatic;
9981 return result_instruction;
9982 }
9983
9984 if (src_scalar_type->data.integral.bit_count == 0 ||
9985 dest_scalar_type->data.integral.bit_count == 0)
9986 {
9987 Stage1AirInst *result = ir_const(ira, scope, source_node, dest_type);
9988 if (!is_vector) {
9989 bigint_init_unsigned(&result->value->data.x_bigint, 0);
9990 }
9991 return result;
9992 }
9993
9994 return ir_build_truncate_gen(ira, scope, source_node, dest_type, operand);
9995}
9996
9903static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) {9997static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) {
9904 Stage1AirInst *op1 = bin_op_instruction->op1->child;9998 Stage1AirInst *op1 = bin_op_instruction->op1->child;
9905 if (type_is_invalid(op1->value->type))9999 if (type_is_invalid(op1->value->type))
...@@ -9951,6 +10045,12 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b...@@ -9951,6 +10045,12 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b
9951 // comptime_int has no finite bit width10045 // comptime_int has no finite bit width
9952 casted_op2 = op2;10046 casted_op2 = op2;
995310047
10048 if (op_id == IrBinOpShlSat) {
10049 ir_add_error_node(ira, bin_op_instruction->base.source_node,
10050 buf_sprintf("saturating shift on a comptime_int which has unlimited bits"));
10051 return ira->codegen->invalid_inst_gen;
10052 }
10053
9954 if (op_id == IrBinOpBitShiftLeftLossy) {10054 if (op_id == IrBinOpBitShiftLeftLossy) {
9955 op_id = IrBinOpBitShiftLeftExact;10055 op_id = IrBinOpBitShiftLeftExact;
9956 }10056 }
...@@ -9972,6 +10072,13 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b...@@ -9972,6 +10072,13 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b
9972 buf_sprintf("shift by negative value %s", buf_ptr(val_buf)));10072 buf_sprintf("shift by negative value %s", buf_ptr(val_buf)));
9973 return ira->codegen->invalid_inst_gen;10073 return ira->codegen->invalid_inst_gen;
9974 }10074 }
10075 } else if (op_id == IrBinOpShlSat) {
10076 casted_op2 = ir_analyze_truncate(ira,
10077 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
10078 op1_scalar_type, bin_op_instruction->op1->source_node,
10079 op2, bin_op_instruction->op2->source_node);
10080 if (type_is_invalid(casted_op2->value->type))
10081 return ira->codegen->invalid_inst_gen;
9975 } else {10082 } else {
9976 const unsigned bit_count = op1_scalar_type->data.integral.bit_count;10083 const unsigned bit_count = op1_scalar_type->data.integral.bit_count;
9977 ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,10084 ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
...@@ -10030,8 +10137,9 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b...@@ -10030,8 +10137,9 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b
10030 return ir_analyze_math_op(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1_type, op1_val, op_id, op2_val);10137 return ir_analyze_math_op(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1_type, op1_val, op_id, op2_val);
10031 }10138 }
1003210139
10033 return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1->value->type,10140 return ir_build_bin_op_gen(ira,
10034 op_id, op1, casted_op2, bin_op_instruction->safety_check_on);10141 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
10142 op1->value->type, op_id, op1, casted_op2, bin_op_instruction->safety_check_on);
10035}10143}
1003610144
10037static bool ok_float_op(IrBinOp op) {10145static bool ok_float_op(IrBinOp op) {
...@@ -11035,6 +11143,7 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns...@@ -11035,6 +11143,7 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
11035 case IrBinOpBitShiftLeftExact:11143 case IrBinOpBitShiftLeftExact:
11036 case IrBinOpBitShiftRightLossy:11144 case IrBinOpBitShiftRightLossy:
11037 case IrBinOpBitShiftRightExact:11145 case IrBinOpBitShiftRightExact:
11146 case IrBinOpShlSat:
11038 return ir_analyze_bit_shift(ira, bin_op_instruction);11147 return ir_analyze_bit_shift(ira, bin_op_instruction);
11039 case IrBinOpBinOr:11148 case IrBinOpBinOr:
11040 case IrBinOpBinXor:11149 case IrBinOpBinXor:
...@@ -11057,7 +11166,6 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns...@@ -11057,7 +11166,6 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
11057 case IrBinOpAddSat:11166 case IrBinOpAddSat:
11058 case IrBinOpSubSat:11167 case IrBinOpSubSat:
11059 case IrBinOpMultSat:11168 case IrBinOpMultSat:
11060 case IrBinOpShlSat:
11061 return ir_analyze_bin_op_math(ira, bin_op_instruction);11169 return ir_analyze_bin_op_math(ira, bin_op_instruction);
11062 case IrBinOpArrayCat:11170 case IrBinOpArrayCat:
11063 return ir_analyze_array_cat(ira, bin_op_instruction);11171 return ir_analyze_array_cat(ira, bin_op_instruction);
...@@ -20017,59 +20125,13 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI...@@ -20017,59 +20125,13 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI
20017 if (type_is_invalid(dest_type))20125 if (type_is_invalid(dest_type))
20018 return ira->codegen->invalid_inst_gen;20126 return ira->codegen->invalid_inst_gen;
2001920127
20020 if (dest_type->id != ZigTypeIdInt &&20128 Stage1AirInst *operand = instruction->target->child;
20021 dest_type->id != ZigTypeIdComptimeInt)20129 if (type_is_invalid(operand->value->type))
20022 {
20023 ir_add_error(ira, dest_type_value, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
20024 return ira->codegen->invalid_inst_gen;
20025 }
20026
20027 Stage1AirInst *target = instruction->target->child;
20028 ZigType *src_type = target->value->type;
20029 if (type_is_invalid(src_type))
20030 return ira->codegen->invalid_inst_gen;
20031
20032 if (src_type->id != ZigTypeIdInt &&
20033 src_type->id != ZigTypeIdComptimeInt)
20034 {
20035 ir_add_error(ira, target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name)));
20036 return ira->codegen->invalid_inst_gen;20130 return ira->codegen->invalid_inst_gen;
20037 }
20038
20039 if (dest_type->id == ZigTypeIdComptimeInt) {
20040 return ir_implicit_cast2(ira, instruction->target->scope, instruction->target->source_node, target, dest_type);
20041 }
2004220131
20043 if (src_type->id != ZigTypeIdComptimeInt) {20132 return ir_analyze_truncate(ira, instruction->base.scope, instruction->base.source_node,
20044 if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {20133 dest_type, instruction->dest_type->source_node,
20045 const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";20134 operand, instruction->target->source_node);
20046 ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name)));
20047 return ira->codegen->invalid_inst_gen;
20048 } else if (src_type->data.integral.bit_count > 0 && src_type->data.integral.bit_count < dest_type->data.integral.bit_count) {
20049 ir_add_error(ira, target, buf_sprintf("type '%s' has fewer bits than destination type '%s'",
20050 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
20051 return ira->codegen->invalid_inst_gen;
20052 }
20053 }
20054
20055 if (instr_is_comptime(target)) {
20056 ZigValue *val = ir_resolve_const(ira, target, UndefBad);
20057 if (val == nullptr)
20058 return ira->codegen->invalid_inst_gen;
20059
20060 Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, dest_type);
20061 bigint_truncate(&result->value->data.x_bigint, &val->data.x_bigint,
20062 dest_type->data.integral.bit_count, dest_type->data.integral.is_signed);
20063 return result;
20064 }
20065
20066 if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) {
20067 Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, dest_type);
20068 bigint_init_unsigned(&result->value->data.x_bigint, 0);
20069 return result;
20070 }
20071
20072 return ir_build_truncate_gen(ira, instruction->base.scope, instruction->base.source_node, dest_type, target);
20073}20135}
2007420136
20075static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node,20137static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node,
test/behavior.zig+2
...@@ -171,6 +171,7 @@ test {...@@ -171,6 +171,7 @@ test {
171 _ = @import("behavior/popcount_stage1.zig");171 _ = @import("behavior/popcount_stage1.zig");
172 _ = @import("behavior/ptrcast_stage1.zig");172 _ = @import("behavior/ptrcast_stage1.zig");
173 _ = @import("behavior/reflection.zig");173 _ = @import("behavior/reflection.zig");
174 _ = @import("behavior/saturating_arithmetic_stage1.zig");
174 _ = @import("behavior/select.zig");175 _ = @import("behavior/select.zig");
175 _ = @import("behavior/shuffle.zig");176 _ = @import("behavior/shuffle.zig");
176 _ = @import("behavior/sizeof_and_typeof_stage1.zig");177 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
...@@ -181,6 +182,7 @@ test {...@@ -181,6 +182,7 @@ test {
181 _ = @import("behavior/switch_prong_err_enum.zig");182 _ = @import("behavior/switch_prong_err_enum.zig");
182 _ = @import("behavior/switch_prong_implicit_cast.zig");183 _ = @import("behavior/switch_prong_implicit_cast.zig");
183 _ = @import("behavior/switch_stage1.zig");184 _ = @import("behavior/switch_stage1.zig");
185 _ = @import("behavior/truncate_stage1.zig");
184 _ = @import("behavior/try.zig");186 _ = @import("behavior/try.zig");
185 _ = @import("behavior/tuple.zig");187 _ = @import("behavior/tuple.zig");
186 _ = @import("behavior/type.zig");188 _ = @import("behavior/type.zig");
test/behavior/saturating_arithmetic_stage1.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "saturating shl uses the LHS type" {
5 const lhs_const: u8 = 1;
6 var lhs_var: u8 = 1;
7
8 const rhs_const: usize = 8;
9 var rhs_var: usize = 8;
10
11 try expect((lhs_const <<| 8) == 255);
12 try expect((lhs_const <<| rhs_const) == 255);
13 try expect((lhs_const <<| rhs_var) == 255);
14
15 try expect((lhs_var <<| 8) == 255);
16 try expect((lhs_var <<| rhs_const) == 255);
17 try expect((lhs_var <<| rhs_var) == 255);
18
19 try expect((@as(u8, 1) <<| 8) == 255);
20 try expect((@as(u8, 1) <<| rhs_const) == 255);
21 try expect((@as(u8, 1) <<| rhs_var) == 255);
22}
test/behavior/truncate_stage1.zig created+13
...@@ -0,0 +1,13 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "truncate on vectors" {
5 const S = struct {
6 fn doTheTest() !void {
7 var v1: @Vector(4, u16) = .{ 0xaabb, 0xccdd, 0xeeff, 0x1122 };
8 var v2 = @truncate(u8, v1);
9 try expect(std.mem.eql(u8, &@as([4]u8, v2), &[4]u8{ 0xbb, 0xdd, 0xff, 0x22 }));
10 }
11 };
12 try S.doTheTest();
13}