result location semantics for cmpxchg

This commit is contained in:
Andrew Kelley 2019-06-10 17:49:36 -04:00
parent b9c033ae1a
commit ee3f7e20f6
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 41 additions and 29 deletions

View File

@ -2862,26 +2862,26 @@ struct IrInstructionEmbedFile {
struct IrInstructionCmpxchgSrc { struct IrInstructionCmpxchgSrc {
IrInstruction base; IrInstruction base;
bool is_weak;
IrInstruction *type_value; IrInstruction *type_value;
IrInstruction *ptr; IrInstruction *ptr;
IrInstruction *cmp_value; IrInstruction *cmp_value;
IrInstruction *new_value; IrInstruction *new_value;
IrInstruction *success_order_value; IrInstruction *success_order_value;
IrInstruction *failure_order_value; IrInstruction *failure_order_value;
ResultLoc *result_loc;
bool is_weak;
}; };
struct IrInstructionCmpxchgGen { struct IrInstructionCmpxchgGen {
IrInstruction base; IrInstruction base;
bool is_weak;
AtomicOrder success_order;
AtomicOrder failure_order;
IrInstruction *ptr; IrInstruction *ptr;
IrInstruction *cmp_value; IrInstruction *cmp_value;
IrInstruction *new_value; IrInstruction *new_value;
LLVMValueRef tmp_ptr; IrInstruction *result_loc;
AtomicOrder success_order;
AtomicOrder failure_order;
bool is_weak;
}; };
struct IrInstructionFence { struct IrInstructionFence {

View File

@ -4516,28 +4516,28 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val, LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
success_order, failure_order, instruction->is_weak); success_order, failure_order, instruction->is_weak);
ZigType *maybe_type = instruction->base.value.type; ZigType *optional_type = instruction->base.value.type;
assert(maybe_type->id == ZigTypeIdOptional); assert(optional_type->id == ZigTypeIdOptional);
ZigType *child_type = maybe_type->data.maybe.child_type; ZigType *child_type = optional_type->data.maybe.child_type;
if (!handle_is_ptr(maybe_type)) { if (!handle_is_ptr(optional_type)) {
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
} }
assert(instruction->tmp_ptr != nullptr); LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
assert(type_has_bits(child_type)); assert(type_has_bits(child_type));
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_null_index, "");
gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false); gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
return instruction->tmp_ptr; return result_loc;
} }
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) { static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
@ -6840,9 +6840,6 @@ static void do_code_gen(CodeGen *g) {
slot = &ref_instruction->tmp_ptr; slot = &ref_instruction->tmp_ptr;
assert(instruction->value.type->id == ZigTypeIdPointer); assert(instruction->value.type->id == ZigTypeIdPointer);
slot_type = instruction->value.type->data.pointer.child_type; slot_type = instruction->value.type->data.pointer.child_type;
} else if (instruction->id == IrInstructionIdCmpxchgGen) {
IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction;
slot = &cmpxchg_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdResizeSlice) { } else if (instruction->id == IrInstructionIdResizeSlice) {
IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction; IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction;
slot = &resize_slice_instruction->tmp_ptr; slot = &resize_slice_instruction->tmp_ptr;

View File

@ -2032,8 +2032,7 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
IrInstruction *success_order_value, IrInstruction *failure_order_value, IrInstruction *success_order_value, IrInstruction *failure_order_value, bool is_weak, ResultLoc *result_loc)
bool is_weak)
{ {
IrInstructionCmpxchgSrc *instruction = ir_build_instruction<IrInstructionCmpxchgSrc>(irb, scope, source_node); IrInstructionCmpxchgSrc *instruction = ir_build_instruction<IrInstructionCmpxchgSrc>(irb, scope, source_node);
instruction->type_value = type_value; instruction->type_value = type_value;
@ -2043,6 +2042,7 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode
instruction->success_order_value = success_order_value; instruction->success_order_value = success_order_value;
instruction->failure_order_value = failure_order_value; instruction->failure_order_value = failure_order_value;
instruction->is_weak = is_weak; instruction->is_weak = is_weak;
instruction->result_loc = result_loc;
ir_ref_instruction(type_value, irb->current_basic_block); ir_ref_instruction(type_value, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block);
@ -2054,22 +2054,25 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base; return &instruction->base;
} }
static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type,
IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstruction *result_loc)
{ {
IrInstructionCmpxchgGen *instruction = ir_build_instruction<IrInstructionCmpxchgGen>(&ira->new_irb, IrInstructionCmpxchgGen *instruction = ir_build_instruction<IrInstructionCmpxchgGen>(&ira->new_irb,
source_instruction->scope, source_instruction->source_node); source_instruction->scope, source_instruction->source_node);
instruction->base.value.type = result_type;
instruction->ptr = ptr; instruction->ptr = ptr;
instruction->cmp_value = cmp_value; instruction->cmp_value = cmp_value;
instruction->new_value = new_value; instruction->new_value = new_value;
instruction->success_order = success_order; instruction->success_order = success_order;
instruction->failure_order = failure_order; instruction->failure_order = failure_order;
instruction->is_weak = is_weak; instruction->is_weak = is_weak;
instruction->result_loc = result_loc;
ir_ref_instruction(ptr, ira->new_irb.current_basic_block); ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block);
ir_ref_instruction(new_value, ira->new_irb.current_basic_block); ir_ref_instruction(new_value, ira->new_irb.current_basic_block);
if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
return &instruction->base; return &instruction->base;
} }
@ -4420,7 +4423,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg5_value; return arg5_value;
IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value,
arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
result_loc);
return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc);
} }
case BuiltinFnIdFence: case BuiltinFnIdFence:
@ -20439,6 +20443,18 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
if (type_is_invalid(ptr->value.type)) if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction; return ira->codegen->invalid_instruction;
ZigType *result_type = get_optional_type(ira->codegen, operand_type);
IrInstruction *result_loc;
if (handle_is_ptr(result_type)) {
result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
result_type, nullptr);
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
return result_loc;
}
} else {
result_loc = nullptr;
}
// TODO let this be volatile // TODO let this be volatile
ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type); IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
@ -20502,12 +20518,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
zig_panic("TODO compile-time execution of cmpxchg"); zig_panic("TODO compile-time execution of cmpxchg");
} }
IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, return ir_build_cmpxchg_gen(ira, &instruction->base, result_type,
casted_ptr, casted_cmp_value, casted_new_value, casted_ptr, casted_cmp_value, casted_new_value,
success_order, failure_order, instruction->is_weak); success_order, failure_order, instruction->is_weak, result_loc);
result->value.type = get_optional_type(ira->codegen, operand_type);
ir_add_alloca(ira, result, result->value.type);
return result;
} }
static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) { static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {

View File

@ -730,7 +730,8 @@ static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruct
ir_print_other_instruction(irp, instruction->success_order_value); ir_print_other_instruction(irp, instruction->success_order_value);
fprintf(irp->f, ", "); fprintf(irp->f, ", ");
ir_print_other_instruction(irp, instruction->failure_order_value); ir_print_other_instruction(irp, instruction->failure_order_value);
fprintf(irp->f, ")"); fprintf(irp->f, ")result=");
ir_print_result_loc(irp, instruction->result_loc);
} }
static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
@ -740,7 +741,8 @@ static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruct
ir_print_other_instruction(irp, instruction->cmp_value); ir_print_other_instruction(irp, instruction->cmp_value);
fprintf(irp->f, ", "); fprintf(irp->f, ", ");
ir_print_other_instruction(irp, instruction->new_value); ir_print_other_instruction(irp, instruction->new_value);
fprintf(irp->f, ", TODO print atomic orders)"); fprintf(irp->f, ", TODO print atomic orders)result=");
ir_print_other_instruction(irp, instruction->result_loc);
} }
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {