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 *
99009900 return ir_implicit_cast(ira, result_instruction, type_entry);
99019901}
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
99039997static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *bin_op_instruction) {
99049998 Stage1AirInst *op1 = bin_op_instruction->op1->child;
99059999 if (type_is_invalid(op1->value->type))
......@@ -9951,6 +10045,12 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b
995110045 // comptime_int has no finite bit width
995210046 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
995410054 if (op_id == IrBinOpBitShiftLeftLossy) {
995510055 op_id = IrBinOpBitShiftLeftExact;
995610056 }
......@@ -9972,6 +10072,13 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b
997210072 buf_sprintf("shift by negative value %s", buf_ptr(val_buf)));
997310073 return ira->codegen->invalid_inst_gen;
997410074 }
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;
997510082 } else {
997610083 const unsigned bit_count = op1_scalar_type->data.integral.bit_count;
997710084 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
1003010137 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);
1003110138 }
1003210139
10033 return ir_build_bin_op_gen(ira, bin_op_instruction->base.scope, bin_op_instruction->base.source_node, op1->value->type,
10034 op_id, op1, casted_op2, bin_op_instruction->safety_check_on);
10140 return ir_build_bin_op_gen(ira,
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);
1003510143}
1003610144
1003710145static bool ok_float_op(IrBinOp op) {
......@@ -11035,6 +11143,7 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
1103511143 case IrBinOpBitShiftLeftExact:
1103611144 case IrBinOpBitShiftRightLossy:
1103711145 case IrBinOpBitShiftRightExact:
11146 case IrBinOpShlSat:
1103811147 return ir_analyze_bit_shift(ira, bin_op_instruction);
1103911148 case IrBinOpBinOr:
1104011149 case IrBinOpBinXor:
......@@ -11057,7 +11166,6 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
1105711166 case IrBinOpAddSat:
1105811167 case IrBinOpSubSat:
1105911168 case IrBinOpMultSat:
11060 case IrBinOpShlSat:
1106111169 return ir_analyze_bin_op_math(ira, bin_op_instruction);
1106211170 case IrBinOpArrayCat:
1106311171 return ir_analyze_array_cat(ira, bin_op_instruction);
......@@ -20017,59 +20125,13 @@ static Stage1AirInst *ir_analyze_instruction_truncate(IrAnalyze *ira, Stage1ZirI
2001720125 if (type_is_invalid(dest_type))
2001820126 return ira->codegen->invalid_inst_gen;
2001920127
20020 if (dest_type->id != ZigTypeIdInt &&
20021 dest_type->id != ZigTypeIdComptimeInt)
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)));
20128 Stage1AirInst *operand = instruction->target->child;
20129 if (type_is_invalid(operand->value->type))
2003620130 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) {
20044 if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) {
20045 const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned";
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);
20132 return ir_analyze_truncate(ira, instruction->base.scope, instruction->base.source_node,
20133 dest_type, instruction->dest_type->source_node,
20134 operand, instruction->target->source_node);
2007320135}
2007420136
2007520137static Stage1AirInst *ir_analyze_int_cast(IrAnalyze *ira, Scope *scope, AstNode *source_node,
test/behavior.zig+2
......@@ -171,6 +171,7 @@ test {
171171 _ = @import("behavior/popcount_stage1.zig");
172172 _ = @import("behavior/ptrcast_stage1.zig");
173173 _ = @import("behavior/reflection.zig");
174 _ = @import("behavior/saturating_arithmetic_stage1.zig");
174175 _ = @import("behavior/select.zig");
175176 _ = @import("behavior/shuffle.zig");
176177 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
......@@ -181,6 +182,7 @@ test {
181182 _ = @import("behavior/switch_prong_err_enum.zig");
182183 _ = @import("behavior/switch_prong_implicit_cast.zig");
183184 _ = @import("behavior/switch_stage1.zig");
185 _ = @import("behavior/truncate_stage1.zig");
184186 _ = @import("behavior/try.zig");
185187 _ = @import("behavior/tuple.zig");
186188 _ = @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}