aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-15 12:37:32 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-15 12:37:32 -0700
commit19691c0b174f283ffe5b6c3fe8533ef458736064 (patch)
tree802390ce8ad5d29cc72450262efd4b13140f5f20 /src
parente5fd45003e56f152364a4bdc609fda07a6b524fd (diff)
downloadzig-19691c0b174f283ffe5b6c3fe8533ef458736064.tar.gz
zig-19691c0b174f283ffe5b6c3fe8533ef458736064.zip
stage2: implement `@fence`
Diffstat (limited to 'src')
-rw-r--r--src/Air.zig6
-rw-r--r--src/AstGen.zig6
-rw-r--r--src/Liveness.zig1
-rw-r--r--src/Sema.zig29
-rw-r--r--src/Zir.zig6
-rw-r--r--src/codegen.zig6
-rw-r--r--src/codegen/c.zig12
-rw-r--r--src/codegen/llvm.zig9
-rw-r--r--src/codegen/llvm/bindings.zig8
-rw-r--r--src/link/C/zig.h3
-rw-r--r--src/print_air.zig7
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];