From b9360640cefd1aa30dedf71a0c6b7bddc51a6ae3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Apr 2018 18:12:00 -0400 Subject: add @atomicLoad builtin See #174 --- src/ir.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 08229b8bb3..d43efe0190 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -709,6 +709,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) { return IrInstructionIdAtomicRmw; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) { + return IrInstructionIdAtomicLoad; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) { return IrInstructionIdPromiseResultType; } @@ -2673,6 +2677,23 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *operand_type, IrInstruction *ptr, + IrInstruction *ordering, AtomicOrder resolved_ordering) +{ + IrInstructionAtomicLoad *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand_type = operand_type; + instruction->ptr = ptr; + instruction->ordering = ordering; + instruction->resolved_ordering = resolved_ordering; + + if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_type) { @@ -4303,6 +4324,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo // these 2 values don't mean anything since we passed non-null values for other args AtomicRmwOp_xchg, AtomicOrderMonotonic); } + case BuiltinFnIdAtomicLoad: + { + 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; + + return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value, + // this value does not mean anything since we passed non-null values for other arg + AtomicOrderMonotonic); + } } zig_unreachable(); } @@ -17898,35 +17940,43 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, return result->value.type; } -static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) { - TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other); - if (type_is_invalid(operand_type)) { +static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { + TypeTableEntry *operand_type = ir_resolve_type(ira, op); + if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; - } + if (operand_type->id == TypeTableEntryIdInt) { if (operand_type->data.integral.bit_count < 8) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, op, buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type", operand_type->data.integral.bit_count)); return ira->codegen->builtin_types.entry_invalid; } if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, op, buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type", operand_type->data.integral.bit_count)); return ira->codegen->builtin_types.entry_invalid; } if (!is_power_of_2(operand_type->data.integral.bit_count)) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, op, buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count)); return ira->codegen->builtin_types.entry_invalid; } } else if (get_codegen_ptr_type(operand_type) == nullptr) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, op, buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name))); return ira->codegen->builtin_types.entry_invalid; } + return operand_type; +} + +static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) { + TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other); + if (type_is_invalid(operand_type)) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *ptr_inst = instruction->ptr->other; if (type_is_invalid(ptr_inst->value.type)) return ira->codegen->builtin_types.entry_invalid; @@ -17974,6 +18024,49 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr return result->value.type; } +static TypeTableEntry *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstructionAtomicLoad *instruction) { + TypeTableEntry *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->other); + if (type_is_invalid(operand_type)) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *ptr_inst = instruction->ptr->other; + if (type_is_invalid(ptr_inst->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, true); + IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type); + if (type_is_invalid(casted_ptr->value.type)) + return ira->codegen->builtin_types.entry_invalid; + + AtomicOrder ordering; + if (instruction->ordering == nullptr) { + ordering = instruction->resolved_ordering; + } else { + if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering)) + return ira->codegen->builtin_types.entry_invalid; + } + + if (ordering == AtomicOrderRelease || ordering == AtomicOrderAcqRel) { + assert(instruction->ordering != nullptr); + ir_add_error(ira, instruction->ordering, + buf_sprintf("@atomicLoad atomic ordering must not be Release or AcqRel")); + return ira->codegen->builtin_types.entry_invalid; + } + + if (instr_is_comptime(casted_ptr)) { + IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr); + ir_link_new_instruction(result, &instruction->base); + assert(result->value.type != nullptr); + return result->value.type; + } + + IrInstruction *result = ir_build_atomic_load(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_ptr, nullptr, ordering); + ir_link_new_instruction(result, &instruction->base); + result->value.type = operand_type; + return result->value.type; +} + static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other); if (type_is_invalid(promise_type)) @@ -18357,6 +18450,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction); case IrInstructionIdAtomicRmw: return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction); + case IrInstructionIdAtomicLoad: + return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction); case IrInstructionIdPromiseResultType: return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); case IrInstructionIdAwaitBookkeeping: @@ -18584,6 +18679,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdAtomicLoad: return false; case IrInstructionIdAsm: -- cgit v1.2.3