Skip to content

Commit

Permalink
add zig llvm wrapper for atomicrmw
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Dec 16, 2019
1 parent b01256e commit 6133479
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 17 deletions.
27 changes: 14 additions & 13 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5106,21 +5106,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();
}
Expand Down Expand Up @@ -5682,27 +5682,28 @@ 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) {
is_signed = operand_type->data.integral.is_signed;
} 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), "");
}
Expand Down
50 changes: 50 additions & 0 deletions src/zig_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, "");
Expand Down
20 changes: 20 additions & 0 deletions src/zig_llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions test/compile_errors.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ 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",
\\export fn entry() 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 {
Expand Down

0 comments on commit 6133479

Please sign in to comment.