diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-03-13 15:17:53 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-03-13 15:17:53 -0400 |
| commit | 656ba530d80e67bc7bb9c40e5c2db26a40743a15 (patch) | |
| tree | 767f4d57000922cf122ae965dc825f87c62ec64e /src/ir.cpp | |
| parent | 96c07674fc2293fa040212ab797c05436dc515b1 (diff) | |
| parent | 3eff77bfb52accbc16eb831753ff4917fc2b4873 (diff) | |
| download | zig-656ba530d80e67bc7bb9c40e5c2db26a40743a15.tar.gz zig-656ba530d80e67bc7bb9c40e5c2db26a40743a15.zip | |
Merge remote-tracking branch 'origin/master' into llvm10
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 398 |
1 files changed, 299 insertions, 99 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index 4068247b72..72e2a3fd98 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4978,6 +4978,7 @@ static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_ case ScopeIdLoop: case ScopeIdSuspend: case ScopeIdCompTime: + case ScopeIdNoAsync: case ScopeIdRuntime: case ScopeIdTypeOf: case ScopeIdExpr: @@ -5033,6 +5034,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope case ScopeIdLoop: case ScopeIdSuspend: case ScopeIdCompTime: + case ScopeIdNoAsync: case ScopeIdRuntime: case ScopeIdTypeOf: case ScopeIdExpr: @@ -5910,10 +5912,18 @@ static IrInstSrc *ir_gen_array_access(IrBuilderSrc *irb, Scope *scope, AstNode * if (array_ref_instruction == irb->codegen->invalid_inst_src) return array_ref_instruction; + // Create an usize-typed result location to hold the subscript value, this + // makes it possible for the compiler to infer the subscript expression type + // if needed + IrInstSrc *usize_type_inst = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, usize_type_inst, no_result_loc()); + AstNode *subscript_node = node->data.array_access_expr.subscript; - IrInstSrc *subscript_instruction = ir_gen_node(irb, subscript_node, scope); - if (subscript_instruction == irb->codegen->invalid_inst_src) - return subscript_instruction; + IrInstSrc *subscript_value = ir_gen_node_extra(irb, subscript_node, scope, LValNone, &result_loc_cast->base); + if (subscript_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *subscript_instruction = ir_build_implicit_cast(irb, scope, subscript_node, subscript_value, result_loc_cast); IrInstSrc *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction, subscript_instruction, true, PtrLenSingle, nullptr); @@ -7266,6 +7276,18 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod zig_unreachable(); } +static ScopeNoAsync *get_scope_noasync(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdNoAsync) + return (ScopeNoAsync *)scope; + if (scope->id == ScopeIdFnDef) + return nullptr; + + scope = scope->parent; + } + return nullptr; +} + static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { @@ -7274,8 +7296,19 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, if (node->data.fn_call_expr.modifier == CallModifierBuiltin) return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); + bool is_noasync = get_scope_noasync(scope) != nullptr; + CallModifier modifier = node->data.fn_call_expr.modifier; + if (is_noasync) { + if (modifier == CallModifierAsync) { + add_node_error(irb->codegen, node, + buf_sprintf("async call in noasync scope")); + return irb->codegen->invalid_inst_src; + } + modifier = CallModifierNoAsync; + } + AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, node->data.fn_call_expr.modifier, + return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, modifier, nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); } @@ -8981,7 +9014,7 @@ static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n return irb->codegen->invalid_inst_src; } else_prong = prong_node; - } else if (prong_item_count == 1 && + } else if (prong_item_count == 1 && prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol && buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) { if (underscore_prong) { @@ -9129,6 +9162,14 @@ static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNod return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); } +static IrInstSrc *ir_gen_noasync(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { + assert(node->type == NodeTypeNoAsync); + + Scope *child_scope = create_noasync_scope(irb->codegen, node, parent_scope); + // purposefully pass null for result_loc and let EndExpr handle it + return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); +} + static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { IrInstSrc *is_comptime; if (ir_should_inline(irb->exec, break_scope)) { @@ -9709,6 +9750,10 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeResume); + if (get_scope_noasync(scope) != nullptr) { + add_node_error(irb->codegen, node, buf_sprintf("resume in noasync scope")); + return irb->codegen->invalid_inst_src; + } IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr); if (target_inst == irb->codegen->invalid_inst_src) @@ -9722,7 +9767,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no { assert(node->type == NodeTypeAwaitExpr); - bool is_noasync = node->data.await_expr.noasync_token != nullptr; + bool is_noasync = get_scope_noasync(scope) != nullptr; AstNode *expr_node = node->data.await_expr.expr; if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { @@ -9768,6 +9813,11 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition")); return irb->codegen->invalid_inst_src; } + if (get_scope_noasync(parent_scope) != nullptr) { + add_node_error(irb->codegen, node, buf_sprintf("suspend in noasync scope")); + return irb->codegen->invalid_inst_src; + } + ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); if (existing_suspend_scope) { if (!existing_suspend_scope->reported_err) { @@ -9897,6 +9947,8 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope return ir_gen_switch_expr(irb, scope, node, lval, result_loc); case NodeTypeCompTime: return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc); + case NodeTypeNoAsync: + return ir_expr_wrap(irb, scope, ir_gen_noasync(irb, scope, node, lval), result_loc); case NodeTypeErrorType: return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); case NodeTypeBreak: @@ -15393,23 +15445,6 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { } } -static bool optional_value_is_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (get_src_ptr_type(val->type) != nullptr) { - if (val->data.x_ptr.special == ConstPtrSpecialNull) { - return true; - } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return val->data.x_ptr.data.hard_coded_addr.addr == 0; - } else { - return false; - } - } else if (is_opt_err_set(val->type)) { - return val->data.x_err_set == nullptr; - } else { - return val->data.x_optional == nullptr; - } -} - static void set_optional_value_to_null(ZigValue *val) { assert(val->special == ConstValSpecialStatic); if (val->type->id == ZigTypeIdNull) return; // nothing to do @@ -15524,9 +15559,20 @@ static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val switch (val->data.x_lazy->id) { case LazyValueIdInvalid: zig_unreachable(); - case LazyValueIdAlignOf: - *result = CmpGT; + case LazyValueIdAlignOf: { + LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(val->data.x_lazy); + IrAnalyze *ira = lazy_align_of->ira; + + bool is_zero_bits; + if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_align_of->target_type->value, + nullptr, nullptr, &is_zero_bits))) + { + return err; + } + + *result = is_zero_bits ? CmpEQ : CmpGT; return ErrorNone; + } case LazyValueIdSizeOf: { LazyValueSizeOf *lazy_size_of = reinterpret_cast<LazyValueSizeOf *>(val->data.x_lazy); IrAnalyze *ira = lazy_size_of->ira; @@ -16556,49 +16602,69 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in IrInstGen *casted_op2; IrBinOp op_id = bin_op_instruction->op_id; if (op1->value->type->id == ZigTypeIdComptimeInt) { + // comptime_int has no finite bit width casted_op2 = op2; if (op_id == IrBinOpBitShiftLeftLossy) { op_id = IrBinOpBitShiftLeftExact; } - if (casted_op2->value->data.x_bigint.is_negative) { + if (!instr_is_comptime(op2)) { + ir_add_error(ira, &bin_op_instruction->base.base, + buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); + return ira->codegen->invalid_inst_gen; + } + + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); + if (op2_val == nullptr) + return ira->codegen->invalid_inst_gen; + + if (op2_val->data.x_bigint.is_negative) { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &casted_op2->value->data.x_bigint, 10); - ir_add_error(ira, &casted_op2->base, buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); + bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); + ir_add_error(ira, &casted_op2->base, + buf_sprintf("shift by negative value %s", buf_ptr(val_buf))); return ira->codegen->invalid_inst_gen; } } else { + const unsigned bit_count = op1->value->type->data.integral.bit_count; ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen, - op1->value->type->data.integral.bit_count - 1); - if (bin_op_instruction->op_id == IrBinOpBitShiftLeftLossy && - op2->value->type->id == ZigTypeIdComptimeInt) { + bit_count > 0 ? bit_count - 1 : 0); - ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad); + casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); + if (type_is_invalid(casted_op2->value->type)) + return ira->codegen->invalid_inst_gen; + + // This check is only valid iff op1 has at least one bit + if (bit_count > 0 && instr_is_comptime(casted_op2)) { + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); if (op2_val == nullptr) return ira->codegen->invalid_inst_gen; - if (!bigint_fits_in_bits(&op2_val->data.x_bigint, - shift_amt_type->data.integral.bit_count, - op2_val->data.x_bigint.is_negative)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10); + + BigInt bit_count_value = {0}; + bigint_init_unsigned(&bit_count_value, bit_count); + + if (bigint_cmp(&op2_val->data.x_bigint, &bit_count_value) != CmpLT) { ErrorMsg* msg = ir_add_error(ira, &bin_op_instruction->base.base, buf_sprintf("RHS of shift is too large for LHS type")); - add_error_note( - ira->codegen, - msg, - op2->base.source_node, - buf_sprintf("value %s cannot fit into type %s", - buf_ptr(val_buf), - buf_ptr(&shift_amt_type->name))); + add_error_note(ira->codegen, msg, op1->base.source_node, + buf_sprintf("type %s has only %u bits", + buf_ptr(&op1->value->type->name), bit_count)); + return ira->codegen->invalid_inst_gen; } } + } - casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type); - if (type_is_invalid(casted_op2->value->type)) + // Fast path for zero RHS + if (instr_is_comptime(casted_op2)) { + ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); + if (op2_val == nullptr) return ira->codegen->invalid_inst_gen; + + if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ) + return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1); } if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) { @@ -16611,12 +16677,6 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in return ira->codegen->invalid_inst_gen; return ir_analyze_math_op(ira, &bin_op_instruction->base.base, op1->value->type, op1_val, op_id, op2_val); - } else if (op1->value->type->id == ZigTypeIdComptimeInt) { - ir_add_error(ira, &bin_op_instruction->base.base, - buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); - return ira->codegen->invalid_inst_gen; - } else if (instr_is_comptime(casted_op2) && bigint_cmp_zero(&casted_op2->value->data.x_bigint) == CmpEQ) { - return ir_build_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1, CastOpNoop); } return ir_build_bin_op_gen(ira, &bin_op_instruction->base.base, op1->value->type, @@ -17498,7 +17558,14 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV ZigValue *init_val = nullptr; if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - init_val = const_ptr_pointee(ira, ira->codegen, var_ptr->value, decl_var_instruction->base.base.source_node); + ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad); + if (ptr_val == nullptr) + return ira->codegen->invalid_inst_gen; + + init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.base.source_node); + if (init_val == nullptr) + return ira->codegen->invalid_inst_gen; + if (is_comptime_var) { if (var->gen_is_const) { var->const_value = init_val; @@ -19306,6 +19373,19 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node); if (type_is_invalid(specified_return_type)) return ira->codegen->invalid_inst_gen; + + if(!is_valid_return_type(specified_return_type)){ + ErrorMsg *msg = ir_add_error(ira, source_instr, + buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name))); + add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here")); + + Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name); + if (tld != nullptr) { + add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here")); + } + return ira->codegen->invalid_inst_gen; + } + if (fn_proto_node->data.fn_proto.auto_err_set) { ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn); if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown))) @@ -25095,12 +25175,50 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch return ira->codegen->invalid_inst_gen; } + ZigType *result_type = get_optional_type(ira->codegen, operand_type); + + // special case zero bit types + switch (type_has_one_possible_value(ira->codegen, operand_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_inst_gen; + case OnePossibleValueYes: { + IrInstGen *result = ir_const(ira, &instruction->base.base, result_type); + set_optional_value_to_null(result->value); + return result; + } + case OnePossibleValueNo: + break; + } + if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar && instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) { - zig_panic("TODO compile-time execution of cmpxchg"); + ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); + if (ptr_val == nullptr) + return ira->codegen->invalid_inst_gen; + + ZigValue *stored_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node); + if (stored_val == nullptr) + return ira->codegen->invalid_inst_gen; + + ZigValue *expected_val = ir_resolve_const(ira, casted_cmp_value, UndefBad); + if (expected_val == nullptr) + return ira->codegen->invalid_inst_gen; + + ZigValue *new_val = ir_resolve_const(ira, casted_new_value, UndefBad); + if (new_val == nullptr) + return ira->codegen->invalid_inst_gen; + + bool eql = const_values_equal(ira->codegen, stored_val, expected_val); + IrInstGen *result = ir_const(ira, &instruction->base.base, result_type); + if (eql) { + copy_const_val(ira->codegen, stored_val, new_val); + set_optional_value_to_null(result->value); + } else { + set_optional_payload(result->value, stored_val); + } + return result; } - ZigType *result_type = get_optional_type(ira->codegen, operand_type); IrInstGen *result_loc; if (handle_is_ptr(ira->codegen, result_type)) { result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, @@ -26035,7 +26153,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i if (array_type->data.pointer.ptr_len == PtrLenC) { array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); - // C pointers are allowzero by default. + // C pointers are allowzero by default. // However, we want to be able to slice them without generating an allowzero slice (see issue #4401). // To achieve this, we generate a runtime safety check and make the slice type non-allowzero. if (array_type->data.pointer.allow_zero) { @@ -26330,7 +26448,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i if (type_is_invalid(ptr_val->value->type)) return ira->codegen->invalid_inst_gen; - + ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); } @@ -28211,43 +28329,20 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; - if (operand_type->id == ZigTypeIdInt) { - if (operand_type->data.integral.bit_count < 8) { - ir_add_error(ira, &op->base, - 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->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) { + ZigType *int_type; + if (operand_type->id == ZigTypeIdEnum) { + int_type = operand_type->data.enumeration.tag_int_type; + } else { + int_type = operand_type; } + auto bit_count = int_type->data.integral.bit_count; uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - if (operand_type->data.integral.bit_count > max_atomic_bits) { + + if (bit_count > max_atomic_bits) { ir_add_error(ira, &op->base, buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type", - max_atomic_bits, 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, &op->base, - 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 (operand_type->id == ZigTypeIdEnum) { - ZigType *int_type = operand_type->data.enumeration.tag_int_type; - if (int_type->data.integral.bit_count < 8) { - ir_add_error(ira, &op->base, - buf_sprintf("expected enum tag type 8 bits or larger, found %" PRIu32 "-bit tag type", - int_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch); - if (int_type->data.integral.bit_count > max_atomic_bits) { - ir_add_error(ira, &op->base, - buf_sprintf("expected %" PRIu32 "-bit enum tag type or smaller, found %" PRIu32 "-bit tag type", - max_atomic_bits, int_type->data.integral.bit_count)); - return ira->codegen->builtin_types.entry_invalid; - } - if (!is_power_of_2(int_type->data.integral.bit_count)) { - ir_add_error(ira, &op->base, - buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count)); + max_atomic_bits, bit_count)); return ira->codegen->builtin_types.entry_invalid; } } else if (operand_type->id == ZigTypeIdFloat) { @@ -28258,6 +28353,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count)); return ira->codegen->builtin_types.entry_invalid; } + } else if (operand_type->id == ZigTypeIdBool) { + // will be treated as u8 } else { Error err; ZigType *operand_ptr_type; @@ -28296,11 +28393,15 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto if (operand_type->id == ZigTypeIdEnum && op != AtomicRmwOp_xchg) { ir_add_error(ira, &instruction->op->base, - buf_sprintf("@atomicRmw on enum only works with .Xchg")); + buf_sprintf("@atomicRmw with enum only allowed with .Xchg")); + return ira->codegen->invalid_inst_gen; + } else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) { + ir_add_error(ira, &instruction->op->base, + buf_sprintf("@atomicRmw with bool only allowed with .Xchg")); return ira->codegen->invalid_inst_gen; } else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) { ir_add_error(ira, &instruction->op->base, - buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub")); + buf_sprintf("@atomicRmw with float only allowed with .Xchg, .Add and .Sub")); return ira->codegen->invalid_inst_gen; } @@ -28321,14 +28422,103 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto return ira->codegen->invalid_inst_gen; } - if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) - { - ir_add_error(ira, &instruction->base.base, - buf_sprintf("compiler bug: TODO compile-time execution of @atomicRmw")); - return ira->codegen->invalid_inst_gen; + // special case zero bit types + switch (type_has_one_possible_value(ira->codegen, operand_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_inst_gen; + case OnePossibleValueYes: + return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type)); + case OnePossibleValueNo: + break; } - return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op, + IrInst *source_inst = &instruction->base.base; + if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) { + ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); + if (ptr_val == nullptr) + return ira->codegen->invalid_inst_gen; + + ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node); + if (op1_val == nullptr) + return ira->codegen->invalid_inst_gen; + + ZigValue *op2_val = ir_resolve_const(ira, casted_operand, UndefBad); + if (op2_val == nullptr) + return ira->codegen->invalid_inst_gen; + + IrInstGen *result = ir_const(ira, source_inst, operand_type); + copy_const_val(ira->codegen, result->value, op1_val); + if (op == AtomicRmwOp_xchg) { + copy_const_val(ira->codegen, op1_val, op2_val); + return result; + } + + if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) { + ir_add_error(ira, &instruction->ordering->base, + buf_sprintf("TODO comptime @atomicRmw with pointers other than .Xchg")); + return ira->codegen->invalid_inst_gen; + } + + ErrorMsg *msg; + if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) { + IrBinOp bin_op; + if (op == AtomicRmwOp_min) + // store op2 if op2 < op1 + bin_op = IrBinOpCmpGreaterThan; + else + // store op2 if op2 > op1 + bin_op = IrBinOpCmpLessThan; + + IrInstGen *dummy_value = ir_const(ira, source_inst, operand_type); + msg = ir_eval_bin_op_cmp_scalar(ira, source_inst, op1_val, bin_op, op2_val, dummy_value->value); + if (msg != nullptr) { + return ira->codegen->invalid_inst_gen; + } + if (dummy_value->value->data.x_bool) + copy_const_val(ira->codegen, op1_val, op2_val); + } else { + IrBinOp bin_op; + switch (op) { + case AtomicRmwOp_xchg: + case AtomicRmwOp_max: + case AtomicRmwOp_min: + zig_unreachable(); + case AtomicRmwOp_add: + if (operand_type->id == ZigTypeIdFloat) + bin_op = IrBinOpAdd; + else + bin_op = IrBinOpAddWrap; + break; + case AtomicRmwOp_sub: + if (operand_type->id == ZigTypeIdFloat) + bin_op = IrBinOpSub; + else + bin_op = IrBinOpSubWrap; + break; + case AtomicRmwOp_and: + case AtomicRmwOp_nand: + bin_op = IrBinOpBinAnd; + break; + case AtomicRmwOp_or: + bin_op = IrBinOpBinOr; + break; + case AtomicRmwOp_xor: + bin_op = IrBinOpBinXor; + break; + } + msg = ir_eval_math_op_scalar(ira, source_inst, operand_type, op1_val, bin_op, op2_val, op1_val); + if (msg != nullptr) { + return ira->codegen->invalid_inst_gen; + } + if (op == AtomicRmwOp_nand) { + bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint, + operand_type->data.integral.bit_count, operand_type->data.integral.is_signed); + } + } + return result; + } + + return ir_build_atomic_rmw_gen(ira, source_inst, casted_ptr, casted_operand, op, ordering, operand_type); } @@ -28400,6 +28590,16 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA return ira->codegen->invalid_inst_gen; } + // special case zero bit types + switch (type_has_one_possible_value(ira->codegen, operand_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_inst_gen; + case OnePossibleValueYes: + return ir_const_void(ira, &instruction->base.base); + case OnePossibleValueNo: + break; + } + if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) { IrInstGen *result = ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, value, false); result->value->type = ira->codegen->builtin_types.entry_void; @@ -30213,7 +30413,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { return ErrorSemanticAnalyzeFail; } else if (elem_type->id == ZigTypeIdOpaque) { ir_add_error(ira, &lazy_ptr_type->elem_type->base, - buf_sprintf("C pointers cannot point opaque types")); + buf_sprintf("C pointers cannot point to opaque types")); return ErrorSemanticAnalyzeFail; } else if (lazy_ptr_type->is_allowzero) { ir_add_error(ira, &lazy_ptr_type->elem_type->base, |
