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...@@ -2118,7 +2118,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2118 .select,2118 .select,
2119 .atomic_load,2119 .atomic_load,
2120 .atomic_rmw,2120 .atomic_rmw,
2121 .atomic_store,
2122 .mul_add,2121 .mul_add,
2123 .builtin_call,2122 .builtin_call,
2124 .field_ptr_type,2123 .field_ptr_type,
...@@ -2164,6 +2163,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2164,6 +2163,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2164 .@"export",2163 .@"export",
2165 .set_eval_branch_quota,2164 .set_eval_branch_quota,
2166 .ensure_err_payload_void,2165 .ensure_err_payload_void,
2166 .atomic_store,
2167 .store,2167 .store,
2168 .store_node,2168 .store_node,
2169 .store_to_block_ptr,2169 .store_to_block_ptr,
src/Sema.zig+60-10
...@@ -314,7 +314,6 @@ pub fn analyzeBody(...@@ -314,7 +314,6 @@ pub fn analyzeBody(
314 .select => try sema.zirSelect(block, inst),314 .select => try sema.zirSelect(block, inst),
315 .atomic_load => try sema.zirAtomicLoad(block, inst),315 .atomic_load => try sema.zirAtomicLoad(block, inst),
316 .atomic_rmw => try sema.zirAtomicRmw(block, inst),316 .atomic_rmw => try sema.zirAtomicRmw(block, inst),
317 .atomic_store => try sema.zirAtomicStore(block, inst),
318 .mul_add => try sema.zirMulAdd(block, inst),317 .mul_add => try sema.zirMulAdd(block, inst),
319 .builtin_call => try sema.zirBuiltinCall(block, inst),318 .builtin_call => try sema.zirBuiltinCall(block, inst),
320 .field_ptr_type => try sema.zirFieldPtrType(block, inst),319 .field_ptr_type => try sema.zirFieldPtrType(block, inst),
...@@ -413,6 +412,11 @@ pub fn analyzeBody(...@@ -413,6 +412,11 @@ pub fn analyzeBody(
413 i += 1;412 i += 1;
414 continue;413 continue;
415 },414 },
415 .atomic_store => {
416 try sema.zirAtomicStore(block, inst);
417 i += 1;
418 continue;
419 },
416 .store => {420 .store => {
417 try sema.zirStore(block, inst);421 try sema.zirStore(block, inst);
418 i += 1;422 i += 1;
...@@ -7669,6 +7673,8 @@ fn zirCmpxchg(...@@ -7669,6 +7673,8 @@ fn zirCmpxchg(
7669 if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| {7673 if (try sema.resolveMaybeUndefVal(block, expected_src, expected_value)) |expected_val| {
7670 if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| {7674 if (try sema.resolveMaybeUndefVal(block, new_value_src, new_value)) |new_val| {
7671 if (expected_val.isUndef() or new_val.isUndef()) {7675 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
7672 return sema.addConstUndef(result_ty);7678 return sema.addConstUndef(result_ty);
7673 }7679 }
7674 const stored_val = (try ptr_val.pointerDeref(sema.arena)) orelse break :rs ptr_src;7680 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...@@ -7830,10 +7836,38 @@ fn zirAtomicRmw(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
7830 });7836 });
7831}7837}
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 {
7834 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;7840 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;
7835 const src = inst_data.src();7842 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);
7837}7871}
78387872
7839fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {7873fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9310,25 +9344,39 @@ fn coerceVarArgParam(...@@ -9310,25 +9344,39 @@ fn coerceVarArgParam(
9310 return inst;9344 return inst;
9311}9345}
93129346
9347// TODO migrate callsites to use storePtr2 instead.
9313fn storePtr(9348fn storePtr(
9314 sema: *Sema,9349 sema: *Sema,
9315 block: *Scope.Block,9350 block: *Scope.Block,
9316 src: LazySrcLoc,9351 src: LazySrcLoc,
9317 ptr: Air.Inst.Ref,9352 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,
9319) !void {9367) !void {
9320 const ptr_ty = sema.typeOf(ptr);9368 const ptr_ty = sema.typeOf(ptr);
9321 if (ptr_ty.isConstPtr())9369 if (ptr_ty.isConstPtr())
9322 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});9370 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
93239371
9324 const elem_ty = ptr_ty.elemType();9372 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);
9326 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)9374 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
9327 return;9375 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: {
9330 if (ptr_val.castTag(.decl_ref_mut)) |decl_ref_mut| {9378 if (ptr_val.castTag(.decl_ref_mut)) |decl_ref_mut| {
9331 const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse9379 const const_val = (try sema.resolveMaybeUndefVal(block, operand_src, operand)) orelse
9332 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});9380 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
93339381
9334 if (decl_ref_mut.data.runtime_index < block.runtime_index) {9382 if (decl_ref_mut.data.runtime_index < block.runtime_index) {
...@@ -9365,11 +9413,13 @@ fn storePtr(...@@ -9365,11 +9413,13 @@ fn storePtr(
9365 old_arena.deinit();9413 old_arena.deinit();
9366 return;9414 return;
9367 }9415 }
9368 }9416 break :rs operand_src;
9417 } else ptr_src;
9418
9369 // TODO handle if the element type requires comptime9419 // TODO handle if the element type requires comptime
93709420
9371 try sema.requireRuntimeBlock(block, src);9421 try sema.requireRuntimeBlock(block, runtime_src);
9372 _ = try block.addBinOp(.store, ptr, value);9422 _ = try block.addBinOp(air_tag, ptr, operand);
9373}9423}
93749424
9375fn bitcast(9425fn bitcast(
src/Zir.zig+15-4
...@@ -3058,7 +3058,6 @@ const Writer = struct {...@@ -3058,7 +3058,6 @@ const Writer = struct {
3058 .shuffle,3058 .shuffle,
3059 .select,3059 .select,
3060 .atomic_rmw,3060 .atomic_rmw,
3061 .atomic_store,
3062 .mul_add,3061 .mul_add,
3063 .builtin_call,3062 .builtin_call,
3064 .field_parent_ptr,3063 .field_parent_ptr,
...@@ -3071,9 +3070,8 @@ const Writer = struct {...@@ -3071,9 +3070,8 @@ const Writer = struct {
3071 .struct_init_ref,3070 .struct_init_ref,
3072 => try self.writeStructInit(stream, inst),3071 => try self.writeStructInit(stream, inst),
30733072
3074 .cmpxchg_strong,3073 .cmpxchg_strong, .cmpxchg_weak => try self.writeCmpxchg(stream, inst),
3075 .cmpxchg_weak,3074 .atomic_store => try self.writeAtomicStore(stream, inst),
3076 => try self.writeCmpxchg(stream, inst),
30773075
3078 .struct_init_anon,3076 .struct_init_anon,
3079 .struct_init_anon_ref,3077 .struct_init_anon_ref,
...@@ -3493,6 +3491,19 @@ const Writer = struct {...@@ -3493,6 +3491,19 @@ const Writer = struct {
3493 try self.writeSrc(stream, inst_data.src());3491 try self.writeSrc(stream, inst_data.src());
3494 }3492 }
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
3496 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void {3507 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3497 const inst_data = self.code.instructions.items(.data)[inst].pl_node;3508 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3498 const extra = self.code.extraData(Inst.StructInitAnon, inst_data.payload_index);3509 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" {...@@ -130,3 +130,11 @@ test "atomic load and rmw with enum" {
130 try expect(@atomicLoad(Value, &x, .SeqCst) != .a);130 try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
131 try expect(@atomicLoad(Value, &x, .SeqCst) != .b);131 try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
132}132}
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;...@@ -3,14 +3,6 @@ const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
4const builtin = @import("builtin");4const 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
14test "atomic store comptime" {6test "atomic store comptime" {
15 comptime try testAtomicStore();7 comptime try testAtomicStore();
16 try testAtomicStore();8 try testAtomicStore();