mirror of
https://github.com/ziglang/zig.git
synced 2026-02-16 06:18:32 +00:00
IR: implement fence and cmpxchg builtins
This commit is contained in:
parent
10cea15cc3
commit
8fcb1a141b
@ -1407,6 +1407,8 @@ enum IrInstructionId {
|
||||
IrInstructionIdCompileErr,
|
||||
IrInstructionIdErrName,
|
||||
IrInstructionIdEmbedFile,
|
||||
IrInstructionIdCmpxchg,
|
||||
IrInstructionIdFence,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -1859,6 +1861,29 @@ struct IrInstructionEmbedFile {
|
||||
IrInstruction *name;
|
||||
};
|
||||
|
||||
struct IrInstructionCmpxchg {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *cmp_value;
|
||||
IrInstruction *new_value;
|
||||
IrInstruction *success_order_value;
|
||||
IrInstruction *failure_order_value;
|
||||
|
||||
// if this instruction gets to runtime then we know these values:
|
||||
AtomicOrder success_order;
|
||||
AtomicOrder failure_order;
|
||||
};
|
||||
|
||||
struct IrInstructionFence {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *order_value;
|
||||
|
||||
// if this instruction gets to runtime then we know these values:
|
||||
AtomicOrder order;
|
||||
};
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeNone,
|
||||
LValPurposeAssign,
|
||||
|
||||
@ -2798,3 +2798,14 @@ ConstExprValue *create_const_float(double value) {
|
||||
init_const_float(const_val, value);
|
||||
return const_val;
|
||||
}
|
||||
|
||||
void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->data.x_enum.tag = tag;
|
||||
}
|
||||
|
||||
ConstExprValue *create_const_enum_tag(uint64_t tag) {
|
||||
ConstExprValue *const_val = allocate<ConstExprValue>(1);
|
||||
init_const_enum_tag(const_val, tag);
|
||||
return const_val;
|
||||
}
|
||||
|
||||
@ -95,4 +95,7 @@ ConstExprValue *create_const_signed(int64_t x);
|
||||
void init_const_float(ConstExprValue *const_val, double value);
|
||||
ConstExprValue *create_const_float(double value);
|
||||
|
||||
void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag);
|
||||
ConstExprValue *create_const_enum_tag(uint64_t tag);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1839,6 +1839,38 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
|
||||
return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
|
||||
}
|
||||
|
||||
static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
|
||||
switch (atomic_order) {
|
||||
case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
|
||||
case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic;
|
||||
case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire;
|
||||
case AtomicOrderRelease: return LLVMAtomicOrderingRelease;
|
||||
case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease;
|
||||
case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
|
||||
LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
|
||||
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
|
||||
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
|
||||
|
||||
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
|
||||
LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
|
||||
|
||||
LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
|
||||
success_order, failure_order);
|
||||
|
||||
return LLVMBuildExtractValue(g->builder, result_val, 1, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
|
||||
LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering(instruction->order);
|
||||
LLVMBuildFence(g->builder, atomic_order, false, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
|
||||
AstNode *source_node = instruction->source_node;
|
||||
Scope *scope = instruction->scope;
|
||||
@ -1928,6 +1960,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
|
||||
case IrInstructionIdErrName:
|
||||
return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
|
||||
case IrInstructionIdCmpxchg:
|
||||
return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
|
||||
case IrInstructionIdFence:
|
||||
return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdStructInit:
|
||||
@ -2989,6 +3025,7 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
entry->zero_bits = true; // only allowed at compile time
|
||||
buf_init_from_str(&entry->name, "AtomicOrder");
|
||||
uint32_t field_count = 6;
|
||||
entry->data.enumeration.src_field_count = field_count;
|
||||
|
||||
555
src/ir.cpp
555
src/ir.cpp
@ -347,6 +347,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
|
||||
return IrInstructionIdEmbedFile;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
|
||||
return IrInstructionIdCmpxchg;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
|
||||
return IrInstructionIdFence;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -1357,6 +1365,54 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
|
||||
IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
|
||||
AtomicOrder success_order, AtomicOrder failure_order)
|
||||
{
|
||||
IrInstructionCmpxchg *instruction = ir_build_instruction<IrInstructionCmpxchg>(irb, scope, source_node);
|
||||
instruction->ptr = ptr;
|
||||
instruction->cmp_value = cmp_value;
|
||||
instruction->new_value = new_value;
|
||||
instruction->success_order_value = success_order_value;
|
||||
instruction->failure_order_value = failure_order_value;
|
||||
instruction->success_order = success_order;
|
||||
instruction->failure_order = failure_order;
|
||||
|
||||
ir_ref_instruction(ptr);
|
||||
ir_ref_instruction(cmp_value);
|
||||
ir_ref_instruction(new_value);
|
||||
ir_ref_instruction(success_order_value);
|
||||
ir_ref_instruction(failure_order_value);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_cmpxchg_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr,
|
||||
IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value,
|
||||
AtomicOrder success_order, AtomicOrder failure_order)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_cmpxchg(irb, old_instruction->scope, old_instruction->source_node,
|
||||
ptr, cmp_value, new_value, success_order_value, failure_order_value, success_order, failure_order);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_fence(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *order_value, AtomicOrder order) {
|
||||
IrInstructionFence *instruction = ir_build_instruction<IrInstructionFence>(irb, scope, source_node);
|
||||
instruction->order_value = order_value;
|
||||
instruction->order = order;
|
||||
|
||||
ir_ref_instruction(order_value);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_fence_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *order_value, AtomicOrder order) {
|
||||
IrInstruction *new_instruction = ir_build_fence(irb, old_instruction->scope, old_instruction->source_node, order_value, order);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
|
||||
bool gen_error_defers, bool gen_maybe_defers)
|
||||
{
|
||||
@ -2096,6 +2152,46 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
|
||||
return ir_build_embed_file(irb, scope, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdCmpExchange:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
|
||||
IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
|
||||
if (arg2_value == irb->codegen->invalid_instruction)
|
||||
return arg2_value;
|
||||
|
||||
AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
|
||||
IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
|
||||
if (arg3_value == irb->codegen->invalid_instruction)
|
||||
return arg3_value;
|
||||
|
||||
AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
|
||||
IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
|
||||
if (arg4_value == irb->codegen->invalid_instruction)
|
||||
return arg4_value;
|
||||
|
||||
return ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
|
||||
arg2_value, arg3_value, arg4_value,
|
||||
AtomicOrderUnordered, AtomicOrderUnordered);
|
||||
}
|
||||
case BuiltinFnIdFence:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
return ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
|
||||
}
|
||||
case BuiltinFnIdMemcpy:
|
||||
case BuiltinFnIdMemset:
|
||||
case BuiltinFnIdAlignof:
|
||||
@ -2107,8 +2203,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
case BuiltinFnIdBreakpoint:
|
||||
case BuiltinFnIdReturnAddress:
|
||||
case BuiltinFnIdFrameAddress:
|
||||
case BuiltinFnIdCmpExchange:
|
||||
case BuiltinFnIdFence:
|
||||
case BuiltinFnIdDivExact:
|
||||
case BuiltinFnIdTruncate:
|
||||
case BuiltinFnIdIntType:
|
||||
@ -3470,6 +3564,12 @@ static bool is_slice(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
|
||||
}
|
||||
|
||||
static bool is_container(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdStruct ||
|
||||
type->id == TypeTableEntryIdEnum ||
|
||||
type->id == TypeTableEntryIdUnion;
|
||||
}
|
||||
|
||||
static bool is_u8(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdInt &&
|
||||
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
|
||||
@ -4085,6 +4185,22 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_atomic_order_enum);
|
||||
if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (AtomicOrder)const_val->data.x_enum.tag;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return nullptr;
|
||||
@ -5689,15 +5805,23 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
if (container_ptr->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *container_type = container_ptr->type_entry->data.pointer.child_type;
|
||||
TypeTableEntry *container_type;
|
||||
if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
|
||||
container_type = container_ptr->type_entry->data.pointer.child_type;
|
||||
} else if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
|
||||
container_type = container_ptr->type_entry;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
|
||||
Buf *field_name = field_ptr_instruction->field_name;
|
||||
AstNode *source_node = field_ptr_instruction->base.source_node;
|
||||
|
||||
if (container_type->id == TypeTableEntryIdInvalid) {
|
||||
return container_type;
|
||||
} else if (is_container_ref(container_type)) {
|
||||
assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
|
||||
return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_ptr, container_type);
|
||||
} else if (container_type->id == TypeTableEntryIdArray) {
|
||||
if (buf_eql_str(field_name, "len")) {
|
||||
@ -5717,26 +5841,43 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
|
||||
if (!container_ptr_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
|
||||
TypeTableEntry *child_type = child_val->data.x_type;
|
||||
|
||||
TypeTableEntry *child_type;
|
||||
if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
|
||||
TypeTableEntry *ptr_type = container_ptr_val->data.x_type;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
child_type = ptr_type->data.pointer.child_type;
|
||||
} else if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
|
||||
ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
|
||||
child_type = child_val->data.x_type;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
if (child_type->id == TypeTableEntryIdInvalid) {
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (child_type->id == TypeTableEntryIdEnum) {
|
||||
zig_panic("TODO enum type field");
|
||||
} else if (child_type->id == TypeTableEntryIdStruct) {
|
||||
} else if (is_container(child_type)) {
|
||||
if (child_type->id == TypeTableEntryIdEnum) {
|
||||
TypeEnumField *field = find_enum_type_field(child_type, field_name);
|
||||
if (field) {
|
||||
if (field->type_entry->id == TypeTableEntryIdVoid) {
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_enum_tag(field->value),
|
||||
child_type, depends_on_compile_var, ConstPtrSpecialNone);
|
||||
} else {
|
||||
zig_panic("TODO enum tag type");
|
||||
}
|
||||
}
|
||||
}
|
||||
ScopeDecls *container_scope = get_container_scope(child_type);
|
||||
auto entry = container_scope->decl_table.maybe_get(field_name);
|
||||
Tld *tld = entry ? entry->value : nullptr;
|
||||
if (tld) {
|
||||
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
|
||||
return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, tld, depends_on_compile_var);
|
||||
} else {
|
||||
add_node_error(ira->codegen, source_node,
|
||||
buf_sprintf("container '%s' has no member called '%s'",
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("container '%s' has no member called '%s'",
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (child_type->id == TypeTableEntryIdPureError) {
|
||||
auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);
|
||||
if (err_table_entry) {
|
||||
@ -5744,7 +5885,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->data.x_pure_err = err_table_entry->value;
|
||||
|
||||
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
|
||||
child_type, depends_on_compile_var, ConstPtrSpecialNone);
|
||||
}
|
||||
@ -5760,6 +5900,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (container_type->id == TypeTableEntryIdNamespace) {
|
||||
assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
|
||||
ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
|
||||
if (!container_ptr_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@ -5769,7 +5910,6 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
|
||||
ImportTableEntry *namespace_import = namespace_val->data.x_import;
|
||||
|
||||
bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
|
||||
Tld *tld = find_decl(&namespace_import->decls_scope->base, field_name);
|
||||
if (!tld) {
|
||||
// we must now resolve all the use decls
|
||||
@ -7184,10 +7324,10 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(&file_path, &file_contents))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
|
||||
ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
|
||||
ir_add_error(ira, instruction->name, buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
@ -7197,11 +7337,94 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
|
||||
|
||||
bool depends_on_compile_var = true;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
|
||||
init_const_str_lit(out_val,&file_contents);
|
||||
init_const_str_lit(out_val, &file_contents);
|
||||
|
||||
return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents));
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
|
||||
IrInstruction *ptr = instruction->ptr->other;
|
||||
if (ptr->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *cmp_value = instruction->cmp_value->other;
|
||||
if (cmp_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *new_value = instruction->new_value->other;
|
||||
if (new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *success_order_value = instruction->success_order_value->other;
|
||||
if (success_order_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
AtomicOrder success_order;
|
||||
if (!ir_resolve_atomic_order(ira, success_order_value, &success_order))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *failure_order_value = instruction->failure_order_value->other;
|
||||
if (failure_order_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
AtomicOrder failure_order;
|
||||
if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (ptr->type_entry->id != TypeTableEntryIdPointer) {
|
||||
ir_add_error(ira, instruction->ptr,
|
||||
buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->type_entry->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type;
|
||||
|
||||
IrInstruction *casted_cmp_value = ir_get_casted_value(ira, cmp_value, child_type);
|
||||
if (casted_cmp_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *casted_new_value = ir_get_casted_value(ira, new_value, child_type);
|
||||
if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (success_order < AtomicOrderMonotonic) {
|
||||
ir_add_error(ira, success_order_value,
|
||||
buf_sprintf("success atomic ordering must be Monotonic or stricter"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (failure_order < AtomicOrderMonotonic) {
|
||||
ir_add_error(ira, failure_order_value,
|
||||
buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (failure_order > success_order) {
|
||||
ir_add_error(ira, failure_order_value,
|
||||
buf_sprintf("failure atomic ordering must be no stricter than success"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (failure_order == AtomicOrderRelease || failure_order == AtomicOrderAcqRel) {
|
||||
ir_add_error(ira, failure_order_value,
|
||||
buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ir_build_cmpxchg_from(&ira->new_irb, &instruction->base, ptr, casted_cmp_value, casted_new_value,
|
||||
success_order_value, failure_order_value, success_order, failure_order);
|
||||
return ira->codegen->builtin_types.entry_bool;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
|
||||
IrInstruction *order_value = instruction->order_value->other;
|
||||
if (order_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
AtomicOrder order;
|
||||
if (!ir_resolve_atomic_order(ira, order_value, &order))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ir_build_fence_from(&ira->new_irb, &instruction->base, order_value, order);
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
@ -7305,6 +7528,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
|
||||
case IrInstructionIdEmbedFile:
|
||||
return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
|
||||
case IrInstructionIdCmpxchg:
|
||||
return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
|
||||
case IrInstructionIdFence:
|
||||
return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
|
||||
case IrInstructionIdCast:
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
@ -7404,6 +7631,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdCInclude:
|
||||
case IrInstructionIdCDefine:
|
||||
case IrInstructionIdCUndef:
|
||||
case IrInstructionIdCmpxchg:
|
||||
case IrInstructionIdFence:
|
||||
return true;
|
||||
case IrInstructionIdPhi:
|
||||
case IrInstructionIdUnOp:
|
||||
@ -7453,102 +7682,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// TODO port over all this commented out code into new IR way of doing things
|
||||
|
||||
|
||||
//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);
|
||||
// AstNode **success_order_arg = &node->data.fn_call_expr.params.at(3);
|
||||
// AstNode **failure_order_arg = &node->data.fn_call_expr.params.at(4);
|
||||
//
|
||||
// TypeTableEntry *ptr_type = analyze_expression(g, import, context, nullptr, *ptr_arg);
|
||||
// if (ptr_type->id == TypeTableEntryIdInvalid) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// } else if (ptr_type->id != TypeTableEntryIdPointer) {
|
||||
// add_node_error(g, *ptr_arg,
|
||||
// buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr_type->name)));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
|
||||
// TypeTableEntry *cmp_type = analyze_expression(g, import, context, child_type, *cmp_arg);
|
||||
// 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_atomic_order_enum, *success_order_arg);
|
||||
// TypeTableEntry *failure_order_type = analyze_expression(g, import, context,
|
||||
// g->builtin_types.entry_atomic_order_enum, *failure_order_arg);
|
||||
//
|
||||
// if (cmp_type->id == TypeTableEntryIdInvalid ||
|
||||
// new_type->id == TypeTableEntryIdInvalid ||
|
||||
// success_order_type->id == TypeTableEntryIdInvalid ||
|
||||
// failure_order_type->id == TypeTableEntryIdInvalid)
|
||||
// {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// ConstExprValue *success_order_val = &get_resolved_expr(*success_order_arg)->const_val;
|
||||
// ConstExprValue *failure_order_val = &get_resolved_expr(*failure_order_arg)->const_val;
|
||||
// if (!success_order_val->ok) {
|
||||
// add_node_error(g, *success_order_arg, buf_sprintf("unable to evaluate constant expression"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// } else if (!failure_order_val->ok) {
|
||||
// add_node_error(g, *failure_order_arg, buf_sprintf("unable to evaluate constant expression"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// if (success_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
|
||||
// add_node_error(g, *success_order_arg,
|
||||
// buf_sprintf("success atomic ordering must be Monotonic or stricter"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// if (failure_order_val->data.x_enum.tag < AtomicOrderMonotonic) {
|
||||
// add_node_error(g, *failure_order_arg,
|
||||
// buf_sprintf("failure atomic ordering must be Monotonic or stricter"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// if (failure_order_val->data.x_enum.tag > success_order_val->data.x_enum.tag) {
|
||||
// add_node_error(g, *failure_order_arg,
|
||||
// buf_sprintf("failure atomic ordering must be no stricter than success"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// if (failure_order_val->data.x_enum.tag == AtomicOrderRelease ||
|
||||
// failure_order_val->data.x_enum.tag == AtomicOrderAcqRel)
|
||||
// {
|
||||
// add_node_error(g, *failure_order_arg,
|
||||
// buf_sprintf("failure atomic ordering must not be Release or AcqRel"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// 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_div_exact(CodeGen *g, ImportTableEntry *import,
|
||||
// BlockContext *context, AstNode *node)
|
||||
//{
|
||||
@ -7780,8 +7913,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// }
|
||||
// case BuiltinFnIdImport:
|
||||
// return analyze_import(g, import, context, node);
|
||||
// case BuiltinFnIdBreakpoint:
|
||||
// mark_impure_fn(g, context, node);
|
||||
// return g->builtin_types.entry_void;
|
||||
@ -7789,20 +7920,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// case BuiltinFnIdFrameAddress:
|
||||
// mark_impure_fn(g, context, node);
|
||||
// return builtin_fn->return_type;
|
||||
// case BuiltinFnIdCmpExchange:
|
||||
// return analyze_cmpxchg(g, import, context, node);
|
||||
// case BuiltinFnIdFence:
|
||||
// return analyze_fence(g, import, context, node);
|
||||
// case BuiltinFnIdDivExact:
|
||||
// return analyze_div_exact(g, import, context, node);
|
||||
// case BuiltinFnIdTruncate:
|
||||
// return analyze_truncate(g, import, context, node);
|
||||
// case BuiltinFnIdIntType:
|
||||
// return analyze_int_type(g, import, context, node);
|
||||
// case BuiltinFnIdSetFnTest:
|
||||
// return analyze_set_fn_test(g, import, context, node);
|
||||
// case BuiltinFnIdSetFnNoInline:
|
||||
// return analyze_set_fn_no_inline(g, import, context, node);
|
||||
// }
|
||||
// zig_unreachable();
|
||||
//}
|
||||
@ -7881,68 +8004,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// }
|
||||
// zig_unreachable();
|
||||
//}
|
||||
//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
|
||||
// AstNode *out_node)
|
||||
//{
|
||||
// assert(field_access_node->type == NodeTypeFieldAccessExpr);
|
||||
//
|
||||
// TypeEnumField *type_enum_field = find_enum_type_field(enum_type, field_name);
|
||||
// if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// field_access_node->data.field_access_expr.type_enum_field = type_enum_field;
|
||||
//
|
||||
// if (type_enum_field) {
|
||||
// if (value_node) {
|
||||
// AstNode **value_node_ptr = value_node->parent_field;
|
||||
// TypeTableEntry *value_type = analyze_expression(g, import, context,
|
||||
// type_enum_field->type_entry, value_node);
|
||||
//
|
||||
// if (value_type->id == TypeTableEntryIdInvalid) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr;
|
||||
// codegen->type_entry = enum_type;
|
||||
// codegen->source_node = field_access_node;
|
||||
//
|
||||
// ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val;
|
||||
// if (value_const_val->ok) {
|
||||
// ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val;
|
||||
// const_val->ok = true;
|
||||
// const_val->data.x_enum.tag = type_enum_field->value;
|
||||
// const_val->data.x_enum.payload = value_const_val;
|
||||
// } else {
|
||||
// if (context->fn_entry) {
|
||||
// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
|
||||
// } else {
|
||||
// add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// }
|
||||
// } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) {
|
||||
// add_node_error(g, field_access_node,
|
||||
// buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
|
||||
// buf_ptr(&enum_type->name),
|
||||
// buf_ptr(field_name),
|
||||
// buf_ptr(&type_enum_field->type_entry->name)));
|
||||
// } else {
|
||||
// Expr *expr = get_resolved_expr(out_node);
|
||||
// expr->const_val.ok = true;
|
||||
// expr->const_val.data.x_enum.tag = type_enum_field->value;
|
||||
// expr->const_val.data.x_enum.payload = nullptr;
|
||||
// }
|
||||
// } else {
|
||||
// add_node_error(g, field_access_node,
|
||||
// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
|
||||
// buf_ptr(&enum_type->name)));
|
||||
// }
|
||||
// return enum_type;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
// AstNode *node)
|
||||
//{
|
||||
@ -8182,34 +8243,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
//
|
||||
|
||||
|
||||
//static LLVMValueRef gen_cmp_exchange(CodeGen *g, 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);
|
||||
// AstNode *success_order_arg = node->data.fn_call_expr.params.at(3);
|
||||
// AstNode *failure_order_arg = node->data.fn_call_expr.params.at(4);
|
||||
//
|
||||
// LLVMValueRef ptr_val = gen_expr(g, ptr_arg);
|
||||
// LLVMValueRef cmp_val = gen_expr(g, cmp_arg);
|
||||
// LLVMValueRef new_val = gen_expr(g, new_arg);
|
||||
//
|
||||
// ConstExprValue *success_order_val = &get_resolved_expr(success_order_arg)->const_val;
|
||||
// ConstExprValue *failure_order_val = &get_resolved_expr(failure_order_arg)->const_val;
|
||||
//
|
||||
// assert(success_order_val->ok);
|
||||
// assert(failure_order_val->ok);
|
||||
//
|
||||
// LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering((AtomicOrder)success_order_val->data.x_enum.tag);
|
||||
// LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag);
|
||||
//
|
||||
// LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
|
||||
// success_order, failure_order);
|
||||
//
|
||||
// return LLVMBuildExtractValue(g->builder, result_val, 1, "");
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_div_exact(CodeGen *g, AstNode *node) {
|
||||
// assert(node->type == NodeTypeFnCallExpr);
|
||||
//
|
||||
@ -8269,9 +8302,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// switch (builtin_fn->id) {
|
||||
// case BuiltinFnIdInvalid:
|
||||
// case BuiltinFnIdTypeof:
|
||||
// case BuiltinFnIdImport:
|
||||
// case BuiltinFnIdCImport:
|
||||
// case BuiltinFnIdCompileErr:
|
||||
// case BuiltinFnIdIntType:
|
||||
// zig_unreachable();
|
||||
// case BuiltinFnIdAddWithOverflow:
|
||||
@ -8585,25 +8615,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//
|
||||
//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
|
||||
// assert(node->type == NodeTypeBinOpExpr);
|
||||
//
|
||||
// AstNode *lhs_node = node->data.bin_op_expr.op1;
|
||||
//
|
||||
// TypeTableEntry *op1_type;
|
||||
//
|
||||
// LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type);
|
||||
//
|
||||
// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
|
||||
//
|
||||
// LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
|
||||
//
|
||||
// gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
|
||||
// return nullptr;
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
|
||||
// assert(node->type == NodeTypeUnwrapErrorExpr);
|
||||
//
|
||||
@ -8894,71 +8905,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
// gen_var_debug_decl(g, variable);
|
||||
// return nullptr;
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
|
||||
// assert(node->type == NodeTypeArrayAccessExpr);
|
||||
//
|
||||
// LLVMValueRef ptr = gen_array_ptr(g, node);
|
||||
// TypeTableEntry *child_type;
|
||||
// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr);
|
||||
// if (array_type->id == TypeTableEntryIdPointer) {
|
||||
// child_type = array_type->data.pointer.child_type;
|
||||
// } else if (array_type->id == TypeTableEntryIdStruct) {
|
||||
// assert(array_type->data.structure.is_slice);
|
||||
// TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
|
||||
// assert(child_ptr_type->id == TypeTableEntryIdPointer);
|
||||
// child_type = child_ptr_type->data.pointer.child_type;
|
||||
// } else if (array_type->id == TypeTableEntryIdArray) {
|
||||
// child_type = array_type->data.array.child_type;
|
||||
// } else {
|
||||
// zig_unreachable();
|
||||
// }
|
||||
//
|
||||
// if (is_lvalue || !ptr || handle_is_ptr(child_type)) {
|
||||
// return ptr;
|
||||
// } else {
|
||||
// return LLVMBuildLoad(g->builder, ptr, "");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
||||
// AstNode *init_expr = node->data.variable_declaration.expr;
|
||||
// if (node->data.variable_declaration.is_const && init_expr) {
|
||||
// TypeTableEntry *init_expr_type = get_expr_type(init_expr);
|
||||
// if (init_expr_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
// init_expr_type->id == TypeTableEntryIdNumLitInt)
|
||||
// {
|
||||
// return nullptr;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// LLVMValueRef init_val = nullptr;
|
||||
// TypeTableEntry *init_val_type;
|
||||
// return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false);
|
||||
//}
|
||||
//
|
||||
//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 LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
|
||||
// switch (atomic_order) {
|
||||
// case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
|
||||
// case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic;
|
||||
// case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire;
|
||||
// case AtomicOrderRelease: return LLVMAtomicOrderingRelease;
|
||||
// case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease;
|
||||
// case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent;
|
||||
// }
|
||||
// zig_unreachable();
|
||||
//}
|
||||
|
||||
@ -719,6 +719,26 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
|
||||
fprintf(irp->f, "@cmpxchg(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->cmp_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->new_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->success_order_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->failure_order_value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
|
||||
fprintf(irp->f, "@fence(");
|
||||
ir_print_other_instruction(irp, instruction->order_value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -883,6 +903,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdEmbedFile:
|
||||
ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCmpxchg:
|
||||
ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
|
||||
break;
|
||||
case IrInstructionIdFence:
|
||||
ir_print_fence(irp, (IrInstructionFence *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
@ -273,6 +273,18 @@ fn testErrorName() {
|
||||
// return result;
|
||||
//}
|
||||
|
||||
fn cmpxchg() {
|
||||
var x: i32 = 1234;
|
||||
while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {}
|
||||
assert(x == 5678);
|
||||
}
|
||||
|
||||
fn fence() {
|
||||
var x: i32 = 1234;
|
||||
@fence(AtomicOrder.SeqCst);
|
||||
x = 5678;
|
||||
}
|
||||
|
||||
fn assert(ok: bool) {
|
||||
if (!ok)
|
||||
@unreachable();
|
||||
@ -300,6 +312,8 @@ fn runAllTests() {
|
||||
testMinValueAndMaxValue();
|
||||
testReturnStringFromFunction();
|
||||
testErrorName();
|
||||
cmpxchg();
|
||||
fence();
|
||||
}
|
||||
|
||||
export nakedcc fn _start() -> unreachable {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user