authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-19 15:07:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-19 15:08:38-07:00
log9fa723ee5043a9d2cb017e417f2e27041f671146
treed25613e4fcf60dbb5294946eb578de7ebe2c1be4
parent2a0c44fff3506cdc072d67374e7ffca495cebdc7

stage2: implement `@atomicStore`


5 files changed, 84 insertions(+), 23 deletions(-)

src/AstGen.zig+1-1
......@@ -2118,7 +2118,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
21182118 .select,
21192119 .atomic_load,
21202120 .atomic_rmw,
2121 .atomic_store,
21222121 .mul_add,
21232122 .builtin_call,
21242123 .field_ptr_type,
......@@ -2164,6 +2163,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
21642163 .@"export",
21652164 .set_eval_branch_quota,
21662165 .ensure_err_payload_void,
2166 .atomic_store,
21672167 .store,
21682168 .store_node,
21692169 .store_to_block_ptr,
src/Sema.zig+60-10
......@@ -314,7 +314,6 @@ pub fn analyzeBody(
314314 .select => try sema.zirSelect(block, inst),
315315 .atomic_load => try sema.zirAtomicLoad(block, inst),
316316 .atomic_rmw => try sema.zirAtomicRmw(block, inst),
317 .atomic_store => try sema.zirAtomicStore(block, inst),
318317 .mul_add => try sema.zirMulAdd(block, inst),
319318 .builtin_call => try sema.zirBuiltinCall(block, inst),
320319 .field_ptr_type => try sema.zirFieldPtrType(block, inst),
......@@ -413,6 +412,11 @@ pub fn analyzeBody(
413412 i += 1;
414413 continue;
415414 },
415 .atomic_store => {
416 try sema.zirAtomicStore(block, inst);
417 i += 1;
418 continue;
419 },
416420 .store => {
417421 try sema.zirStore(block, inst);
418422 i += 1;
......@@ -7669,6 +7673,8 @@ fn zirCmpxchg(
76697673 if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| {
76707674 if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| {
76717675 if (expected_val.isUndef() or new_val.isUndef()) {
7676 // TODO: this should probably cause the memory stored at the pointer
7677 // to become undef as well
76727678 return sema.addConstUndef(result_ty);
76737679 }
76747680 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
78307836 });
78317837}
78327838
7833fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
7839fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
78347840 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
7841 const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
78357842 const src = inst_data.src();
7836 return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicStore", .{});
7843 // zig fmt: off
7844 const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
7845 const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
7846 const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
7847 const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
7848 // zig fmt: on
7849 const ptr = sema.resolveInst(extra.ptr);
7850 const operand_ty = sema.typeOf(ptr).elemType();
7851 try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty);
7852 const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src);
7853 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering);
7854
7855 const air_tag: Air.Inst.Tag = switch (order) {
7856 .Acquire, .AcqRel => {
7857 return sema.mod.fail(
7858 &block.base,
7859 order_src,
7860 "@atomicStore atomic ordering must not be Acquire or AcqRel",
7861 .{},
7862 );
7863 },
7864 .Unordered => .atomic_store_unordered,
7865 .Monotonic => .atomic_store_monotonic,
7866 .Release => .atomic_store_release,
7867 .SeqCst => .atomic_store_seq_cst,
7868 };
7869
7870 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
78377871}
78387872
78397873fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -9310,25 +9344,39 @@ fn coerceVarArgParam(
93109344 return inst;
93119345}
93129346
9347// TODO migrate callsites to use storePtr2 instead.
93139348fn storePtr(
93149349 sema: *Sema,
93159350 block: *Scope.Block,
93169351 src: LazySrcLoc,
93179352 ptr: Air.Inst.Ref,
9318 uncasted_value: Air.Inst.Ref,
9353 uncasted_operand: Air.Inst.Ref,
9354) !void {
9355 return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, .store);
9356}
9357
9358fn storePtr2(
9359 sema: *Sema,
9360 block: *Scope.Block,
9361 src: LazySrcLoc,
9362 ptr: Air.Inst.Ref,
9363 ptr_src: LazySrcLoc,
9364 uncasted_operand: Air.Inst.Ref,
9365 operand_src: LazySrcLoc,
9366 air_tag: Air.Inst.Tag,
93199367) !void {
93209368 const ptr_ty = sema.typeOf(ptr);
93219369 if (ptr_ty.isConstPtr())
93229370 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
93239371
93249372 const elem_ty = ptr_ty.elemType();
9325 const value = try sema.coerce(block, elem_ty, uncasted_value, src);
9373 const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
93269374 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
93279375 return;
93289376
9329 if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
9377 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
93309378 if (ptr_val.castTag(.decl_ref_mut)) |decl_ref_mut| {
9331 const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse
9379 const const_val = (try sema.resolveMaybeUndefVal(block, operand_src, operand)) orelse
93329380 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
93339381
93349382 if (decl_ref_mut.data.runtime_index < block.runtime_index) {
......@@ -9365,11 +9413,13 @@ fn storePtr(
93659413 old_arena.deinit();
93669414 return;
93679415 }
9368 }
9416 break :rs operand_src;
9417 } else ptr_src;
9418
93699419 // TODO handle if the element type requires comptime
93709420
9371 try sema.requireRuntimeBlock(block, src);
9372 _ = try block.addBinOp(.store, ptr, value);
9421 try sema.requireRuntimeBlock(block, runtime_src);
9422 _ = try block.addBinOp(air_tag, ptr, operand);
93739423}
93749424
93759425fn bitcast(
src/Zir.zig+15-4
......@@ -3058,7 +3058,6 @@ const Writer = struct {
30583058 .shuffle,
30593059 .select,
30603060 .atomic_rmw,
3061 .atomic_store,
30623061 .mul_add,
30633062 .builtin_call,
30643063 .field_parent_ptr,
......@@ -3071,9 +3070,8 @@ const Writer = struct {
30713070 .struct_init_ref,
30723071 => try self.writeStructInit(stream, inst),
30733072
3074 .cmpxchg_strong,
3075 .cmpxchg_weak,
3076 => try self.writeCmpxchg(stream, inst),
3073 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
3074 .atomic_store => try self.writeAtomicStore(stream, inst),
30773075
30783076 .struct_init_anon,
30793077 .struct_init_anon_ref,
......@@ -3493,6 +3491,19 @@ const Writer = struct {
34933491 try self.writeSrc(stream, inst_data.src());
34943492 }
34953493
3494 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3495 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3496 const extra = self.code.extraData(Inst.AtomicStore, inst_data.payload_index).data;
3497
3498 try self.writeInstRef(stream, extra.ptr);
3499 try stream.writeAll(", ");
3500 try self.writeInstRef(stream, extra.operand);
3501 try stream.writeAll(", ");
3502 try self.writeInstRef(stream, extra.ordering);
3503 try stream.writeAll(") ");
3504 try self.writeSrc(stream, inst_data.src());
3505 }
3506
34963507 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void {
34973508 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
34983509 const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index);
test/behavior/atomics.zig+8
......@@ -130,3 +130,11 @@ test "atomic load and rmw with enum" {
130130 try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
131131 try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
132132}
133
134test "atomic store" {
135 var x: u32 = 0;
136 @atomicStore(u32, &x, 1, .SeqCst);
137 try expect(@atomicLoad(u32, &x, .SeqCst) == 1);
138 @atomicStore(u32, &x, 12345678, .SeqCst);
139 try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
140}
test/behavior/atomics_stage1.zig-8
......@@ -3,14 +3,6 @@ const expect = std.testing.expect;
33const expectEqual = std.testing.expectEqual;
44const builtin = @import("builtin");
55
6test "atomic store" {
7 var x: u32 = 0;
8 @atomicStore(u32, &x, 1, .SeqCst);
9 try expect(@atomicLoad(u32, &x, .SeqCst) == 1);
10 @atomicStore(u32, &x, 12345678, .SeqCst);
11 try expect(@atomicLoad(u32, &x, .SeqCst) == 12345678);
12}
13
146test "atomic store comptime" {
157 comptime try testAtomicStore();
168 try testAtomicStore();