diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-09-15 12:37:32 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-15 12:37:32 -0700 |
| commit | 19691c0b174f283ffe5b6c3fe8533ef458736064 (patch) | |
| tree | 802390ce8ad5d29cc72450262efd4b13140f5f20 /src | |
| parent | e5fd45003e56f152364a4bdc609fda07a6b524fd (diff) | |
| download | zig-19691c0b174f283ffe5b6c3fe8533ef458736064.tar.gz zig-19691c0b174f283ffe5b6c3fe8533ef458736064.zip | |
stage2: implement `@fence`
Diffstat (limited to 'src')
| -rw-r--r-- | src/Air.zig | 6 | ||||
| -rw-r--r-- | src/AstGen.zig | 6 | ||||
| -rw-r--r-- | src/Liveness.zig | 1 | ||||
| -rw-r--r-- | src/Sema.zig | 29 | ||||
| -rw-r--r-- | src/Zir.zig | 6 | ||||
| -rw-r--r-- | src/codegen.zig | 6 | ||||
| -rw-r--r-- | src/codegen/c.zig | 12 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 9 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 8 | ||||
| -rw-r--r-- | src/link/C/zig.h | 3 | ||||
| -rw-r--r-- | src/print_air.zig | 7 |
11 files changed, 76 insertions, 17 deletions
diff --git a/src/Air.zig b/src/Air.zig index 29deb9a523..e4289c2826 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -127,6 +127,10 @@ pub const Inst = struct { /// Lowers to a hardware trap instruction, or the next best thing. /// Result type is always void. breakpoint, + /// Lowers to a memory fence instruction. + /// Result type is always void. + /// Uses the `fence` field. + fence, /// Function call. /// Result type is the return type of the function being called. /// Uses the `pl_op` field with the `Call` payload. operand is the callee. @@ -380,6 +384,7 @@ pub const Inst = struct { line: u32, column: u32, }, + fence: std.builtin.AtomicOrder, // Make sure we don't accidentally add a field to make this union // bigger than expected. Note that in Debug builds, Zig is allowed @@ -566,6 +571,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .breakpoint, .dbg_stmt, .store, + .fence, => return Type.initTag(.void), .ptrtoint, diff --git a/src/AstGen.zig b/src/AstGen.zig index b9d7d6f5be..ac4c807027 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7116,9 +7116,13 @@ fn builtinCall( }); return rvalue(gz, rl, result, node); }, + .fence => { + const order = try expr(gz, scope, .{ .coerced_ty = .atomic_order_type }, params[0]); + const result = try gz.addUnNode(.fence, order, node); + return rvalue(gz, rl, result, node); + }, .breakpoint => return simpleNoOpVoid(gz, rl, node, .breakpoint), - .fence => return simpleNoOpVoid(gz, rl, node, .fence), .This => return rvalue(gz, rl, try gz.addNodeExtended(.this, node), node), .return_address => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr, node), node), diff --git a/src/Liveness.zig b/src/Liveness.zig index 5d8e3eed34..a7519a33ee 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -264,6 +264,7 @@ fn analyzeInst( .breakpoint, .dbg_stmt, .unreach, + .fence, => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), .not, diff --git a/src/Sema.zig b/src/Sema.zig index de0d0b7c88..e679f03fcc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -377,7 +377,9 @@ pub fn analyzeBody( // We also know that they cannot be referenced later, so we avoid // putting them into the map. .breakpoint => { - try sema.zirBreakpoint(block, inst); + if (!block.is_comptime) { + _ = try block.addNoOp(.breakpoint); + } i += 1; continue; }, @@ -2308,20 +2310,21 @@ fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) C block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand); } -fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { - const tracy = trace(@src()); - defer tracy.end(); +fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { + if (block.is_comptime) return; - const src_node = sema.code.instructions.items(.data)[inst].node; - const src: LazySrcLoc = .{ .node_offset = src_node }; - try sema.requireRuntimeBlock(block, src); - _ = try block.addNoOp(.breakpoint); -} + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; + const order = try sema.resolveAtomicOrder(block, order_src, inst_data.operand); -fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { - const src_node = sema.code.instructions.items(.data)[inst].node; - const src: LazySrcLoc = .{ .node_offset = src_node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{}); + if (@enumToInt(order) < @enumToInt(std.builtin.AtomicOrder.Acquire)) { + return sema.mod.fail(&block.base, order_src, "atomic ordering must be Acquire or stricter", .{}); + } + + _ = try block.addInst(.{ + .tag = .fence, + .data = .{ .fence = order }, + }); } fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { diff --git a/src/Zir.zig b/src/Zir.zig index 1f0e4e370b..fcc2d5f330 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -731,7 +731,7 @@ pub const Inst = struct { size_of, /// Implements the `@bitSizeOf` builtin. Uses `un_node`. bit_size_of, - /// Implements the `@fence` builtin. Uses `node`. + /// Implements the `@fence` builtin. Uses `un_node`. fence, /// Implement builtin `@ptrToInt`. Uses `un_node`. @@ -1416,7 +1416,7 @@ pub const Inst = struct { .type_info = .un_node, .size_of = .un_node, .bit_size_of = .un_node, - .fence = .node, + .fence = .un_node, .ptr_to_int = .un_node, .error_to_int = .un_node, @@ -3016,6 +3016,7 @@ const Writer = struct { .@"resume", .@"await", .await_nosuspend, + .fence, => try self.writeUnNode(stream, inst), .ref, @@ -3187,7 +3188,6 @@ const Writer = struct { .as_node => try self.writeAs(stream, inst), .breakpoint, - .fence, .repeat, .repeat_inline, .alloc_inferred, diff --git a/src/codegen.zig b/src/codegen.zig index e79003f728..75e7a56b15 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -833,6 +833,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .block => try self.airBlock(inst), .br => try self.airBr(inst), .breakpoint => try self.airBreakpoint(), + .fence => try self.airFence(), .call => try self.airCall(inst), .cond_br => try self.airCondBr(inst), .dbg_stmt => try self.airDbgStmt(inst), @@ -2549,6 +2550,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { return self.finishAirBookkeeping(); } + fn airFence(self: *Self) !void { + return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch}); + //return self.finishAirBookkeeping(); + } + fn airCall(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const fn_ty = self.air.typeOf(pl_op.operand); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index ff49b18f7b..a2e2d7b20d 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -842,6 +842,7 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM .breakpoint => try airBreakpoint(o), .unreach => try airUnreach(o), + .fence => try airFence(o, inst), // TODO use a different strategy for add that communicates to the optimizer // that wrapping is UB. @@ -1439,6 +1440,17 @@ fn airBreakpoint(o: *Object) !CValue { return CValue.none; } +fn airFence(o: *Object, inst: Air.Inst.Index) !CValue { + const atomic_order = o.air.instructions.items(.data)[inst].fence; + const writer = o.writer(); + + try writer.writeAll("zig_fence("); + try writeMemoryOrder(writer, atomic_order); + try writer.writeAll(");\n"); + + return CValue.none; +} + fn airUnreach(o: *Object) !CValue { try o.writer().writeAll("zig_unreachable();\n"); return CValue.none; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index b28c371466..569f857caa 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1059,6 +1059,7 @@ pub const FuncGen = struct { .array_to_slice => try self.airArrayToSlice(inst), .cmpxchg_weak => try self.airCmpxchg(inst, true), .cmpxchg_strong => try self.airCmpxchg(inst, false), + .fence => try self.airFence(inst), .struct_field_ptr => try self.airStructFieldPtr(inst), .struct_field_val => try self.airStructFieldVal(inst), @@ -2005,6 +2006,14 @@ pub const FuncGen = struct { return null; } + fn airFence(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + const atomic_order = self.air.instructions.items(.data)[inst].fence; + const llvm_memory_order = toLlvmAtomicOrdering(atomic_order); + const single_threaded = llvm.Bool.fromBool(self.single_threaded); + _ = self.builder.buildFence(llvm_memory_order, single_threaded, ""); + return null; + } + fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*const llvm.Value { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index b4bd91708d..3fed3ca879 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -522,6 +522,14 @@ pub const Builder = opaque { Else: *const Value, Name: [*:0]const u8, ) *const Value; + + pub const buildFence = LLVMBuildFence; + extern fn LLVMBuildFence( + B: *const Builder, + ordering: AtomicOrdering, + singleThread: Bool, + Name: [*:0]const u8, + ) *const Value; }; pub const IntPredicate = enum(c_uint) { diff --git a/src/link/C/zig.h b/src/link/C/zig.h index f3fb02b840..28d6f2dd17 100644 --- a/src/link/C/zig.h +++ b/src/link/C/zig.h @@ -64,12 +64,15 @@ #include <stdatomic.h> #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) +#define zig_fence(order) atomic_thread_fence(order) #elif __GNUC__ #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __sync_val_compare_and_swap(obj, expected, desired) #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) __sync_val_compare_and_swap(obj, expected, desired) +#define zig_fence(order) __sync_synchronize(order) #else #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) zig_unimplemented() #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) zig_unimplemented() +#define zig_fence(order) zig_unimplemented() #endif #include <stdint.h> diff --git a/src/print_air.zig b/src/print_air.zig index 11cf1b7baa..82068188fd 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -192,6 +192,7 @@ const Writer = struct { .cond_br => try w.writeCondBr(s, inst), .switch_br => try w.writeSwitchBr(s, inst), .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst), + .fence => try w.writeFence(s, inst), } } @@ -276,6 +277,12 @@ const Writer = struct { }); } + fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const atomic_order = w.air.instructions.items(.data)[inst].fence; + + try s.print("{s}", .{@tagName(atomic_order)}); + } + fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; const val = w.air.values[ty_pl.payload]; |
