aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2018-10-17 21:16:01 +0100
committergingerBill <bill@gingerbill.org>2018-10-17 21:16:01 +0100
commitb171cc41e6cc0271656593b547c3f8b27664d5bc (patch)
treec34fc8d8555fbf6892ff6798bc7ed52208f6f3da /src
parentefc3a9e69dd072b678a78535d7b5a5f71e474024 (diff)
__atomic_* "intrinsics" using LLVM instructions
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp146
-rw-r--r--src/check_type.cpp1
-rw-r--r--src/checker.cpp5
-rw-r--r--src/checker.hpp149
-rw-r--r--src/entity.cpp14
-rw-r--r--src/ir.cpp201
-rw-r--r--src/ir_print.cpp269
7 files changed, 765 insertions, 20 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 2e1663f98..60e5d2649 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -2872,6 +2872,18 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
return entity;
}
+bool is_type_normal_pointer(Type *ptr, Type **elem) {
+ ptr = base_type(ptr);
+ if (is_type_pointer(ptr)) {
+ if (is_type_rawptr(ptr)) {
+ return false;
+ }
+ if (elem) *elem = ptr->Pointer.elem;
+ return true;
+ }
+ return false;
+}
+
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
ast_node(ce, CallExpr, call);
@@ -2914,6 +2926,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
+ String builtin_name = builtin_procs[id].name;
+
if (ce->args.count > 0) {
if (ce->args[0]->kind == Ast_FieldValue) {
@@ -2924,7 +2938,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
switch (id) {
default:
- GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_procs[id].name));
+ GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
break;
case BuiltinProc_DIRECTIVE: {
@@ -3023,9 +3037,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
if (mode == Addressing_Invalid) {
- String name = builtin_procs[id].name;
gbString t = type_to_string(operand->type);
- error(call, "'%.*s' is not supported for '%s'", LIT(name), t);
+ error(call, "'%.*s' is not supported for '%s'", LIT(builtin_name), t);
return false;
}
@@ -3805,6 +3818,133 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
+ case BuiltinProc_atomic_fence:
+ case BuiltinProc_atomic_fence_acq:
+ case BuiltinProc_atomic_fence_rel:
+ case BuiltinProc_atomic_fence_acqrel:
+ operand->mode = Addressing_NoValue;
+ break;
+
+ case BuiltinProc_atomic_store:
+ case BuiltinProc_atomic_store_rel:
+ case BuiltinProc_atomic_store_relaxed:
+ case BuiltinProc_atomic_store_unordered:
+ {
+ Type *elem = nullptr;
+ if (!is_type_normal_pointer(operand->type, &elem)) {
+ error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ Operand x = {};
+ check_expr_with_type_hint(c, &x, ce->args[1], elem);
+ check_assignment(c, &x, elem, builtin_name);
+
+ operand->type = nullptr;
+ operand->mode = Addressing_NoValue;
+ break;
+ }
+ case BuiltinProc_atomic_load:
+ case BuiltinProc_atomic_load_acq:
+ case BuiltinProc_atomic_load_relaxed:
+ case BuiltinProc_atomic_load_unordered:
+ {
+ Type *elem = nullptr;
+ if (!is_type_normal_pointer(operand->type, &elem)) {
+ error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ operand->type = elem;
+ operand->mode = Addressing_Value;
+ break;
+ }
+
+ case BuiltinProc_atomic_add:
+ case BuiltinProc_atomic_add_acq:
+ case BuiltinProc_atomic_add_rel:
+ case BuiltinProc_atomic_add_acqrel:
+ case BuiltinProc_atomic_add_relaxed:
+ case BuiltinProc_atomic_sub:
+ case BuiltinProc_atomic_sub_acq:
+ case BuiltinProc_atomic_sub_rel:
+ case BuiltinProc_atomic_sub_acqrel:
+ case BuiltinProc_atomic_sub_relaxed:
+ case BuiltinProc_atomic_and:
+ case BuiltinProc_atomic_and_acq:
+ case BuiltinProc_atomic_and_rel:
+ case BuiltinProc_atomic_and_acqrel:
+ case BuiltinProc_atomic_and_relaxed:
+ case BuiltinProc_atomic_nand:
+ case BuiltinProc_atomic_nand_acq:
+ case BuiltinProc_atomic_nand_rel:
+ case BuiltinProc_atomic_nand_acqrel:
+ case BuiltinProc_atomic_nand_relaxed:
+ case BuiltinProc_atomic_or:
+ case BuiltinProc_atomic_or_acq:
+ case BuiltinProc_atomic_or_rel:
+ case BuiltinProc_atomic_or_acqrel:
+ case BuiltinProc_atomic_or_relaxed:
+ case BuiltinProc_atomic_xor:
+ case BuiltinProc_atomic_xor_acq:
+ case BuiltinProc_atomic_xor_rel:
+ case BuiltinProc_atomic_xor_acqrel:
+ case BuiltinProc_atomic_xor_relaxed:
+ case BuiltinProc_atomic_xchg:
+ case BuiltinProc_atomic_xchg_acq:
+ case BuiltinProc_atomic_xchg_rel:
+ case BuiltinProc_atomic_xchg_acqrel:
+ case BuiltinProc_atomic_xchg_relaxed:
+ {
+ Type *elem = nullptr;
+ if (!is_type_normal_pointer(operand->type, &elem)) {
+ error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ Operand x = {};
+ check_expr_with_type_hint(c, &x, ce->args[1], elem);
+ check_assignment(c, &x, elem, builtin_name);
+
+ operand->type = elem;
+ operand->mode = Addressing_Value;
+ break;
+ }
+
+ case BuiltinProc_atomic_cxchg:
+ case BuiltinProc_atomic_cxchg_acq:
+ case BuiltinProc_atomic_cxchg_rel:
+ case BuiltinProc_atomic_cxchg_acqrel:
+ case BuiltinProc_atomic_cxchg_relaxed:
+ case BuiltinProc_atomic_cxchg_failrelaxed:
+ case BuiltinProc_atomic_cxchg_failacq:
+ case BuiltinProc_atomic_cxchg_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchg_acqrel_failrelaxed:
+
+ case BuiltinProc_atomic_cxchgweak:
+ case BuiltinProc_atomic_cxchgweak_acq:
+ case BuiltinProc_atomic_cxchgweak_rel:
+ case BuiltinProc_atomic_cxchgweak_acqrel:
+ case BuiltinProc_atomic_cxchgweak_relaxed:
+ case BuiltinProc_atomic_cxchgweak_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_failacq:
+ case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed:
+ {
+ Type *elem = nullptr;
+ if (!is_type_normal_pointer(operand->type, &elem)) {
+ error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ Operand x = {};
+ Operand y = {};
+ check_expr_with_type_hint(c, &x, ce->args[1], elem);
+ check_expr_with_type_hint(c, &y, ce->args[2], elem);
+ check_assignment(c, &x, elem, builtin_name);
+ check_assignment(c, &y, elem, builtin_name);
+
+ operand->mode = Addressing_Value;
+ operand->type = make_optional_ok_type(elem);
+ break;
+ }
+ break;
}
return true;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 9704db081..f1c9875a1 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -2068,6 +2068,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
}
Type *make_optional_ok_type(Type *value) {
+ // LEAK TODO(bill): probably don't reallocate everything here and reuse the same one for the same type if possible
gbAllocator a = heap_allocator();
bool typed = true;
Type *t = alloc_type_tuple();
diff --git a/src/checker.cpp b/src/checker.cpp
index 61910f959..14daeb7ed 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -494,13 +494,14 @@ void add_declaration_dependency(CheckerContext *c, Entity *e) {
Entity *add_global_entity(Entity *entity) {
String name = entity->token.string;
+ defer (entity->state = EntityState_Resolved);
+
if (gb_memchr(name.text, ' ', name.len)) {
- return entity; // NOTE(bill): 'untyped thing'
+ return entity; // NOTE(bill): Usually an 'untyped thing'
}
if (scope_insert(builtin_scope, entity)) {
compiler_error("double declaration");
}
- entity->state = EntityState_Resolved;
return entity;
}
diff --git a/src/checker.hpp b/src/checker.hpp
index 5d05d5809..855a48da3 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -81,6 +81,79 @@ enum BuiltinProcId {
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
+ // "Intrinsics"
+ BuiltinProc_atomic_fence,
+ BuiltinProc_atomic_fence_acq,
+ BuiltinProc_atomic_fence_rel,
+ BuiltinProc_atomic_fence_acqrel,
+
+ BuiltinProc_atomic_store,
+ BuiltinProc_atomic_store_rel,
+ BuiltinProc_atomic_store_relaxed,
+ BuiltinProc_atomic_store_unordered,
+
+ BuiltinProc_atomic_load,
+ BuiltinProc_atomic_load_acq,
+ BuiltinProc_atomic_load_relaxed,
+ BuiltinProc_atomic_load_unordered,
+
+ BuiltinProc_atomic_add,
+ BuiltinProc_atomic_add_acq,
+ BuiltinProc_atomic_add_rel,
+ BuiltinProc_atomic_add_acqrel,
+ BuiltinProc_atomic_add_relaxed,
+ BuiltinProc_atomic_sub,
+ BuiltinProc_atomic_sub_acq,
+ BuiltinProc_atomic_sub_rel,
+ BuiltinProc_atomic_sub_acqrel,
+ BuiltinProc_atomic_sub_relaxed,
+ BuiltinProc_atomic_and,
+ BuiltinProc_atomic_and_acq,
+ BuiltinProc_atomic_and_rel,
+ BuiltinProc_atomic_and_acqrel,
+ BuiltinProc_atomic_and_relaxed,
+ BuiltinProc_atomic_nand,
+ BuiltinProc_atomic_nand_acq,
+ BuiltinProc_atomic_nand_rel,
+ BuiltinProc_atomic_nand_acqrel,
+ BuiltinProc_atomic_nand_relaxed,
+ BuiltinProc_atomic_or,
+ BuiltinProc_atomic_or_acq,
+ BuiltinProc_atomic_or_rel,
+ BuiltinProc_atomic_or_acqrel,
+ BuiltinProc_atomic_or_relaxed,
+ BuiltinProc_atomic_xor,
+ BuiltinProc_atomic_xor_acq,
+ BuiltinProc_atomic_xor_rel,
+ BuiltinProc_atomic_xor_acqrel,
+ BuiltinProc_atomic_xor_relaxed,
+
+ BuiltinProc_atomic_xchg,
+ BuiltinProc_atomic_xchg_acq,
+ BuiltinProc_atomic_xchg_rel,
+ BuiltinProc_atomic_xchg_acqrel,
+ BuiltinProc_atomic_xchg_relaxed,
+
+ BuiltinProc_atomic_cxchg,
+ BuiltinProc_atomic_cxchg_acq,
+ BuiltinProc_atomic_cxchg_rel,
+ BuiltinProc_atomic_cxchg_acqrel,
+ BuiltinProc_atomic_cxchg_relaxed,
+ BuiltinProc_atomic_cxchg_failrelaxed,
+ BuiltinProc_atomic_cxchg_failacq,
+ BuiltinProc_atomic_cxchg_acq_failrelaxed,
+ BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
+
+ BuiltinProc_atomic_cxchgweak,
+ BuiltinProc_atomic_cxchgweak_acq,
+ BuiltinProc_atomic_cxchgweak_rel,
+ BuiltinProc_atomic_cxchgweak_acqrel,
+ BuiltinProc_atomic_cxchgweak_relaxed,
+ BuiltinProc_atomic_cxchgweak_failrelaxed,
+ BuiltinProc_atomic_cxchgweak_failacq,
+ BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
+ BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
+
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -111,6 +184,80 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("clamp"), 3, false, Expr_Expr},
{STR_LIT(""), 0, true, Expr_Expr}, // DIRECTIVE
+
+
+ // "Intrinsics"
+ {STR_LIT("__atomic_fence"), 0, false, Expr_Stmt},
+ {STR_LIT("__atomic_fence_acq"), 0, false, Expr_Stmt},
+ {STR_LIT("__atomic_fence_rel"), 0, false, Expr_Stmt},
+ {STR_LIT("__atomic_fence_acqrel"), 0, false, Expr_Stmt},
+
+ {STR_LIT("__atomic_store"), 2, false, Expr_Stmt},
+ {STR_LIT("__atomic_store_rel"), 2, false, Expr_Stmt},
+ {STR_LIT("__atomic_store_relaxed"), 2, false, Expr_Stmt},
+ {STR_LIT("__atomic_store_unordered"), 2, false, Expr_Stmt},
+
+ {STR_LIT("__atomic_load"), 1, false, Expr_Expr},
+ {STR_LIT("__atomic_load_acq"), 1, false, Expr_Expr},
+ {STR_LIT("__atomic_load_relaxed"), 1, false, Expr_Expr},
+ {STR_LIT("__atomic_load_unordered"), 1, false, Expr_Expr},
+
+ {STR_LIT("__atomic_add"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_add_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_add_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_add_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_add_relaxed"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_sub"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_sub_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_sub_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_sub_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_sub_relaxed"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_and"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_and_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_and_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_and_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_and_relaxed"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_nand"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_nand_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_nand_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_nand_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_nand_relaxed"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_or"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_or_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_or_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_or_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_or_relaxed"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xor"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xor_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xor_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xor_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xor_relaxed"), 2, false, Expr_Expr},
+
+ {STR_LIT("__atomic_xchg"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xchg_acq"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xchg_rel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xchg_acqrel"), 2, false, Expr_Expr},
+ {STR_LIT("__atomic_xchg_relaxed"), 2, false, Expr_Expr},
+
+ {STR_LIT("__atomic_cxchg"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_acq"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_rel"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_acqrel"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_relaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_failrelaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_failacq"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr},
+
+ {STR_LIT("__atomic_cxchgweak"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_acq"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_rel"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_acqrel"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_relaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_failacq"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr},
+ {STR_LIT("__atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr},
};
@@ -250,7 +397,7 @@ struct ImportGraphNode {
struct ForeignContext {
- Ast * curr_library;
+ Ast * curr_library;
ProcCallingConvention default_cc;
String link_prefix;
bool in_export;
diff --git a/src/entity.cpp b/src/entity.cpp
index 2dd4a4be0..15a70f0a5 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -122,13 +122,13 @@ struct Entity {
String ir_mangled_name;
} TypeName;
struct {
- u64 tags;
- Entity * foreign_library;
- Ast * foreign_library_ident;
- String link_name;
- String link_prefix;
- bool is_foreign;
- bool is_export;
+ u64 tags;
+ Entity *foreign_library;
+ Ast * foreign_library_ident;
+ String link_name;
+ String link_prefix;
+ bool is_foreign;
+ bool is_export;
} Procedure;
struct {
Array<Entity *> entities;
diff --git a/src/ir.cpp b/src/ir.cpp
index 29cc9247c..9189d63c3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -184,10 +184,27 @@ gbAllocator ir_allocator(void) {
i64 alignment; \
}) \
IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \
- IR_INSTR_KIND(Store, struct { \
- irValue *address, *value; bool atomic; \
- }) \
+ IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \
IR_INSTR_KIND(Load, struct { Type *type; irValue *address; }) \
+ IR_INSTR_KIND(AtomicFence, struct { BuiltinProcId id; }) \
+ IR_INSTR_KIND(AtomicStore, struct { \
+ irValue *address, *value; \
+ BuiltinProcId id; \
+ }) \
+ IR_INSTR_KIND(AtomicLoad, struct { \
+ Type *type; irValue *address; \
+ BuiltinProcId id; \
+ }) \
+ IR_INSTR_KIND(AtomicRmw, struct { \
+ Type *type; irValue *address; \
+ irValue *value; \
+ BuiltinProcId id; \
+ }) \
+ IR_INSTR_KIND(AtomicCxchg, struct { \
+ Type *type; irValue *address; \
+ irValue *old_value; irValue *new_value; \
+ BuiltinProcId id; \
+ }) \
IR_INSTR_KIND(PtrOffset, struct { \
irValue *address; \
irValue *offset; \
@@ -485,7 +502,7 @@ irAddr ir_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_re
}
-irAddr ir_addr_context(irValue *addr, Selection sel = {}) {
+irAddr ir_addr_context(irValue *addr, Selection sel = empty_selection) {
irAddr v = {irAddr_Context, addr};
v.ctx.sel = sel;
return v;
@@ -644,6 +661,12 @@ Type *ir_instr_type(irInstr *instr) {
return instr->Local.type;
case irInstr_Load:
return instr->Load.type;
+ case irInstr_AtomicLoad:
+ return instr->AtomicLoad.type;
+ case irInstr_AtomicRmw:
+ return instr->AtomicRmw.type;
+ case irInstr_AtomicCxchg:
+ return instr->AtomicCxchg.type;
case irInstr_StructElementPtr:
return instr->StructElementPtr.result_type;
case irInstr_ArrayElementPtr:
@@ -925,12 +948,11 @@ irValue *ir_instr_zero_init(irProcedure *p, irValue *address) {
return v;
}
-irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value, bool atomic) {
+irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value) {
irValue *v = ir_alloc_instr(p, irInstr_Store);
irInstr *i = &v->Instr;
i->Store.address = address;
i->Store.value = value;
- i->Store.atomic = atomic;
return v;
}
@@ -942,6 +964,68 @@ irValue *ir_instr_load(irProcedure *p, irValue *address) {
return v;
}
+irValue *ir_instr_atomic_fence(irProcedure *p, BuiltinProcId id) {
+ irValue *v = ir_alloc_instr(p, irInstr_AtomicFence);
+ irInstr *i = &v->Instr;
+ i->AtomicFence.id = id;
+ return v;
+}
+
+irValue *ir_instr_atomic_store(irProcedure *p, irValue *address, irValue *value, BuiltinProcId id) {
+ irValue *v = ir_alloc_instr(p, irInstr_AtomicStore);
+ irInstr *i = &v->Instr;
+ i->AtomicStore.address = address;
+ i->AtomicStore.value = value;
+ i->AtomicStore.id = id;
+ return v;
+}
+
+irValue *ir_instr_atomic_load(irProcedure *p, irValue *address, BuiltinProcId id) {
+ irValue *v = ir_alloc_instr(p, irInstr_AtomicLoad);
+ irInstr *i = &v->Instr;
+ i->AtomicLoad.address = address;
+ i->AtomicLoad.type = type_deref(ir_type(address));
+ i->AtomicLoad.id = id;
+ return v;
+}
+
+irValue *ir_instr_atomic_rmw(irProcedure *p, irValue *address, irValue *value, BuiltinProcId id) {
+ irValue *v = ir_alloc_instr(p, irInstr_AtomicRmw);
+ irInstr *i = &v->Instr;
+ i->AtomicRmw.type = type_deref(ir_type(address));
+ i->AtomicRmw.address = address;
+ i->AtomicRmw.value = value;
+ i->AtomicRmw.id = id;
+ return v;
+}
+
+
+irValue *ir_instr_atomic_cxchg(irProcedure *p, Type *type, irValue *address, irValue *old_value, irValue *new_value, BuiltinProcId id) {
+ irValue *v = ir_alloc_instr(p, irInstr_AtomicCxchg);
+ irInstr *i = &v->Instr;
+
+
+ if (type->kind == Type_Tuple) {
+ GB_ASSERT(type->Tuple.variables.count == 2);
+ Type *elem = type->Tuple.variables[0]->type;
+ // LEAK TODO(bill): LLVM returns {T, i1} whilst Odin does {T, bool}, fix this mapping hack
+ gbAllocator a = heap_allocator();
+ Type *llvm_type = alloc_type_tuple();
+ array_init(&llvm_type->Tuple.variables, a, 0, 2);
+ array_add (&llvm_type->Tuple.variables, alloc_entity_field(nullptr, blank_token, elem, false, 0));
+ array_add (&llvm_type->Tuple.variables, alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1));
+
+ type = llvm_type;
+ }
+ i->AtomicCxchg.type = type;
+
+ i->AtomicCxchg.address = address;
+ i->AtomicCxchg.old_value = old_value;
+ i->AtomicCxchg.new_value = new_value;
+ i->AtomicCxchg.id = id;
+ return v;
+}
+
irValue *ir_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *elem_index) {
irValue *v = ir_alloc_instr(p, irInstr_ArrayElementPtr);
irInstr *i = &v->Instr;
@@ -1579,7 +1663,7 @@ irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
if (!is_type_untyped(b)) {
GB_ASSERT_MSG(are_types_identical(core_type(a), core_type(b)), "%s %s", type_to_string(a), type_to_string(b));
}
- return ir_emit(p, ir_instr_store(p, address, value, false));
+ return ir_emit(p, ir_instr_store(p, address, value));
}
irValue *ir_emit_load(irProcedure *p, irValue *address) {
GB_ASSERT(address != nullptr);
@@ -4710,6 +4794,106 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
ir_build_expr(proc, ce->args[0]),
ir_build_expr(proc, ce->args[1]),
ir_build_expr(proc, ce->args[2]));
+
+
+
+ // "Intrinsics"
+ case BuiltinProc_atomic_fence:
+ case BuiltinProc_atomic_fence_acq:
+ case BuiltinProc_atomic_fence_rel:
+ case BuiltinProc_atomic_fence_acqrel:
+ return ir_emit(proc, ir_instr_atomic_fence(proc, id));
+
+ case BuiltinProc_atomic_store:
+ case BuiltinProc_atomic_store_rel:
+ case BuiltinProc_atomic_store_relaxed:
+ case BuiltinProc_atomic_store_unordered: {
+ irValue *dst = ir_build_expr(proc, ce->args[0]);
+ irValue *val = ir_build_expr(proc, ce->args[1]);
+ val = ir_emit_conv(proc, val, type_deref(ir_type(dst)));
+ return ir_emit(proc, ir_instr_atomic_store(proc, dst, val, id));
+ }
+
+ case BuiltinProc_atomic_load:
+ case BuiltinProc_atomic_load_acq:
+ case BuiltinProc_atomic_load_relaxed:
+ case BuiltinProc_atomic_load_unordered: {
+ irValue *dst = ir_build_expr(proc, ce->args[0]);
+ return ir_emit(proc, ir_instr_atomic_load(proc, dst, id));
+ }
+
+ case BuiltinProc_atomic_add:
+ case BuiltinProc_atomic_add_acq:
+ case BuiltinProc_atomic_add_rel:
+ case BuiltinProc_atomic_add_acqrel:
+ case BuiltinProc_atomic_add_relaxed:
+ case BuiltinProc_atomic_sub:
+ case BuiltinProc_atomic_sub_acq:
+ case BuiltinProc_atomic_sub_rel:
+ case BuiltinProc_atomic_sub_acqrel:
+ case BuiltinProc_atomic_sub_relaxed:
+ case BuiltinProc_atomic_and:
+ case BuiltinProc_atomic_and_acq:
+ case BuiltinProc_atomic_and_rel:
+ case BuiltinProc_atomic_and_acqrel:
+ case BuiltinProc_atomic_and_relaxed:
+ case BuiltinProc_atomic_nand:
+ case BuiltinProc_atomic_nand_acq:
+ case BuiltinProc_atomic_nand_rel:
+ case BuiltinProc_atomic_nand_acqrel:
+ case BuiltinProc_atomic_nand_relaxed:
+ case BuiltinProc_atomic_or:
+ case BuiltinProc_atomic_or_acq:
+ case BuiltinProc_atomic_or_rel:
+ case BuiltinProc_atomic_or_acqrel:
+ case BuiltinProc_atomic_or_relaxed:
+ case BuiltinProc_atomic_xor:
+ case BuiltinProc_atomic_xor_acq:
+ case BuiltinProc_atomic_xor_rel:
+ case BuiltinProc_atomic_xor_acqrel:
+ case BuiltinProc_atomic_xor_relaxed:
+ case BuiltinProc_atomic_xchg:
+ case BuiltinProc_atomic_xchg_acq:
+ case BuiltinProc_atomic_xchg_rel:
+ case BuiltinProc_atomic_xchg_acqrel:
+ case BuiltinProc_atomic_xchg_relaxed: {
+ irValue *dst = ir_build_expr(proc, ce->args[0]);
+ irValue *val = ir_build_expr(proc, ce->args[1]);
+ val = ir_emit_conv(proc, val, type_deref(ir_type(dst)));
+ return ir_emit(proc, ir_instr_atomic_rmw(proc, dst, val, id));
+ }
+
+ case BuiltinProc_atomic_cxchg:
+ case BuiltinProc_atomic_cxchg_acq:
+ case BuiltinProc_atomic_cxchg_rel:
+ case BuiltinProc_atomic_cxchg_acqrel:
+ case BuiltinProc_atomic_cxchg_relaxed:
+ case BuiltinProc_atomic_cxchg_failrelaxed:
+ case BuiltinProc_atomic_cxchg_failacq:
+ case BuiltinProc_atomic_cxchg_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchg_acqrel_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak:
+ case BuiltinProc_atomic_cxchgweak_acq:
+ case BuiltinProc_atomic_cxchgweak_rel:
+ case BuiltinProc_atomic_cxchgweak_acqrel:
+ case BuiltinProc_atomic_cxchgweak_relaxed:
+ case BuiltinProc_atomic_cxchgweak_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_failacq:
+ case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: {
+ Type *type = expr->tav.type;
+
+ irValue *address = ir_build_expr(proc, ce->args[0]);
+ Type *elem = type_deref(ir_type(address));
+ irValue *old_value = ir_build_expr(proc, ce->args[1]);
+ irValue *new_value = ir_build_expr(proc, ce->args[2]);
+ old_value = ir_emit_conv(proc, old_value, elem);
+ new_value = ir_emit_conv(proc, new_value, elem);
+
+ return ir_emit(proc, ir_instr_atomic_cxchg(proc, type, address, old_value, new_value, id));
+ }
+
+
}
GB_PANIC("Unhandled built-in procedure");
@@ -8430,6 +8614,9 @@ void ir_gen_tree(irGen *s) {
continue;
case Entity_ProcGroup:
continue;
+
+ case Entity_Procedure:
+ break;
}
bool polymorphic_struct = false;
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 5796845fb..aec43b276 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1040,6 +1040,275 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_debug_location(f, m, value);
break;
}
+
+ case irInstr_AtomicFence:
+ ir_write_str_lit(f, "fence ");
+ switch (instr->AtomicFence.id) {
+ case BuiltinProc_atomic_fence: ir_write_str_lit(f, "seq_cst"); break;
+ case BuiltinProc_atomic_fence_acq: ir_write_str_lit(f, "acquire"); break;
+ case BuiltinProc_atomic_fence_rel: ir_write_str_lit(f, "release"); break;
+ case BuiltinProc_atomic_fence_acqrel: ir_write_str_lit(f, "acq_rel"); break;
+ default: GB_PANIC("Unknown atomic fence"); break;
+ }
+ break;
+
+ case irInstr_AtomicStore: {
+ Type *type = type_deref(ir_type(instr->AtomicStore.address));
+ ir_write_str_lit(f, "store atomic ");
+ ir_print_type(f, m, type);
+ ir_write_byte(f, ' ');
+ ir_print_value(f, m, instr->AtomicStore.value, type);
+ ir_write_str_lit(f, ", ");
+ ir_print_type(f, m, type);
+ ir_write_str_lit(f, "* ");
+ ir_print_value(f, m, instr->AtomicStore.address, type);
+
+ switch (instr->AtomicStore.id) {
+ case BuiltinProc_atomic_store: ir_write_str_lit(f, " seq_cst "); break;
+ case BuiltinProc_atomic_store_rel: ir_write_str_lit(f, " release"); break;
+ case BuiltinProc_atomic_store_relaxed: ir_write_str_lit(f, " monotonic"); break;
+ case BuiltinProc_atomic_store_unordered: ir_write_str_lit(f, " unordered"); break;
+ default: GB_PANIC("Unknown atomic store"); break;
+ }
+
+ ir_fprintf(f, ", align %lld", type_align_of(type));
+
+ ir_print_debug_location(f, m, value);
+ break;
+ }
+
+ case irInstr_AtomicLoad: {
+ Type *type = instr->AtomicLoad.type;
+ ir_fprintf(f, "%%%d = load atomic ", value->index);
+ ir_print_type(f, m, type);
+ ir_write_str_lit(f, ", ");
+ ir_print_type(f, m, type);
+ ir_write_str_lit(f, "* ");
+ ir_print_value(f, m, instr->AtomicLoad.address, type);
+
+ switch (instr->AtomicLoad.id) {
+ case BuiltinProc_atomic_load: ir_fprintf(f, " seq_cst"); break;
+ case BuiltinProc_atomic_load_acq: ir_fprintf(f, " acquire"); break;
+ case BuiltinProc_atomic_load_relaxed: ir_fprintf(f, " monotonic"); break;
+ case BuiltinProc_atomic_load_unordered: ir_fprintf(f, " unordered"); break;
+ default: GB_PANIC("Unknown atomic load"); break;
+ }
+
+ ir_fprintf(f, ", align %lld", type_align_of(type));
+ ir_print_debug_location(f, m, value);
+ break;
+ }
+
+ case irInstr_AtomicRmw: {
+ String operation = {};
+ String ordering = {};
+ switch (instr->AtomicRmw.id) {
+ case BuiltinProc_atomic_add:
+ case BuiltinProc_atomic_add_acq:
+ case BuiltinProc_atomic_add_rel:
+ case BuiltinProc_atomic_add_acqrel:
+ case BuiltinProc_atomic_add_relaxed:
+ operation = str_lit("add");
+ break;
+ case BuiltinProc_atomic_sub:
+ case BuiltinProc_atomic_sub_acq:
+ case BuiltinProc_atomic_sub_rel:
+ case BuiltinProc_atomic_sub_acqrel:
+ case BuiltinProc_atomic_sub_relaxed:
+ operation = str_lit("sub");
+ break;
+ case BuiltinProc_atomic_and:
+ case BuiltinProc_atomic_and_acq:
+ case BuiltinProc_atomic_and_rel:
+ case BuiltinProc_atomic_and_acqrel:
+ case BuiltinProc_atomic_and_relaxed:
+ operation = str_lit("and");
+ break;
+ case BuiltinProc_atomic_nand:
+ case BuiltinProc_atomic_nand_acq:
+ case BuiltinProc_atomic_nand_rel:
+ case BuiltinProc_atomic_nand_acqrel:
+ case BuiltinProc_atomic_nand_relaxed:
+ operation = str_lit("nand");
+ break;
+ case BuiltinProc_atomic_or:
+ case BuiltinProc_atomic_or_acq:
+ case BuiltinProc_atomic_or_rel:
+ case BuiltinProc_atomic_or_acqrel:
+ case BuiltinProc_atomic_or_relaxed:
+ operation = str_lit("or");
+ break;
+ case BuiltinProc_atomic_xor:
+ case BuiltinProc_atomic_xor_acq:
+ case BuiltinProc_atomic_xor_rel:
+ case BuiltinProc_atomic_xor_acqrel:
+ case BuiltinProc_atomic_xor_relaxed:
+ operation = str_lit("xor");
+ break;
+ case BuiltinProc_atomic_xchg:
+ case BuiltinProc_atomic_xchg_acq:
+ case BuiltinProc_atomic_xchg_rel:
+ case BuiltinProc_atomic_xchg_acqrel:
+ case BuiltinProc_atomic_xchg_relaxed:
+ operation = str_lit("xchg");
+ break;
+ }
+
+ switch (instr->AtomicRmw.id) {
+ case BuiltinProc_atomic_add:
+ case BuiltinProc_atomic_sub:
+ case BuiltinProc_atomic_and:
+ case BuiltinProc_atomic_nand:
+ case BuiltinProc_atomic_or:
+ case BuiltinProc_atomic_xor:
+ case BuiltinProc_atomic_xchg:
+ ordering = str_lit("seq_cst");
+ break;
+ case BuiltinProc_atomic_add_acq:
+ case BuiltinProc_atomic_sub_acq:
+ case BuiltinProc_atomic_and_acq:
+ case BuiltinProc_atomic_nand_acq:
+ case BuiltinProc_atomic_or_acq:
+ case BuiltinProc_atomic_xor_acq:
+ case BuiltinProc_atomic_xchg_acq:
+ ordering = str_lit("acquire");
+ break;
+ case BuiltinProc_atomic_add_rel:
+ case BuiltinProc_atomic_sub_rel:
+ case BuiltinProc_atomic_and_rel:
+ case BuiltinProc_atomic_nand_rel:
+ case BuiltinProc_atomic_or_rel:
+ case BuiltinProc_atomic_xor_rel:
+ case BuiltinProc_atomic_xchg_rel:
+ ordering = str_lit("release");
+ break;
+ case BuiltinProc_atomic_add_acqrel:
+ case BuiltinProc_atomic_sub_acqrel:
+ case BuiltinProc_atomic_and_acqrel:
+ case BuiltinProc_atomic_nand_acqrel:
+ case BuiltinProc_atomic_or_acqrel:
+ case BuiltinProc_atomic_xor_acqrel:
+ case BuiltinProc_atomic_xchg_acqrel:
+ ordering = str_lit("acq_rel");
+ break;
+ case BuiltinProc_atomic_add_relaxed:
+ case BuiltinProc_atomic_sub_relaxed:
+ case BuiltinProc_atomic_and_relaxed:
+ case BuiltinProc_atomic_nand_relaxed:
+ case BuiltinProc_atomic_or_relaxed:
+ case BuiltinProc_atomic_xor_relaxed:
+ case BuiltinProc_atomic_xchg_relaxed:
+ ordering = str_lit("monotonic");
+ break;
+ }
+
+ Type *type = type_deref(ir_type(instr->AtomicRmw.address));
+ ir_write_str_lit(f, "atomicrmw ");
+ ir_write_string(f, operation);
+ ir_write_byte(f, ' ');
+ ir_print_type(f, m, type);
+ ir_write_str_lit(f, "* ");
+ ir_print_value(f, m, instr->AtomicRmw.address, type);
+ ir_write_str_lit(f, ", ");
+ ir_print_type(f, m, type);
+ ir_write_byte(f, ' ');
+ ir_print_value(f, m, instr->AtomicRmw.value, type);
+
+ ir_write_byte(f, ' ');
+ ir_write_string(f, ordering);
+
+ ir_print_debug_location(f, m, value);
+ break;
+ }
+
+ case irInstr_AtomicCxchg: {
+ Type *type = type_deref(ir_type(instr->AtomicCxchg.address));
+ bool weak = false;
+ String success = {};
+ String failure = {};
+
+ switch (instr->AtomicCxchg.id) {
+ case BuiltinProc_atomic_cxchgweak:
+ case BuiltinProc_atomic_cxchgweak_acq:
+ case BuiltinProc_atomic_cxchgweak_rel:
+ case BuiltinProc_atomic_cxchgweak_acqrel:
+ case BuiltinProc_atomic_cxchgweak_relaxed:
+ case BuiltinProc_atomic_cxchgweak_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_failacq:
+ case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed:
+ weak = true;
+ break;
+ }
+
+ switch (instr->AtomicCxchg.id) {
+ case BuiltinProc_atomic_cxchg:
+ case BuiltinProc_atomic_cxchgweak:
+ success = str_lit("seq_cst");
+ failure = str_lit("seq_cst");
+ break;
+ case BuiltinProc_atomic_cxchg_acq:
+ case BuiltinProc_atomic_cxchgweak_acq:
+ success = str_lit("acquire");
+ failure = str_lit("seq_cst");
+ break;
+ case BuiltinProc_atomic_cxchg_rel:
+ case BuiltinProc_atomic_cxchgweak_rel:
+ success = str_lit("release");
+ failure = str_lit("seq_cst");
+ break;
+ case BuiltinProc_atomic_cxchg_acqrel:
+ case BuiltinProc_atomic_cxchgweak_acqrel:
+ success = str_lit("acq_rel");
+ failure = str_lit("seq_cst");
+ break;
+ case BuiltinProc_atomic_cxchg_relaxed:
+ case BuiltinProc_atomic_cxchgweak_relaxed:
+ success = str_lit("monotonic");
+ failure = str_lit("monotonic");
+ break;
+ case BuiltinProc_atomic_cxchg_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_failrelaxed:
+ success = str_lit("seq_cst");
+ failure = str_lit("monotonic");
+ break;
+ case BuiltinProc_atomic_cxchg_failacq:
+ case BuiltinProc_atomic_cxchgweak_failacq:
+ success = str_lit("seq_cst");
+ failure = str_lit("acquire");
+ break;
+ case BuiltinProc_atomic_cxchg_acq_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_acq_failrelaxed:
+ success = str_lit("acquire");
+ failure = str_lit("monotonic");
+ break;
+ case BuiltinProc_atomic_cxchg_acqrel_failrelaxed:
+ case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed:
+ success = str_lit("acq_rel");
+ failure = str_lit("monotonic");
+ break;
+ }
+
+ ir_fprintf(f, "%%%d = cmpxchg ", value->index);
+ if (weak) {
+ ir_write_str_lit(f, "weak ");
+ }
+ ir_print_type(f, m, type);
+ ir_write_str_lit(f, "* ");
+ ir_print_value(f, m, instr->AtomicCxchg.address, type);
+ ir_write_str_lit(f, ", ");
+ ir_print_type(f, m, type); ir_write_str_lit(f, " ");
+ ir_print_value(f, m, instr->AtomicCxchg.old_value, type);
+ ir_write_str_lit(f, ", ");
+ ir_print_type(f, m, type); ir_write_str_lit(f, " ");
+ ir_print_value(f, m, instr->AtomicCxchg.new_value, type);
+ ir_write_str_lit(f, " ");
+ ir_write_string(f, success);
+ ir_write_str_lit(f, " ");
+ ir_write_string(f, failure);
+ break;
+ }
+
case irInstr_ArrayElementPtr: {
Type *et = ir_type(instr->ArrayElementPtr.address);
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);