Commit dedde0d790

Andrew Kelley <superjoe30@gmail.com>
2016-05-05 03:34:17
add fence builtin function
1 parent c95e497
src/all_types.hpp
@@ -1116,6 +1116,7 @@ enum BuiltinFnId {
     BuiltinFnIdBreakpoint,
     BuiltinFnIdEmbedFile,
     BuiltinFnIdCmpExchange,
+    BuiltinFnIdFence,
 };
 
 struct BuiltinFnEntry {
@@ -1184,7 +1185,7 @@ struct CodeGen {
         TypeTableEntry *entry_os_enum;
         TypeTableEntry *entry_arch_enum;
         TypeTableEntry *entry_environ_enum;
-        TypeTableEntry *entry_mem_order_enum;
+        TypeTableEntry *entry_atomic_order_enum;
     } builtin_types;
 
     ZigTarget zig_target;
src/analyze.cpp
@@ -4417,6 +4417,8 @@ static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import,
 static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
         BlockContext *context, AstNode *node)
 {
+    assert(node->type == NodeTypeFnCallExpr);
+
     AstNode **ptr_arg = &node->data.fn_call_expr.params.at(0);
     AstNode **cmp_arg = &node->data.fn_call_expr.params.at(1);
     AstNode **new_arg = &node->data.fn_call_expr.params.at(2);
@@ -4437,9 +4439,9 @@ static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
     TypeTableEntry *new_type = analyze_expression(g, import, context, child_type, *new_arg);
 
     TypeTableEntry *success_order_type = analyze_expression(g, import, context,
-            g->builtin_types.entry_mem_order_enum, *success_order_arg);
+            g->builtin_types.entry_atomic_order_enum, *success_order_arg);
     TypeTableEntry *failure_order_type = analyze_expression(g, import, context,
-            g->builtin_types.entry_mem_order_enum, *failure_order_arg);
+            g->builtin_types.entry_atomic_order_enum, *failure_order_arg);
 
     if (cmp_type->id == TypeTableEntryIdInvalid ||
         new_type->id == TypeTableEntryIdInvalid ||
@@ -4485,6 +4487,29 @@ static TypeTableEntry *analyze_cmpxchg(CodeGen *g, ImportTableEntry *import,
     return g->builtin_types.entry_bool;
 }
 
+static TypeTableEntry *analyze_fence(CodeGen *g, ImportTableEntry *import,
+        BlockContext *context, AstNode *node)
+{
+    assert(node->type == NodeTypeFnCallExpr);
+
+    AstNode **atomic_order_arg = &node->data.fn_call_expr.params.at(0);
+    TypeTableEntry *atomic_order_type = analyze_expression(g, import, context,
+            g->builtin_types.entry_atomic_order_enum, *atomic_order_arg);
+
+    if (atomic_order_type->id == TypeTableEntryIdInvalid) {
+        return g->builtin_types.entry_invalid;
+    }
+
+    ConstExprValue *atomic_order_val = &get_resolved_expr(*atomic_order_arg)->const_val;
+
+    if (!atomic_order_val->ok) {
+        add_node_error(g, *atomic_order_arg, buf_sprintf("unable to evaluate constant expression"));
+        return g->builtin_types.entry_invalid;
+    }
+
+    return g->builtin_types.entry_void;
+}
+
 static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node)
 {
@@ -4823,6 +4848,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
             return analyze_embed_file(g, import, context, node);
         case BuiltinFnIdCmpExchange:
             return analyze_cmpxchg(g, import, context, node);
+        case BuiltinFnIdFence:
+            return analyze_fence(g, import, context, node);
     }
     zig_unreachable();
 }
src/codegen.cpp
@@ -441,6 +441,20 @@ static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) {
     return LLVMBuildExtractValue(g->builder, result_val, 1, "");
 }
 
+static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) {
+    assert(node->type == NodeTypeFnCallExpr);
+
+    AstNode *atomic_order_arg = node->data.fn_call_expr.params.at(0);
+    ConstExprValue *atomic_order_val = &get_resolved_expr(atomic_order_arg)->const_val;
+
+    assert(atomic_order_val->ok);
+
+    LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering((AtomicOrder)atomic_order_val->data.x_enum.tag);
+
+    LLVMBuildFence(g->builder, atomic_order, false, "");
+    return nullptr;
+}
+
 static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
     assert(node->type == NodeTypeFnCallExpr);
     AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -588,6 +602,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
             return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
         case BuiltinFnIdCmpExchange:
             return gen_cmp_exchange(g, node);
+        case BuiltinFnIdFence:
+            return gen_fence(g, node);
     }
     zig_unreachable();
 }
@@ -4139,7 +4155,7 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
         entry->data.enumeration.tag_type = tag_type_entry;
 
-        g->builtin_types.entry_mem_order_enum = entry;
+        g->builtin_types.entry_atomic_order_enum = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
 }
@@ -4241,7 +4257,7 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdEmbedFile, "embed_file", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
-    //create_builtin_fn_with_arg_count(g, BuiltinFnIdAtomicRmw, "atomicrmw", 1);
+    create_builtin_fn_with_arg_count(g, BuiltinFnIdFence, "fence", 1);
 }
 
 static void init(CodeGen *g, Buf *source_path) {
src/eval.cpp
@@ -687,6 +687,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
             return eval_fn_with_overflow(ef, node, out_val, bignum_add);
         case BuiltinFnIdSubWithOverflow:
             return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
+        case BuiltinFnIdFence:
+            return false;
         case BuiltinFnIdMemcpy:
         case BuiltinFnIdMemset:
         case BuiltinFnIdSizeof:
test/self_hosted.zig
@@ -1449,3 +1449,10 @@ fn cmpxchg() {
     while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
     assert(x == 5678);
 }
+
+#attribute("test")
+fn fence() {
+    var x: i32 = 1234;
+    @fence(AtomicOrder.SeqCst);
+    x = 5678;
+}