stage2: implement @atomicStore

This commit is contained in:
Andrew Kelley 2021-09-19 15:07:51 -07:00
parent 2a0c44fff3
commit 9fa723ee50
5 changed files with 84 additions and 23 deletions

View File

@ -2118,7 +2118,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.select,
.atomic_load,
.atomic_rmw,
.atomic_store,
.mul_add,
.builtin_call,
.field_ptr_type,
@ -2164,6 +2163,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.@"export",
.set_eval_branch_quota,
.ensure_err_payload_void,
.atomic_store,
.store,
.store_node,
.store_to_block_ptr,

View File

@ -314,7 +314,6 @@ pub fn analyzeBody(
.select => try sema.zirSelect(block, inst),
.atomic_load => try sema.zirAtomicLoad(block, inst),
.atomic_rmw => try sema.zirAtomicRmw(block, inst),
.atomic_store => try sema.zirAtomicStore(block, inst),
.mul_add => try sema.zirMulAdd(block, inst),
.builtin_call => try sema.zirBuiltinCall(block, inst),
.field_ptr_type => try sema.zirFieldPtrType(block, inst),
@ -413,6 +412,11 @@ pub fn analyzeBody(
i += 1;
continue;
},
.atomic_store => {
try sema.zirAtomicStore(block, inst);
i += 1;
continue;
},
.store => {
try sema.zirStore(block, inst);
i += 1;
@ -7669,6 +7673,8 @@ fn zirCmpxchg(
if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| {
if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| {
if (expected_val.isUndef() or new_val.isUndef()) {
// TODO: this should probably cause the memory stored at the pointer
// to become undef as well
return sema.addConstUndef(result_ty);
}
const stored_val = (try ptr_val.pointerDeref(sema.arena)) orelse break :rs ptr_src;
@ -7830,10 +7836,38 @@ fn zirAtomicRmw(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
});
}
fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
const src = inst_data.src();
return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicStore", .{});
// zig fmt: off
const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
// zig fmt: on
const ptr = sema.resolveInst(extra.ptr);
const operand_ty = sema.typeOf(ptr).elemType();
try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);
const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);
const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
const air_tag: Air.Inst.Tag = switch (order) {
.Acquire, .AcqRel => {
return sema.mod.fail(
&block.base,
order_src,
"@atomicStore atomic ordering must not be Acquire or AcqRel",
.{},
);
},
.Unordered => .atomic_store_unordered,
.Monotonic => .atomic_store_monotonic,
.Release => .atomic_store_release,
.SeqCst => .atomic_store_seq_cst,
};
return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
}
fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@ -9310,25 +9344,39 @@ fn coerceVarArgParam(
return inst;
}
// TODO migrate callsites to use storePtr2 instead.
fn storePtr(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
ptr: Air.Inst.Ref,
uncasted_value: Air.Inst.Ref,
uncasted_operand: Air.Inst.Ref,
) !void {
return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, .store);
}
fn storePtr2(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
ptr: Air.Inst.Ref,
ptr_src: LazySrcLoc,
uncasted_operand: Air.Inst.Ref,
operand_src: LazySrcLoc,
air_tag: Air.Inst.Tag,
) !void {
const ptr_ty = sema.typeOf(ptr);
if (ptr_ty.isConstPtr())
return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
const elem_ty = ptr_ty.elemType();
const value = try sema.coerce(block, elem_ty, uncasted_value, src);
const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
return;
if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
if (ptr_val.castTag(.decl_ref_mut)) |decl_ref_mut| {
const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse
const const_val = (try sema.resolveMaybeUndefVal(block, operand_src, operand)) orelse
return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
if (decl_ref_mut.data.runtime_index < block.runtime_index) {
@ -9365,11 +9413,13 @@ fn storePtr(
old_arena.deinit();
return;
}
}
break :rs operand_src;
} else ptr_src;
// TODO handle if the element type requires comptime
try sema.requireRuntimeBlock(block, src);
_ = try block.addBinOp(.store, ptr, value);
try sema.requireRuntimeBlock(block, runtime_src);
_ = try block.addBinOp(air_tag, ptr, operand);
}
fn bitcast(

View File

@ -3058,7 +3058,6 @@ const Writer = struct {
.shuffle,
.select,
.atomic_rmw,
.atomic_store,
.mul_add,
.builtin_call,
.field_parent_ptr,
@ -3071,9 +3070,8 @@ const Writer = struct {
.struct_init_ref,
=> try self.writeStructInit(stream, inst),
.cmpxchg_strong,
.cmpxchg_weak,
=> try self.writeCmpxchg(stream, inst),
.cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
.atomic_store => try self.writeAtomicStore(stream, inst),
.struct_init_anon,
.struct_init_anon_ref,
@ -3493,6 +3491,19 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
fn writeAtomicStore(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Inst.AtomicStore, inst_data.payload_index).data;
try self.writeInstRef(stream, extra.ptr);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.operand);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.ordering);
try stream.writeAll(") ");
try self.writeSrc(stream, inst_data.src());
}
fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index);

View File

@ -130,3 +130,11 @@ test "atomic load and rmw with enum" {
try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
}
test "atomic store" {
var x: u32 = 0;
@atomicStore(u32, &x, 1, .SeqCst);
try expect(@atomicLoad(u32, &x, .SeqCst) == 1);
@atomicStore(u32, &x, 12345678, .SeqCst);
try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
}

View File

@ -3,14 +3,6 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
test "atomic store" {
var x: u32 = 0;
@atomicStore(u32, &x, 1, .SeqCst);
try expect(@atomicLoad(u32, &x, .SeqCst) == 1);
@atomicStore(u32, &x, 12345678, .SeqCst);
try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
}
test "atomic store comptime" {
comptime try testAtomicStore();
try testAtomicStore();