authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 13:28:57-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 13:28:57-05:00
log52bb71867d8d6e738eefb7dafead875eb21a4ae7
tree317c8b0f23e603c590f943700587c3a6596bc8ff
parent2fe8a0831f2830a3357cdf65b2ebfe1214b13a83
signature Commit is signed but in an unrecognized format.

implement vector negation

also fix vector behavior tests, they weren't actually testing runtime vectors, but now they are. See #903

5 files changed, 157 insertions(+), 47 deletions(-)

src/codegen.cpp+6-5
......@@ -3229,7 +3229,8 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc
32293229static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) {
32303230 IrUnOp op_id = un_op_instruction->op_id;
32313231 LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value);
3232 ZigType *expr_type = un_op_instruction->value->value.type;
3232 ZigType *operand_type = un_op_instruction->value->value.type;
3233 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
32333234
32343235 switch (op_id) {
32353236 case IrUnOpInvalid:
......@@ -3239,16 +3240,16 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
32393240 case IrUnOpNegation:
32403241 case IrUnOpNegationWrap:
32413242 {
3242 if (expr_type->id == ZigTypeIdFloat) {
3243 if (scalar_type->id == ZigTypeIdFloat) {
32433244 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base));
32443245 return LLVMBuildFNeg(g->builder, expr, "");
3245 } else if (expr_type->id == ZigTypeIdInt) {
3246 } else if (scalar_type->id == ZigTypeIdInt) {
32463247 if (op_id == IrUnOpNegationWrap) {
32473248 return LLVMBuildNeg(g->builder, expr, "");
32483249 } else if (ir_want_runtime_safety(g, &un_op_instruction->base)) {
32493250 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
3250 return gen_overflow_op(g, expr_type, AddSubMulSub, zero, expr);
3251 } else if (expr_type->data.integral.is_signed) {
3251 return gen_overflow_op(g, operand_type, AddSubMulSub, zero, expr);
3252 } else if (scalar_type->data.integral.is_signed) {
32523253 return LLVMBuildNSWNeg(g->builder, expr, "");
32533254 } else {
32543255 return LLVMBuildNUWNeg(g->builder, expr, "");
src/ir.cpp+71-33
......@@ -14620,6 +14620,41 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
1462014620 zig_unreachable();
1462114621}
1462214622
14623static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type,
14624 ConstExprValue *operand_val, ConstExprValue *scalar_out_val, bool is_wrap_op)
14625{
14626 bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);
14627
14628 bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) ||
14629 scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op));
14630
14631 if (!ok_type) {
14632 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
14633 return ir_add_error(ira, source_instr, buf_sprintf(fmt, buf_ptr(&scalar_type->name)));
14634 }
14635
14636 if (is_float) {
14637 float_negate(scalar_out_val, operand_val);
14638 } else if (is_wrap_op) {
14639 bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,
14640 scalar_type->data.integral.bit_count);
14641 } else {
14642 bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);
14643 }
14644
14645 scalar_out_val->type = scalar_type;
14646 scalar_out_val->special = ConstValSpecialStatic;
14647
14648 if (is_wrap_op || is_float || scalar_type->id == ZigTypeIdComptimeInt) {
14649 return nullptr;
14650 }
14651
14652 if (!bigint_fits_in_bits(&scalar_out_val->data.x_bigint, scalar_type->data.integral.bit_count, true)) {
14653 return ir_add_error(ira, source_instr, buf_sprintf("negation caused overflow"));
14654 }
14655 return nullptr;
14656}
14657
1462314658static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *instruction) {
1462414659 IrInstruction *value = instruction->value->child;
1462514660 ZigType *expr_type = value->value.type;
......@@ -14628,47 +14663,50 @@ static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *ins
1462814663
1462914664 bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap);
1463014665
14631 bool is_float = (expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat);
14666 ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
1463214667
14633 if ((expr_type->id == ZigTypeIdInt && expr_type->data.integral.is_signed) ||
14634 expr_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op))
14635 {
14636 if (instr_is_comptime(value)) {
14637 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
14638 if (!target_const_val)
14639 return ira->codegen->invalid_instruction;
14668 if (instr_is_comptime(value)) {
14669 ConstExprValue *operand_val = ir_resolve_const(ira, value, UndefBad);
14670 if (!operand_val)
14671 return ira->codegen->invalid_instruction;
1464014672
14641 IrInstruction *result = ir_const(ira, &instruction->base, expr_type);
14642 ConstExprValue *out_val = &result->value;
14643 if (is_float) {
14644 float_negate(out_val, target_const_val);
14645 } else if (is_wrap_op) {
14646 bigint_negate_wrap(&out_val->data.x_bigint, &target_const_val->data.x_bigint,
14647 expr_type->data.integral.bit_count);
14648 } else {
14649 bigint_negate(&out_val->data.x_bigint, &target_const_val->data.x_bigint);
14650 }
14651 if (is_wrap_op || is_float || expr_type->id == ZigTypeIdComptimeInt) {
14652 return result;
14673 IrInstruction *result_instruction = ir_const(ira, &instruction->base, expr_type);
14674 ConstExprValue *out_val = &result_instruction->value;
14675 if (expr_type->id == ZigTypeIdVector) {
14676 expand_undef_array(ira->codegen, operand_val);
14677 out_val->special = ConstValSpecialUndef;
14678 expand_undef_array(ira->codegen, out_val);
14679 size_t len = expr_type->data.vector.len;
14680 for (size_t i = 0; i < len; i += 1) {
14681 ConstExprValue *scalar_operand_val = &operand_val->data.x_array.data.s_none.elements[i];
14682 ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
14683 assert(scalar_operand_val->type == scalar_type);
14684 assert(scalar_out_val->type == scalar_type);
14685 ErrorMsg *msg = ir_eval_negation_scalar(ira, &instruction->base, scalar_type,
14686 scalar_operand_val, scalar_out_val, is_wrap_op);
14687 if (msg != nullptr) {
14688 add_error_note(ira->codegen, msg, instruction->base.source_node,
14689 buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i));
14690 return ira->codegen->invalid_instruction;
14691 }
1465314692 }
14654
14655 if (!bigint_fits_in_bits(&out_val->data.x_bigint, expr_type->data.integral.bit_count, true)) {
14656 ir_add_error(ira, &instruction->base, buf_sprintf("negation caused overflow"));
14693 out_val->type = expr_type;
14694 out_val->special = ConstValSpecialStatic;
14695 } else {
14696 if (ir_eval_negation_scalar(ira, &instruction->base, scalar_type, operand_val, out_val,
14697 is_wrap_op) != nullptr)
14698 {
1465714699 return ira->codegen->invalid_instruction;
1465814700 }
14659 return result;
1466014701 }
14661
14662 IrInstruction *result = ir_build_un_op(&ira->new_irb,
14663 instruction->base.scope, instruction->base.source_node,
14664 instruction->op_id, value);
14665 result->value.type = expr_type;
14666 return result;
14702 return result_instruction;
1466714703 }
1466814704
14669 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
14670 ir_add_error(ira, &instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
14671 return ira->codegen->invalid_instruction;
14705 IrInstruction *result = ir_build_un_op(&ira->new_irb,
14706 instruction->base.scope, instruction->base.source_node,
14707 instruction->op_id, value);
14708 result->value.type = expr_type;
14709 return result;
1467214710}
1467314711
1467414712static IrInstruction *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *instruction) {
test/compile_errors.zig+12
......@@ -1,6 +1,18 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.addTest(
5 "comptime vector overflow shows the index",
6 \\comptime {
7 \\ var a: @Vector(4, u8) = []u8{ 1, 2, 255, 4 };
8 \\ var b: @Vector(4, u8) = []u8{ 5, 6, 1, 8 };
9 \\ var x = a + b;
10 \\}
11 ,
12 ".tmp_source.zig:4:15: error: operation caused overflow",
13 ".tmp_source.zig:4:15: note: when computing vector element at index 2",
14 );
15
416 cases.addTest(
517 "packed struct with fields of not allowed types",
618 \\const A = packed struct {
test/runtime_safety.zig+41
......@@ -118,6 +118,47 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
118118 \\}
119119 );
120120
121 cases.addRuntimeSafety("vector integer subtraction overflow",
122 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
123 \\ @import("std").os.exit(126);
124 \\}
125 \\pub fn main() void {
126 \\ var a: @Vector(4, u32) = []u32{ 1, 2, 8, 4 };
127 \\ var b: @Vector(4, u32) = []u32{ 5, 6, 7, 8 };
128 \\ const x = sub(b, a);
129 \\}
130 \\fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
131 \\ return a - b;
132 \\}
133 );
134
135 cases.addRuntimeSafety("vector integer multiplication overflow",
136 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
137 \\ @import("std").os.exit(126);
138 \\}
139 \\pub fn main() void {
140 \\ var a: @Vector(4, u8) = []u8{ 1, 2, 200, 4 };
141 \\ var b: @Vector(4, u8) = []u8{ 5, 6, 2, 8 };
142 \\ const x = mul(b, a);
143 \\}
144 \\fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
145 \\ return a * b;
146 \\}
147 );
148
149 cases.addRuntimeSafety("vector integer negation overflow",
150 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
151 \\ @import("std").os.exit(126);
152 \\}
153 \\pub fn main() void {
154 \\ var a: @Vector(4, i16) = []i16{ 1, -32768, 200, 4 };
155 \\ const x = neg(a);
156 \\}
157 \\fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
158 \\ return -a;
159 \\}
160 );
161
121162 cases.addRuntimeSafety("integer subtraction overflow",
122163 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
123164 \\ @import("std").os.exit(126);
test/stage1/behavior/vector.zig+27-9
......@@ -5,11 +5,28 @@ const expect = std.testing.expect;
55test "vector wrap operators" {
66 const S = struct {
77 fn doTheTest() void {
8 const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
9 const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
10 expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 }));
11 expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 }));
12 expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 }));
8 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
9 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
10 expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ -2147483648, 2147483645, 33, 44 }));
11 expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 2147483646, 2147483647, 27, 36 }));
12 expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 2147483647, 2, 90, 160 }));
13 var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };
14 expect(mem.eql(i32, ([4]i32)(-%z), [4]i32{ -1, -2, -3, -2147483648 }));
15 }
16 };
17 S.doTheTest();
18 comptime S.doTheTest();
19}
20
21test "vector int operators" {
22 const S = struct {
23 fn doTheTest() void {
24 var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
25 var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
26 expect(mem.eql(i32, ([4]i32)(v + x), [4]i32{ 11, 22, 33, 44 }));
27 expect(mem.eql(i32, ([4]i32)(v - x), [4]i32{ 9, 18, 27, 36 }));
28 expect(mem.eql(i32, ([4]i32)(v * x), [4]i32{ 10, 40, 90, 160 }));
29 expect(mem.eql(i32, ([4]i32)(-v), [4]i32{ -10, -20, -30, -40 }));
1330 }
1431 };
1532 S.doTheTest();
......@@ -19,11 +36,12 @@ test "vector wrap operators" {
1936test "vector float operators" {
2037 const S = struct {
2138 fn doTheTest() void {
22 const v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
23 const x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
39 var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
40 var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
2441 expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 }));
2542 expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 }));
2643 expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 }));
44 expect(mem.eql(f32, ([4]f32)(-x), [4]f32{ -1, -2, -3, -4 }));
2745 }
2846 };
2947 S.doTheTest();
......@@ -33,8 +51,8 @@ test "vector float operators" {
3351test "vector bit operators" {
3452 const S = struct {
3553 fn doTheTest() void {
36 const v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
37 const x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
54 var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
55 var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
3856 expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
3957 expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
4058 expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));