authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 23:15:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 23:15:01-07:00
logc64279b15b527749420e0e79fcc6dbfbfeb02812
tree8f7fe813a6b2b7048468731f5f93619b3704e882
parent1adb15098c711973d1c75061f122b907aaf09a7c

Sema: fix shl_sat with comptime rhs


7 files changed, 89 insertions(+), 65 deletions(-)

src/Sema.zig+49-6
......@@ -6398,7 +6398,6 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
63986398 defer tracy.end();
63996399
64006400 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6401 const src = inst_data.src();
64026401 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
64036402 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
64046403 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
......@@ -6406,16 +6405,29 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
64066405 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
64076406 const operand = sema.resolveInst(extra.rhs);
64086407
6408 return sema.intCast(block, dest_ty, dest_ty_src, operand, operand_src, true);
6409}
6410
6411fn intCast(
6412 sema: *Sema,
6413 block: *Block,
6414 dest_ty: Type,
6415 dest_ty_src: LazySrcLoc,
6416 operand: Air.Inst.Ref,
6417 operand_src: LazySrcLoc,
6418 runtime_safety: bool,
6419) CompileError!Air.Inst.Ref {
64096420 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty);
64106421 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
64116422
64126423 if (try sema.isComptimeKnown(block, operand_src, operand)) {
64136424 return sema.coerce(block, dest_ty, operand, operand_src);
64146425 } else if (dest_is_comptime_int) {
6415 return sema.fail(block, src, "unable to cast runtime value to 'comptime_int'", .{});
6426 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
64166427 }
64176428
64186429 // TODO insert safety check to make sure the value fits in the dest type
6430 _ = runtime_safety;
64196431
64206432 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
64216433 return sema.addConstant(dest_ty, opv);
......@@ -7986,6 +7998,7 @@ fn zirShl(
79867998 const rhs = sema.resolveInst(extra.rhs);
79877999
79888000 // TODO coerce rhs if air_tag is not shl_sat
8001 const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, sema.typeOf(rhs));
79898002
79908003 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
79918004 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
......@@ -7999,13 +8012,14 @@ fn zirShl(
79998012 }
80008013 }
80018014
8002 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
8003 const lhs_ty = sema.typeOf(lhs);
8015 const lhs_ty = sema.typeOf(lhs);
8016 const rhs_ty = sema.typeOf(rhs);
8017 const target = sema.mod.getTarget();
80048018
8019 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
80058020 if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
80068021 const rhs_val = maybe_rhs_val orelse break :rs rhs_src;
80078022
8008 const target = sema.mod.getTarget();
80098023 const val = switch (air_tag) {
80108024 .shl_exact => val: {
80118025 const shifted = try lhs_val.shl(rhs_val, sema.arena);
......@@ -8038,8 +8052,24 @@ fn zirShl(
80388052
80398053 // TODO: insert runtime safety check for shl_exact
80408054
8055 const new_rhs = if (air_tag == .shl_sat) rhs: {
8056 // Limit the RHS type for saturating shl to be an integer as small as the LHS.
8057 if (rhs_is_comptime_int or
8058 rhs_ty.intInfo(target).bits > lhs_ty.intInfo(target).bits)
8059 {
8060 const max_int = try sema.addConstant(
8061 lhs_ty,
8062 try lhs_ty.maxInt(sema.arena, target),
8063 );
8064 const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src);
8065 break :rhs try sema.intCast(block, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
8066 } else {
8067 break :rhs rhs;
8068 }
8069 } else rhs;
8070
80418071 try sema.requireRuntimeBlock(block, runtime_src);
8042 return block.addBinOp(air_tag, lhs, rhs);
8072 return block.addBinOp(air_tag, lhs, new_rhs);
80438073}
80448074
80458075fn zirShr(
......@@ -14537,6 +14567,19 @@ fn zirMinMax(
1453714567 const rhs = sema.resolveInst(extra.rhs);
1453814568 try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs));
1453914569 try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs));
14570 return sema.analyzeMinMax(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
14571}
14572
14573fn analyzeMinMax(
14574 sema: *Sema,
14575 block: *Block,
14576 src: LazySrcLoc,
14577 lhs: Air.Inst.Ref,
14578 rhs: Air.Inst.Ref,
14579 air_tag: Air.Inst.Tag,
14580 lhs_src: LazySrcLoc,
14581 rhs_src: LazySrcLoc,
14582) CompileError!Air.Inst.Ref {
1454014583 const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
1454114584
1454214585 // TODO @maximum(max_int, undefined) should return max_int
test/behavior/floatop.zig+9-2
......@@ -609,7 +609,11 @@ test "negation f64" {
609609}
610610
611611test "negation f80" {
612 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
612 if (builtin.zig_backend != .stage1) {
613 // This test case exercises @intToFloat f80 in the compiler implementation.
614 // https://github.com/ziglang/zig/issues/11030
615 return error.SkipZigTest;
616 }
613617
614618 if (builtin.os.tag == .freebsd) {
615619 // TODO file issue to track this failure
......@@ -673,7 +677,10 @@ fn fnWithFloatMode() f32 {
673677}
674678
675679test "float literal at compile time not lossy" {
676 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
680 if (builtin.zig_backend != .stage1) {
681 // https://github.com/ziglang/zig/issues/11169
682 return error.SkipZigTest;
683 }
677684
678685 try expect(16777216.0 + 1.0 == 16777217.0);
679686 try expect(9007199254740992.0 + 1.0 == 9007199254740993.0);
test/behavior/fn.zig+16-7
......@@ -307,13 +307,20 @@ fn acceptsString(foo: []u8) void {
307307}
308308
309309test "function pointers" {
310 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
310 if (builtin.zig_backend == .stage1) {
311 // stage1 has wrong semantics for function pointers
312 return error.SkipZigTest;
313 }
314
315 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311318
312 const fns = [_]@TypeOf(fn1){
313 fn1,
314 fn2,
315 fn3,
316 fn4,
319 const fns = [_]*const @TypeOf(fn1){
320 &fn1,
321 &fn2,
322 &fn3,
323 &fn4,
317324 };
318325 for (fns) |f, i| {
319326 try expect(f() == @intCast(u32, i) + 5);
......@@ -380,7 +387,9 @@ test "ability to give comptime types and non comptime types to same parameter" {
380387}
381388
382389test "function with inferred error set but returning no error" {
383 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
391 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
392 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
384393
385394 const S = struct {
386395 fn foo() !void {}
test/behavior/saturating_arithmetic.zig-2
......@@ -163,8 +163,6 @@ test "saturating shift-left" {
163163}
164164
165165test "saturating shl uses the LHS type" {
166 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
167
168166 const lhs_const: u8 = 1;
169167 var lhs_var: u8 = 1;
170168
test/behavior/translate_c_macros.zig+3-3
......@@ -45,16 +45,16 @@ test "cast negative integer to pointer" {
4545}
4646
4747test "casting to union with a macro" {
48 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO Sema.zirUnionInitPtr
48 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
4949
5050 const l: c_long = 42;
5151 const d: f64 = 2.0;
5252
5353 var casted = h.UNION_CAST(l);
54 try expectEqual(l, casted.l);
54 try expect(l == casted.l);
5555
5656 casted = h.UNION_CAST(d);
57 try expectEqual(d, casted.d);
57 try expect(d == casted.d);
5858}
5959
6060test "nested comma operator" {
test/behavior/type.zig+4-37
......@@ -230,7 +230,10 @@ test "Type.Vector" {
230230}
231231
232232test "Type.AnyFrame" {
233 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
233 if (builtin.zig_backend != .stage1) {
234 // https://github.com/ziglang/zig/issues/6025
235 return error.SkipZigTest;
236 }
234237
235238 try testTypes(&[_]type{
236239 anyframe,
......@@ -514,39 +517,3 @@ test "Type.Union from regular enum" {
514517 _ = T;
515518 _ = @typeInfo(T).Union;
516519}
517
518test "Type.Fn" {
519 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
520
521 // wasm doesn't support align attributes on functions
522 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
523
524 const foo = struct {
525 fn func(a: usize, b: bool) align(4) callconv(.C) usize {
526 _ = a;
527 _ = b;
528 return 0;
529 }
530 }.func;
531 const Foo = @Type(@typeInfo(@TypeOf(foo)));
532 const foo_2: Foo = foo;
533 _ = foo_2;
534}
535
536test "Type.BoundFn" {
537 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
538
539 // wasm doesn't support align attributes on functions
540 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
541
542 const TestStruct = packed struct {
543 pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {
544 _ = self;
545 }
546 };
547 const test_instance: TestStruct = undefined;
548 try testing.expect(std.meta.eql(
549 @typeName(@TypeOf(test_instance.foo)),
550 @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
551 ));
552}
test/behavior/type_info.zig+8-8
......@@ -379,12 +379,6 @@ fn testFunction() !void {
379379 try expect(fn_info.Fn.return_type.? == usize);
380380 const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
381381 try expect(fn_aligned_info.Fn.alignment == 4);
382
383 if (builtin.zig_backend != .stage1) return; // no bound fn in stage2
384 const test_instance: TestPackedStruct = undefined;
385 const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
386 try expect(bound_fn_info == .BoundFn);
387 try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestPackedStruct);
388382}
389383
390384extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
......@@ -413,7 +407,10 @@ fn testVector() !void {
413407}
414408
415409test "type info: anyframe and anyframe->T" {
416 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
410 if (builtin.zig_backend != .stage1) {
411 // https://github.com/ziglang/zig/issues/6025
412 return error.SkipZigTest;
413 }
417414
418415 try testAnyFrame();
419416 comptime try testAnyFrame();
......@@ -469,7 +466,10 @@ fn add(a: i32, b: i32) i32 {
469466}
470467
471468test "type info for async frames" {
472 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend != .stage1) {
470 // https://github.com/ziglang/zig/issues/6025
471 return error.SkipZigTest;
472 }
473473
474474 switch (@typeInfo(@Frame(add))) {
475475 .Frame => |frame| {