diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-12-30 19:19:05 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-30 19:19:05 -0500 |
| commit | 73e535e1125d76bcd4e85123defea8b76412ab09 (patch) | |
| tree | e347bc78a7ea39a2009b490e3be97074d05f9fcb /src | |
| parent | cbfd66f68a5a390abcf99e8cc6923d056ee1e4fa (diff) | |
| parent | 2252951066f772ac6b77ab183ad3bc074ae8f09f (diff) | |
| download | zig-73e535e1125d76bcd4e85123defea8b76412ab09.tar.gz zig-73e535e1125d76bcd4e85123defea8b76412ab09.zip | |
Merge pull request #3683 from Vexu/atomic-float
Support floats with some atomic operations
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.cpp | 29 | ||||
| -rw-r--r-- | src/ir.cpp | 20 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 50 | ||||
| -rw-r--r-- | src/zig_llvm.h | 20 |
4 files changed, 105 insertions, 14 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 01cda22cd4..320d5c75d5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5132,19 +5132,21 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { zig_unreachable(); } -static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) { +static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed, bool is_float) { switch (op) { - case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg; - case AtomicRmwOp_add: return LLVMAtomicRMWBinOpAdd; - case AtomicRmwOp_sub: return LLVMAtomicRMWBinOpSub; - case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd; - case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand; - case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr; - case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor; + case AtomicRmwOp_xchg: return ZigLLVMAtomicRMWBinOpXchg; + case AtomicRmwOp_add: + return is_float ? ZigLLVMAtomicRMWBinOpFAdd : ZigLLVMAtomicRMWBinOpAdd; + case AtomicRmwOp_sub: + 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(); } @@ -5738,25 +5740,26 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable, { bool is_signed; ZigType *operand_type = instruction->operand->value->type; + bool is_float = operand_type->id == ZigTypeIdFloat; if (operand_type->id == ZigTypeIdInt) { is_signed = operand_type->data.integral.is_signed; } else { is_signed = false; } - LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed); + 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/ir.cpp b/src/ir.cpp index bf5a297a81..7cc1829341 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -23959,6 +23959,12 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi if (type_is_invalid(operand_type)) return ira->codegen->invalid_instruction; + if (operand_type->id == ZigTypeIdFloat) { + ir_add_error(ira, instruction->type_value->child, + buf_sprintf("expected integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); + return ira->codegen->invalid_instruction; + } + IrInstruction *ptr = instruction->ptr->child; if (type_is_invalid(ptr->value->type)) return ira->codegen->invalid_instruction; @@ -27440,9 +27446,17 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count)); return ira->codegen->builtin_types.entry_invalid; } + } else if (operand_type->id == ZigTypeIdFloat) { + uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); + if (operand_type->data.floating.bit_count > max_atomic_bits) { + ir_add_error(ira, op, + buf_sprintf("expected %" PRIu32 "-bit float or smaller, found %" PRIu32 "-bit float", + max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count)); + return ira->codegen->builtin_types.entry_invalid; + } } else if (get_codegen_ptr_type(operand_type) == nullptr) { ir_add_error(ira, op, - buf_sprintf("expected integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); + buf_sprintf("expected integer, float, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -27477,6 +27491,10 @@ static IrInstruction *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstru ir_add_error(ira, instruction->op, buf_sprintf("@atomicRmw on enum only works with .Xchg")); return ira->codegen->invalid_instruction; + } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) { + ir_add_error(ira, instruction->op, + buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub")); + return ira->codegen->invalid_instruction; } IrInstruction *operand = instruction->operand->child; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 852475c3c4..7ecb717047 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<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, ""); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 0fad21a19b..4d8a3fa927 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 |
