Commit ab7fc33c83

Vexu <git@vexu.eu>
2019-12-16 23:24:23
add zig llvm wrapper for atomicrmw
1 parent 8bb1e04
src/codegen.cpp
@@ -5129,21 +5129,21 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
     zig_unreachable();
 }
 
-static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) {
+static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) {
     switch (op) {
-        case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg;
+        case AtomicRmwOp_xchg: return ZigLLVMAtomicRMWBinOpXchg;
         case AtomicRmwOp_add:
-            return is_float ? LLVMAtomicRMWBinOpFAdd: LLVMAtomicRMWBinOpAdd;
+            return is_float ? ZigLLVMAtomicRMWBinOpFAdd : ZigLLVMAtomicRMWBinOpAdd;
         case AtomicRmwOp_sub:
-            return is_float ? LLVMAtomicRMWBinOpFSub: LLVMAtomicRMWBinOpSub;
-        case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd;
-        case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand;
-        case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr;
-        case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor;
+            return is_float ? ZigLLVMAtomicRMWBinOpFSub : ZigLLVMAtomicRMWBinOpSub;
+        case AtomicRmwOp_and: return ZigLLVMAtomicRMWBinOpAnd;
+        case AtomicRmwOp_nand: return ZigLLVMAtomicRMWBinOpNand;
+        case AtomicRmwOp_or: return ZigLLVMAtomicRMWBinOpOr;
+        case AtomicRmwOp_xor: return ZigLLVMAtomicRMWBinOpXor;
         case AtomicRmwOp_max:
-            return is_signed ? LLVMAtomicRMWBinOpMax : LLVMAtomicRMWBinOpUMax;
+            return is_signed ? ZigLLVMAtomicRMWBinOpMax : ZigLLVMAtomicRMWBinOpUMax;
         case AtomicRmwOp_min:
-            return is_signed ? LLVMAtomicRMWBinOpMin : LLVMAtomicRMWBinOpUMin;
+            return is_signed ? ZigLLVMAtomicRMWBinOpMin : ZigLLVMAtomicRMWBinOpUMin;
     }
     zig_unreachable();
 }
@@ -5727,6 +5727,7 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
 static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
         IrInstructionAtomicRmw *instruction)
 {
+    bool is_signed;
     ZigType *operand_type = instruction->operand->value->type;
     bool is_float = operand_type->id == ZigTypeIdFloat;
     if (operand_type->id == ZigTypeIdInt) {
@@ -5734,20 +5735,20 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
     } else {
         is_signed = false;
     }
-    LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed, is_float);
+    enum ZigLLVM_AtomicRMWBinOp op = to_ZigLLVMAtomicRMWBinOp(instruction->resolved_op, is_signed, is_float);
     LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
     LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
     LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
 
     if (get_codegen_ptr_type(operand_type) == nullptr) {
-        return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
+        return ZigLLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
     }
 
     // it's a pointer but we need to treat it as an int
     LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
         LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
     LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, "");
-    LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
+    LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
             g->is_single_threaded);
     return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
 }
src/zig_llvm.cpp
@@ -1096,6 +1096,56 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
     abort();
 }
 
+static AtomicRMWInst::BinOp toLLVMRMWBinOp(enum ZigLLVM_AtomicRMWBinOp BinOp) {
+    switch (BinOp) {
+        default:
+        case ZigLLVMAtomicRMWBinOpXchg: return AtomicRMWInst::Xchg;
+        case ZigLLVMAtomicRMWBinOpAdd: return AtomicRMWInst::Add;
+        case ZigLLVMAtomicRMWBinOpSub: return AtomicRMWInst::Sub;
+        case ZigLLVMAtomicRMWBinOpAnd: return AtomicRMWInst::And;
+        case ZigLLVMAtomicRMWBinOpNand: return AtomicRMWInst::Nand;
+        case ZigLLVMAtomicRMWBinOpOr: return AtomicRMWInst::Or;
+        case ZigLLVMAtomicRMWBinOpXor: return AtomicRMWInst::Xor;
+        case ZigLLVMAtomicRMWBinOpMax: return AtomicRMWInst::Max;
+        case ZigLLVMAtomicRMWBinOpMin: return AtomicRMWInst::Min;
+        case ZigLLVMAtomicRMWBinOpUMax: return AtomicRMWInst::UMax;
+        case ZigLLVMAtomicRMWBinOpUMin: return AtomicRMWInst::UMin;
+        case ZigLLVMAtomicRMWBinOpFAdd: return AtomicRMWInst::FAdd;
+        case ZigLLVMAtomicRMWBinOpFSub: return AtomicRMWInst::FSub;
+    }
+}
+
+static AtomicOrdering toLLVMOrdering(LLVMAtomicOrdering Ordering) {
+    switch (Ordering) {
+        default:
+        case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;
+        case LLVMAtomicOrderingUnordered: return AtomicOrdering::Unordered;
+        case LLVMAtomicOrderingMonotonic: return AtomicOrdering::Monotonic;
+        case LLVMAtomicOrderingAcquire: return AtomicOrdering::Acquire;
+        case LLVMAtomicOrderingRelease: return AtomicOrdering::Release;
+        case LLVMAtomicOrderingAcquireRelease: return AtomicOrdering::AcquireRelease;
+        case LLVMAtomicOrderingSequentiallyConsistent: return AtomicOrdering::SequentiallyConsistent;
+    }
+}
+
+inline LLVMAttributeRef wrap(Attribute Attr) {
+    return reinterpret_cast<LLVMAttributeRef>(Attr.getRawPointer());
+}
+
+inline Attribute unwrap(LLVMAttributeRef Attr) {
+    return Attribute::fromRawPointer(Attr);
+}
+
+LLVMValueRef ZigLLVMBuildAtomicRMW(LLVMBuilderRef B, enum ZigLLVM_AtomicRMWBinOp op,
+    LLVMValueRef PTR, LLVMValueRef Val,
+    LLVMAtomicOrdering ordering, LLVMBool singleThread) 
+{
+    AtomicRMWInst::BinOp intop = toLLVMRMWBinOp(op);
+    return wrap(unwrap(B)->CreateAtomicRMW(intop, unwrap(PTR),
+        unwrap(Val), toLLVMOrdering(ordering), 
+        singleThread ? SyncScope::SingleThread : SyncScope::System));
+}
+
 static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
 static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
 static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
src/zig_llvm.h
@@ -422,6 +422,26 @@ enum ZigLLVM_ObjectFormatType {
     ZigLLVM_XCOFF,
 };
 
+enum ZigLLVM_AtomicRMWBinOp {
+    ZigLLVMAtomicRMWBinOpXchg,
+    ZigLLVMAtomicRMWBinOpAdd,
+    ZigLLVMAtomicRMWBinOpSub,
+    ZigLLVMAtomicRMWBinOpAnd,
+    ZigLLVMAtomicRMWBinOpNand,
+    ZigLLVMAtomicRMWBinOpOr,
+    ZigLLVMAtomicRMWBinOpXor,
+    ZigLLVMAtomicRMWBinOpMax,
+    ZigLLVMAtomicRMWBinOpMin,
+    ZigLLVMAtomicRMWBinOpUMax,
+    ZigLLVMAtomicRMWBinOpUMin,
+    ZigLLVMAtomicRMWBinOpFAdd,
+    ZigLLVMAtomicRMWBinOpFSub,
+};
+
+LLVMValueRef ZigLLVMBuildAtomicRMW(LLVMBuilderRef B, enum ZigLLVM_AtomicRMWBinOp op,
+    LLVMValueRef PTR, LLVMValueRef Val,
+    LLVMAtomicOrdering ordering, LLVMBool singleThread);
+
 #define ZigLLVM_DIFlags_Zero 0U
 #define ZigLLVM_DIFlags_Private 1U
 #define ZigLLVM_DIFlags_Protected 2U
test/compile_errors.zig
@@ -19,9 +19,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    var x: f32 = 0;
         \\    _ = @cmpxchgWeak(f32, &x, 1, 2, .SeqCst, .SeqCst);
         \\}
-    ,
+    , &[_][]const u8{
         "tmp.zig:3:22: error: expected integer, enum or pointer type, found 'f32'",
-    );
+    });
 
     cases.add(
         "atomicrmw with float op not .Xchg, .Add or .Sub",
@@ -29,9 +29,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    var x: f32 = 0;
         \\    _ = @atomicRmw(f32, &x, .And, 2, .SeqCst);
         \\}
-    ,
+    , &[_][]const u8{
         "tmp.zig:3:29: error: @atomicRmw with float only works with .Xchg, .Add and .Sub",
-    );
+    });
 
     cases.add("intToPtr with misaligned address",
         \\pub fn main() void {