aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-03-13 15:17:53 -0400
committerAndrew Kelley <andrew@ziglang.org>2020-03-13 15:17:53 -0400
commit656ba530d80e67bc7bb9c40e5c2db26a40743a15 (patch)
tree767f4d57000922cf122ae965dc825f87c62ec64e /src/ir.cpp
parent96c07674fc2293fa040212ab797c05436dc515b1 (diff)
parent3eff77bfb52accbc16eb831753ff4917fc2b4873 (diff)
downloadzig-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.cpp398
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,