Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,753 changes: 387 additions & 1,366 deletions src/Sema.zig

Large diffs are not rendered by default.

1,609 changes: 1,609 additions & 0 deletions src/Sema/arith.zig

Large diffs are not rendered by default.

1,202 changes: 231 additions & 971 deletions src/Value.zig

Large diffs are not rendered by default.

48 changes: 40 additions & 8 deletions src/Zcu.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1716,9 +1716,25 @@ pub const SrcLoc = struct {
const node = node_off.toAbsolute(src_loc.base_node);

switch (tree.nodeTag(node)) {
.assign => {
return tree.nodeToSpan(tree.nodeData(node).node_and_node[0]);
},
.assign,
.assign_mul,
.assign_div,
.assign_mod,
.assign_add,
.assign_sub,
.assign_shl,
.assign_shl_sat,
.assign_shr,
.assign_bit_and,
.assign_bit_xor,
.assign_bit_or,
.assign_mul_wrap,
.assign_add_wrap,
.assign_sub_wrap,
.assign_mul_sat,
.assign_add_sat,
.assign_sub_sat,
=> return tree.nodeToSpan(tree.nodeData(node).node_and_node[0]),
else => return tree.nodeToSpan(node),
}
},
Expand All @@ -1727,9 +1743,25 @@ pub const SrcLoc = struct {
const node = node_off.toAbsolute(src_loc.base_node);

switch (tree.nodeTag(node)) {
.assign => {
return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]);
},
.assign,
.assign_mul,
.assign_div,
.assign_mod,
.assign_add,
.assign_sub,
.assign_shl,
.assign_shl_sat,
.assign_shr,
.assign_bit_and,
.assign_bit_xor,
.assign_bit_or,
.assign_mul_wrap,
.assign_add_wrap,
.assign_sub_wrap,
.assign_mul_sat,
.assign_add_sat,
.assign_sub_sat,
=> return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]),
else => return tree.nodeToSpan(node),
}
},
Expand Down Expand Up @@ -2209,9 +2241,9 @@ pub const LazySrcLoc = struct {
node_offset_field_default: Ast.Node.Offset,
/// The source location points to the type of an array or struct initializer.
node_offset_init_ty: Ast.Node.Offset,
/// The source location points to the LHS of an assignment.
/// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`).
node_offset_store_ptr: Ast.Node.Offset,
/// The source location points to the RHS of an assignment.
/// The source location points to the RHS of an assignment (or assign-op, e.g. `+=`).
node_offset_store_operand: Ast.Node.Offset,
/// The source location points to the operand of a `return` statement, or
/// the `return` itself if there is no explicit operand.
Expand Down
4 changes: 0 additions & 4 deletions test/behavior/floatop.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1696,10 +1696,6 @@ test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
}
}

test "comptime_float zero divided by zero produces zero" {
try expect((0.0 / 0.0) == 0.0);
}

test "comptime float compared with runtime int" {
const f = 10.0;
var i: usize = 0;
Expand Down
137 changes: 131 additions & 6 deletions test/behavior/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1265,12 +1265,6 @@ test "allow signed integer division/remainder when values are comptime-known and

try expect(5 % 3 == 2);
try expect(-6 % 3 == 0);

var undef: i32 = undefined;
_ = &undef;
if (0 % undef != 0) {
@compileError("0 as numerator should return comptime zero independent of denominator");
}
}

test "quad hex float literal parsing accurate" {
Expand Down Expand Up @@ -1861,3 +1855,134 @@ test "runtime int comparison to inf is comptime-known" {
comptime S.doTheTest(f64, 123);
comptime S.doTheTest(f128, 123);
}

test "float divide by zero" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;

const S = struct {
fn doTheTest(comptime F: type, zero: F, one: F) !void {
try expect(math.isPositiveInf(@divTrunc(one, zero)));
try expect(math.isPositiveInf(@divFloor(one, zero)));

try expect(math.isNan(@rem(one, zero)));
try expect(math.isNan(@mod(one, zero)));
}
};

try S.doTheTest(f16, 0, 1);
comptime S.doTheTest(f16, 0, 1) catch unreachable;

try S.doTheTest(f32, 0, 1);
comptime S.doTheTest(f32, 0, 1) catch unreachable;

try S.doTheTest(f64, 0, 1);
comptime S.doTheTest(f64, 0, 1) catch unreachable;

try S.doTheTest(f80, 0, 1);
comptime S.doTheTest(f80, 0, 1) catch unreachable;

try S.doTheTest(f128, 0, 1);
comptime S.doTheTest(f128, 0, 1) catch unreachable;
}

test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

var lhs: @Vector(2, i8) = .{ -128, 5 };
const rhs: @Vector(2, i8) = .{ 1, -1 };

const expected: @Vector(2, i8) = .{ -128, -5 };

lhs = lhs; // suppress error

const trunc = @divTrunc(lhs, rhs);
try expect(trunc[0] == expected[0]);
try expect(trunc[1] == expected[1]);

const floor = @divFloor(lhs, rhs);
try expect(floor[0] == expected[0]);
try expect(floor[1] == expected[1]);

const exact = @divExact(lhs, rhs);
try expect(exact[0] == expected[0]);
try expect(exact[1] == expected[1]);
}

test "float vector division of comptime zero by runtime nan is nan" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;

const ct_zero: @Vector(1, f32) = .{0};
var rt_nan: @Vector(1, f32) = .{math.nan(f32)};

rt_nan = rt_nan; // suppress error

try expect(math.isNan((@divTrunc(ct_zero, rt_nan))[0]));
try expect(math.isNan((@divFloor(ct_zero, rt_nan))[0]));
try expect(math.isNan((ct_zero / rt_nan)[0]));
}

test "float vector multiplication of comptime zero by runtime nan is nan" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

const ct_zero: @Vector(1, f32) = .{0};
var rt_nan: @Vector(1, f32) = .{math.nan(f32)};

rt_nan = rt_nan; // suppress error

try expect(math.isNan((ct_zero * rt_nan)[0]));
try expect(math.isNan((rt_nan * ct_zero)[0]));
}

test "comptime float vector division of zero by nan is nan" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

const ct_zero: @Vector(1, f32) = .{0};
const ct_nan: @Vector(1, f32) = .{math.nan(f32)};

comptime assert(math.isNan((@divTrunc(ct_zero, ct_nan))[0]));
comptime assert(math.isNan((@divFloor(ct_zero, ct_nan))[0]));
comptime assert(math.isNan((ct_zero / ct_nan)[0]));
}

test "comptime float vector multiplication of zero by nan is nan" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

const ct_zero: @Vector(1, f32) = .{0};
const ct_nan: @Vector(1, f32) = .{math.nan(f32)};

comptime assert(math.isNan((ct_zero * ct_nan)[0]));
comptime assert(math.isNan((ct_nan * ct_zero)[0]));
}
2 changes: 2 additions & 0 deletions test/behavior/vector.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,8 @@ test "zero multiplicand" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO

const zeros = @Vector(2, u32){ 0.0, 0.0 };
var ones = @Vector(2, u32){ 1.0, 1.0 };
Expand Down
101 changes: 10 additions & 91 deletions test/behavior/x86_64/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21685,20 +21685,7 @@ test mulUnsafe {
}

inline fn multiply(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs * rhs) {
if (@inComptime() and @typeInfo(Type) == .vector) {
// workaround https://github.com/ziglang/zig/issues/22743
// TODO: return @select(Scalar(Type), boolAnd(lhs == lhs, rhs == rhs), lhs * rhs, lhs + rhs);
// workaround https://github.com/ziglang/zig/issues/22744
var res: Type = undefined;
for (0..@typeInfo(Type).vector.len) |i| res[i] = lhs[i] * rhs[i];
return res;
}
// workaround https://github.com/ziglang/zig/issues/22745
// TODO: return lhs * rhs;
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = .{ &rt_lhs, &rt_rhs };
return rt_lhs * rt_rhs;
return lhs * rhs;
}
test multiply {
const test_multiply = binary(multiply, .{});
Expand All @@ -21715,24 +21702,8 @@ test divide {
try test_divide.testFloatVectors();
}

inline fn divTrunc(comptime Type: type, lhs: Type, rhs: Type) Type {
switch (@typeInfo(Scalar(Type))) {
else => @compileError(@typeName(Type)),
.int => return @divTrunc(lhs, rhs),
.float => {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
return @trunc(lhs / rhs);
}
// workaround https://github.com/ziglang/zig/issues/22748
// workaround https://github.com/ziglang/zig/issues/22749
// TODO: return @divTrunc(lhs, rhs);
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = .{ &rt_lhs, &rt_rhs };
return @divTrunc(rt_lhs, rt_rhs);
},
}
inline fn divTrunc(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@divTrunc(lhs, rhs)) {
return @divTrunc(lhs, rhs);
}
test divTrunc {
const test_div_trunc = binary(divTrunc, .{ .compare = .approx_int });
Expand All @@ -21742,56 +21713,17 @@ test divTrunc {
try test_div_trunc.testFloatVectors();
}

inline fn divFloor(comptime Type: type, lhs: Type, rhs: Type) Type {
switch (@typeInfo(Scalar(Type))) {
else => @compileError(@typeName(Type)),
.int => return @divFloor(lhs, rhs),
.float => {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
return @floor(lhs / rhs);
}
// workaround https://github.com/ziglang/zig/issues/22748
// workaround https://github.com/ziglang/zig/issues/22749
// TODO: return @divFloor(lhs, rhs);
var rt_lhs = lhs;
var rt_rhs = rhs;
_ = .{ &rt_lhs, &rt_rhs };
return @divFloor(rt_lhs, rt_rhs);
},
}
inline fn divFloor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@divFloor(lhs, rhs)) {
return @divFloor(lhs, rhs);
}
test divFloor {
const test_div_floor = binary(divFloor, .{ .compare = .approx_int });
try test_div_floor.testFloats();
try test_div_floor.testFloatVectors();
}

// workaround https://github.com/ziglang/zig/issues/22748
// TODO: @TypeOf(@rem(lhs, rhs))
inline fn rem(comptime Type: type, lhs: Type, rhs: Type) Type {
switch (@typeInfo(Scalar(Type))) {
else => @compileError(@typeName(Type)),
.int => return @rem(lhs, rhs),
.float => {
if (@inComptime()) {
// workaround https://github.com/ziglang/zig/issues/22748
switch (@typeInfo(Type)) {
else => return if (rhs != 0) @rem(lhs, rhs) else nan(Type),
.vector => |info| {
var res: Type = undefined;
inline for (0..info.len) |i| res[i] = if (rhs[i] != 0) @rem(lhs[i], rhs[i]) else nan(Scalar(Type));
return res;
},
}
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: return @rem(lhs, rhs);
var rt_rhs = rhs;
_ = &rt_rhs;
return @rem(lhs, rt_rhs);
},
}
inline fn rem(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@rem(lhs, rhs)) {
return @rem(lhs, rhs);
}
test rem {
const test_rem = binary(rem, .{});
Expand All @@ -21801,25 +21733,16 @@ test rem {
try test_rem.testFloatVectors();
}

inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type {
inline fn mod(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(@mod(lhs, rhs)) {
// workaround llvm backend bugs
if (@inComptime()) {
const scalarMod = struct {
fn scalarMod(scalar_lhs: Scalar(Type), scalar_rhs: Scalar(Type)) Scalar(Type) {
// workaround https://github.com/ziglang/zig/issues/22748
if (scalar_rhs == 0) return nan(Scalar(Type));
const scalar_rem = @rem(scalar_lhs, scalar_rhs);
return if (scalar_rem == 0 or math.signbit(scalar_rem) == math.signbit(scalar_rhs)) scalar_rem else scalar_rem + scalar_rhs;
}
}.scalarMod;
// workaround https://github.com/ziglang/zig/issues/22748
switch (@typeInfo(Type)) {
// workaround llvm backend bugs
// TODO: else => return if (rhs != 0) @mod(lhs, rhs) else nan(Type),
// TODO: .vector => |info| {
// TODO: var res: Type = undefined;
// TODO: inline for (0..info.len) |i| res[i] = if (rhs[i] != 0) @mod(lhs[i], rhs[i]) else nan(Scalar(Type));
// TODO: return res;
// TODO: },
else => return scalarMod(lhs, rhs),
.vector => |info| {
var res: Type = undefined;
Expand All @@ -21828,11 +21751,7 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type {
},
}
}
// workaround https://github.com/ziglang/zig/issues/22748
// TODO: return @mod(lhs, rhs);
var rt_rhs = rhs;
_ = &rt_rhs;
return @mod(lhs, rt_rhs);
return @mod(lhs, rhs);
}
test mod {
const test_mod = binary(mod, .{});
Expand Down
4 changes: 1 addition & 3 deletions test/cases/compile_errors/add_assign_on_undefined_value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ comptime {
}

// error
// backend=stage2
// target=native
//
// :3:10: error: use of undefined value here causes undefined behavior
// :3:5: error: use of undefined value here causes undefined behavior
Loading