stage2: improve handling of 0 bit types

* Sema: zirAtomicLoad handles 0-bit types correctly
 * LLVM backend: when lowering function types, elide parameters
   with 0-bit types.
 * Type: abiSize handles u0/i0 correctly
This commit is contained in:
Andrew Kelley 2021-09-20 16:48:42 -07:00
parent 4b2d7a9c67
commit abc30f7948
6 changed files with 39 additions and 35 deletions

View File

@ -7803,6 +7803,10 @@ fn zirAtomicLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
else => {},
}
if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| {
return sema.addConstant(elem_ty, val);
}
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try ptr_val.pointerDeref(sema.arena)) |elem_val| {
return sema.addConstant(elem_ty, elem_val);

View File

@ -541,17 +541,21 @@ pub const DeclGen = struct {
defer self.gpa.free(fn_param_types);
zig_fn_type.fnParamTypes(fn_param_types);
const llvm_param = try self.gpa.alloc(*const llvm.Type, fn_param_len);
defer self.gpa.free(llvm_param);
const llvm_param_buffer = try self.gpa.alloc(*const llvm.Type, fn_param_len);
defer self.gpa.free(llvm_param_buffer);
for (fn_param_types) |fn_param, i| {
llvm_param[i] = try self.llvmType(fn_param);
var llvm_params_len: c_uint = 0;
for (fn_param_types) |fn_param| {
if (fn_param.hasCodeGenBits()) {
llvm_param_buffer[llvm_params_len] = try self.llvmType(fn_param);
llvm_params_len += 1;
}
}
const fn_type = llvm.functionType(
try self.llvmType(return_type),
llvm_param.ptr,
@intCast(c_uint, fn_param_len),
llvm_param_buffer.ptr,
llvm_params_len,
.False,
);
const llvm_fn = self.llvmModule().addFunction(decl.name, fn_type);

View File

@ -1822,6 +1822,7 @@ pub const Type = extern union {
.int_signed, .int_unsigned => {
const bits: u16 = self.cast(Payload.Bits).?.data;
if (bits == 0) return 0;
return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
},

View File

@ -23,7 +23,6 @@ test {
_ = @import("behavior/asm.zig");
_ = @import("behavior/async_fn.zig");
}
_ = @import("behavior/atomics_stage1.zig");
_ = @import("behavior/await_struct.zig");
_ = @import("behavior/bit_shifting.zig");
_ = @import("behavior/bitcast.zig");

View File

@ -195,3 +195,27 @@ fn testAtomicRmwInt() !void {
_ = @atomicRmw(u8, &x, .Min, 1, .SeqCst);
try expect(x == 1);
}
test "atomics with different types" {
try testAtomicsWithType(bool, true, false);
try testAtomicsWithType(u1, 0, 1);
try testAtomicsWithType(i4, 0, 1);
try testAtomicsWithType(u5, 0, 1);
try testAtomicsWithType(i15, 0, 1);
try testAtomicsWithType(u24, 0, 1);
try testAtomicsWithType(u0, 0, 0);
try testAtomicsWithType(i0, 0, 0);
}
fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
var x: T = b;
@atomicStore(T, &x, a, .SeqCst);
try expect(x == a);
try expect(@atomicLoad(T, &x, .SeqCst) == a);
try expect(@atomicRmw(T, &x, .Xchg, b, .SeqCst) == a);
try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst) == null);
if (@sizeOf(T) != 0)
try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a);
}

View File

@ -1,28 +0,0 @@
const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
test "atomics with different types" {
try testAtomicsWithType(bool, true, false);
try testAtomicsWithType(u1, 0, 1);
try testAtomicsWithType(i4, 0, 1);
try testAtomicsWithType(u5, 0, 1);
try testAtomicsWithType(i15, 0, 1);
try testAtomicsWithType(u24, 0, 1);
try testAtomicsWithType(u0, 0, 0);
try testAtomicsWithType(i0, 0, 0);
}
fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
var x: T = b;
@atomicStore(T, &x, a, .SeqCst);
try expect(x == a);
try expect(@atomicLoad(T, &x, .SeqCst) == a);
try expect(@atomicRmw(T, &x, .Xchg, b, .SeqCst) == a);
try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst) == null);
if (@sizeOf(T) != 0)
try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a);
}