diff --git a/src/codegen.cpp b/src/codegen.cpp index cd4b4320f..3da61c5a7 100644 --- a/src/codegen.cpp +++ b/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), ""); } diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 852475c3c..7ecb71704 100644 --- a/src/zig_llvm.cpp +++ b/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(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, ""); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 0fad21a19..4d8a3fa92 100644 --- a/src/zig_llvm.h +++ b/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 diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 38d6355d5..c08476343 100644 --- a/test/compile_errors.zig +++ b/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 {