aboutsummaryrefslogtreecommitdiff
path: root/src/Air.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-15 18:55:39 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-15 19:00:35 -0700
commitb67d1810be3234c363ee2929ffcc91083bfb0ae5 (patch)
treec4fda56637928dc68069dcdd28411d37cafd721b /src/Air.zig
parentf83a4b444c4c2fca7086fe6dbdaccc7b6d8f35ca (diff)
downloadzig-b67d1810be3234c363ee2929ffcc91083bfb0ae5.tar.gz
zig-b67d1810be3234c363ee2929ffcc91083bfb0ae5.zip
stage2: implement `@atomicRmw` and `@atomicLoad`
* langref: add some more "see also" links for atomics * Add the following AIR instructions - atomic_load - atomic_store_unordered - atomic_store_monotonic - atomic_store_release - atomic_store_seq_cst - atomic_rmw * Implement those AIR instructions in LLVM and C backends. * AstGen: make the `ty` result locations for `@atomicRmw`, `@atomicLoad`, and `@atomicStore` be `coerced_ty` to avoid unnecessary ZIR instructions when Sema will be doing the coercions redundantly. * Sema for `@atomicLoad` and `@atomicRmw` is done, however Sema for `@atomicStore` is not yet implemented. - comptime eval for `@atomicRmw` is not yet implemented. * Sema: flesh out `coerceInMemoryAllowed` a little bit more. It can now handle pointers.
Diffstat (limited to 'src/Air.zig')
-rw-r--r--src/Air.zig60
1 files changed, 56 insertions, 4 deletions
diff --git a/src/Air.zig b/src/Air.zig
index e4289c2826..2834699d69 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -127,14 +127,11 @@ 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.
call,
+
/// `<`. Result type is always bool.
/// Uses the `bin_op` field.
cmp_lt,
@@ -153,6 +150,7 @@ pub const Inst = struct {
/// `!=`. Result type is always bool.
/// Uses the `bin_op` field.
cmp_neq,
+
/// Conditional branch.
/// Result type is always noreturn; no instructions in a block follow this one.
/// Uses the `pl_op` field. Operand is the condition. Payload is `CondBr`.
@@ -313,10 +311,33 @@ pub const Inst = struct {
/// Given a pointer to an array, return a slice.
/// Uses the `ty_op` field.
array_to_slice,
+
/// Uses the `ty_pl` field with payload `Cmpxchg`.
cmpxchg_weak,
/// Uses the `ty_pl` field with payload `Cmpxchg`.
cmpxchg_strong,
+ /// Lowers to a memory fence instruction.
+ /// Result type is always void.
+ /// Uses the `fence` field.
+ fence,
+ /// Atomically load from a pointer.
+ /// Result type is the element type of the pointer.
+ /// Uses the `atomic_load` field.
+ atomic_load,
+ /// Atomically store through a pointer.
+ /// Result type is always `void`.
+ /// Uses the `bin_op` field. LHS is pointer, RHS is element.
+ atomic_store_unordered,
+ /// Same as `atomic_store_unordered` but with `AtomicOrder.Monotonic`.
+ atomic_store_monotonic,
+ /// Same as `atomic_store_unordered` but with `AtomicOrder.Release`.
+ atomic_store_release,
+ /// Same as `atomic_store_unordered` but with `AtomicOrder.SeqCst`.
+ atomic_store_seq_cst,
+ /// Atomically read-modify-write via a pointer.
+ /// Result type is the element type of the pointer.
+ /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
+ atomic_rmw,
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
return switch (op) {
@@ -385,6 +406,10 @@ pub const Inst = struct {
column: u32,
},
fence: std.builtin.AtomicOrder,
+ atomic_load: struct {
+ ptr: Ref,
+ order: 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
@@ -469,6 +494,21 @@ pub const Cmpxchg = struct {
}
};
+pub const AtomicRmw = struct {
+ operand: Inst.Ref,
+ /// 0b00000000000000000000000000000XXX - ordering
+ /// 0b0000000000000000000000000XXXX000 - op
+ flags: u32,
+
+ pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder {
+ return @intToEnum(std.builtin.AtomicOrder, @truncate(u3, self.flags));
+ }
+
+ pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp {
+ return @intToEnum(std.builtin.AtomicRmwOp, @truncate(u4, self.flags >> 3));
+ }
+};
+
pub fn getMainBody(air: Air) []const Air.Inst.Index {
const body_index = air.extra[@enumToInt(ExtraIndex.main_block)];
const extra = air.extraData(Block, body_index);
@@ -572,6 +612,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.dbg_stmt,
.store,
.fence,
+ .atomic_store_unordered,
+ .atomic_store_monotonic,
+ .atomic_store_release,
+ .atomic_store_seq_cst,
=> return Type.initTag(.void),
.ptrtoint,
@@ -594,6 +638,14 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
const inner_ptr_ty = outer_ptr_ty.elemType();
return inner_ptr_ty.elemType();
},
+ .atomic_load => {
+ const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr);
+ return ptr_ty.elemType();
+ },
+ .atomic_rmw => {
+ const ptr_ty = air.typeOf(datas[inst].pl_op.operand);
+ return ptr_ty.elemType();
+ },
}
}