mirror of
https://github.com/ziglang/zig.git
synced 2024-12-12 14:16:59 +00:00
stage2: implement @fence
This commit is contained in:
parent
e5fd45003e
commit
19691c0b17
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -264,6 +264,7 @@ fn analyzeInst(
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.unreach,
|
||||
.fence,
|
||||
=> return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
|
||||
|
||||
.not,
|
||||
|
31
src/Sema.zig
31
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (block.is_comptime) return;
|
||||
|
||||
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);
|
||||
|
||||
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 {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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];
|
||||
|
@ -24,3 +24,9 @@ fn testCmpxchg() !void {
|
||||
try expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null);
|
||||
try expect(x == 42);
|
||||
}
|
||||
|
||||
test "fence" {
|
||||
var x: i32 = 1234;
|
||||
@fence(.SeqCst);
|
||||
x = 5678;
|
||||
}
|
||||
|
@ -3,12 +3,6 @@ const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "fence" {
|
||||
var x: i32 = 1234;
|
||||
@fence(.SeqCst);
|
||||
x = 5678;
|
||||
}
|
||||
|
||||
test "atomicrmw and atomicload" {
|
||||
var data: u8 = 200;
|
||||
try testAtomicRmw(&data);
|
||||
|
Loading…
Reference in New Issue
Block a user