| ... | ... | @@ -14715,51 +14715,64 @@ fn checkNumericType( |
| 14715 | 14715 | } |
| 14716 | 14716 | } |
| 14717 | 14717 | |
| 14718 | | fn checkAtomicOperandType( |
| 14718 | /// Returns the casted pointer. |
| 14719 | fn checkAtomicPtrOperand( |
| 14719 | 14720 | sema: *Sema, |
| 14720 | 14721 | block: *Block, |
| 14721 | | ty_src: LazySrcLoc, |
| 14722 | | ty: Type, |
| 14723 | | ) CompileError!void { |
| 14724 | | var buffer: Type.Payload.Bits = undefined; |
| 14722 | elem_ty: Type, |
| 14723 | elem_ty_src: LazySrcLoc, |
| 14724 | ptr: Air.Inst.Ref, |
| 14725 | ptr_src: LazySrcLoc, |
| 14726 | ptr_const: bool, |
| 14727 | ) CompileError!Air.Inst.Ref { |
| 14725 | 14728 | const target = sema.mod.getTarget(); |
| 14726 | | const max_atomic_bits = target_util.largestAtomicBits(target); |
| 14727 | | const int_ty = switch (ty.zigTypeTag()) { |
| 14728 | | .Int => ty, |
| 14729 | | .Enum => ty.intTagType(&buffer), |
| 14730 | | .Float => { |
| 14731 | | const bit_count = ty.floatBits(target); |
| 14732 | | if (bit_count > max_atomic_bits) { |
| 14733 | | return sema.fail( |
| 14734 | | block, |
| 14735 | | ty_src, |
| 14736 | | "expected {d}-bit float type or smaller; found {d}-bit float type", |
| 14737 | | .{ max_atomic_bits, bit_count }, |
| 14738 | | ); |
| 14739 | | } |
| 14740 | | return; |
| 14741 | | }, |
| 14742 | | .Bool => return, // Will be treated as `u8`. |
| 14743 | | else => { |
| 14744 | | if (ty.isPtrAtRuntime()) return; |
| 14729 | var diag: target_util.AtomicPtrAlignmentDiagnostics = .{}; |
| 14730 | const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) { |
| 14731 | error.FloatTooBig => return sema.fail( |
| 14732 | block, |
| 14733 | elem_ty_src, |
| 14734 | "expected {d}-bit float type or smaller; found {d}-bit float type", |
| 14735 | .{ diag.max_bits, diag.bits }, |
| 14736 | ), |
| 14737 | error.IntTooBig => return sema.fail( |
| 14738 | block, |
| 14739 | elem_ty_src, |
| 14740 | "expected {d}-bit integer type or smaller; found {d}-bit integer type", |
| 14741 | .{ diag.max_bits, diag.bits }, |
| 14742 | ), |
| 14743 | error.BadType => return sema.fail( |
| 14744 | block, |
| 14745 | elem_ty_src, |
| 14746 | "expected bool, integer, float, enum, or pointer type; found {}", |
| 14747 | .{elem_ty.fmt(sema.mod)}, |
| 14748 | ), |
| 14749 | }; |
| 14745 | 14750 | |
| 14746 | | return sema.fail( |
| 14747 | | block, |
| 14748 | | ty_src, |
| 14749 | | "expected bool, integer, float, enum, or pointer type; found {}", |
| 14750 | | .{ty.fmt(sema.mod)}, |
| 14751 | | ); |
| 14751 | var wanted_ptr_data: Type.Payload.Pointer.Data = .{ |
| 14752 | .pointee_type = elem_ty, |
| 14753 | .@"align" = alignment, |
| 14754 | .@"addrspace" = .generic, |
| 14755 | .mutable = !ptr_const, |
| 14756 | }; |
| 14757 | |
| 14758 | const ptr_ty = sema.typeOf(ptr); |
| 14759 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) { |
| 14760 | .Pointer => ptr_ty.ptrInfo().data, |
| 14761 | else => { |
| 14762 | const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); |
| 14763 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 14764 | unreachable; |
| 14752 | 14765 | }, |
| 14753 | 14766 | }; |
| 14754 | | const bit_count = int_ty.intInfo(target).bits; |
| 14755 | | if (bit_count > max_atomic_bits) { |
| 14756 | | return sema.fail( |
| 14757 | | block, |
| 14758 | | ty_src, |
| 14759 | | "expected {d}-bit integer type or smaller; found {d}-bit integer type", |
| 14760 | | .{ max_atomic_bits, bit_count }, |
| 14761 | | ); |
| 14762 | | } |
| 14767 | |
| 14768 | wanted_ptr_data.@"addrspace" = ptr_data.@"addrspace"; |
| 14769 | wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; |
| 14770 | wanted_ptr_data.@"volatile" = ptr_data.@"volatile"; |
| 14771 | |
| 14772 | const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); |
| 14773 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 14774 | |
| 14775 | return casted_ptr; |
| 14763 | 14776 | } |
| 14764 | 14777 | |
| 14765 | 14778 | fn checkPtrIsNotComptimeMutable( |
| ... | ... | @@ -15036,10 +15049,8 @@ fn zirCmpxchg( |
| 15036 | 15049 | const success_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node }; |
| 15037 | 15050 | const failure_order_src: LazySrcLoc = .{ .node_offset_builtin_call_arg5 = inst_data.src_node }; |
| 15038 | 15051 | // zig fmt: on |
| 15039 | | const ptr = sema.resolveInst(extra.ptr); |
| 15040 | | const ptr_ty = sema.typeOf(ptr); |
| 15041 | | const elem_ty = ptr_ty.elemType(); |
| 15042 | | try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty); |
| 15052 | const expected_value = sema.resolveInst(extra.expected_value); |
| 15053 | const elem_ty = sema.typeOf(expected_value); |
| 15043 | 15054 | if (elem_ty.zigTypeTag() == .Float) { |
| 15044 | 15055 | return sema.fail( |
| 15045 | 15056 | block, |
| ... | ... | @@ -15048,7 +15059,8 @@ fn zirCmpxchg( |
| 15048 | 15059 | .{elem_ty.fmt(sema.mod)}, |
| 15049 | 15060 | ); |
| 15050 | 15061 | } |
| 15051 | | const expected_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.expected_value), expected_src); |
| 15062 | const uncasted_ptr = sema.resolveInst(extra.ptr); |
| 15063 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); |
| 15052 | 15064 | const new_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.new_value), new_value_src); |
| 15053 | 15065 | const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order); |
| 15054 | 15066 | const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order); |
| ... | ... | @@ -15081,6 +15093,7 @@ fn zirCmpxchg( |
| 15081 | 15093 | // to become undef as well |
| 15082 | 15094 | return sema.addConstUndef(result_ty); |
| 15083 | 15095 | } |
| 15096 | const ptr_ty = sema.typeOf(ptr); |
| 15084 | 15097 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 15085 | 15098 | const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: { |
| 15086 | 15099 | try sema.storePtr(block, src, ptr, new_value); |
| ... | ... | @@ -15487,17 +15500,16 @@ fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15487 | 15500 | |
| 15488 | 15501 | fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15489 | 15502 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 15490 | | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 15503 | const extra = sema.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data; |
| 15491 | 15504 | // zig fmt: off |
| 15492 | 15505 | const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15493 | 15506 | const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 15494 | 15507 | const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 15495 | 15508 | // zig fmt: on |
| 15496 | | const ptr = sema.resolveInst(extra.lhs); |
| 15497 | | const ptr_ty = sema.typeOf(ptr); |
| 15498 | | const elem_ty = ptr_ty.elemType(); |
| 15499 | | try sema.checkAtomicOperandType(block, elem_ty_src, elem_ty); |
| 15500 | | const order = try sema.resolveAtomicOrder(block, order_src, extra.rhs); |
| 15509 | const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type); |
| 15510 | const uncasted_ptr = sema.resolveInst(extra.ptr); |
| 15511 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); |
| 15512 | const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering); |
| 15501 | 15513 | |
| 15502 | 15514 | switch (order) { |
| 15503 | 15515 | .Release, .AcqRel => { |
| ... | ... | @@ -15516,7 +15528,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 15516 | 15528 | } |
| 15517 | 15529 | |
| 15518 | 15530 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 15519 | | if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| { |
| 15531 | if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| { |
| 15520 | 15532 | return sema.addConstant(elem_ty, elem_val); |
| 15521 | 15533 | } |
| 15522 | 15534 | } |
| ... | ... | @@ -15536,19 +15548,19 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15536 | 15548 | const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; |
| 15537 | 15549 | const src = inst_data.src(); |
| 15538 | 15550 | // zig fmt: off |
| 15539 | | const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15551 | const elem_ty_src : LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15540 | 15552 | const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 15541 | 15553 | const op_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 15542 | 15554 | const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; |
| 15543 | 15555 | const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg4 = inst_data.src_node }; |
| 15544 | 15556 | // zig fmt: on |
| 15545 | | const ptr = sema.resolveInst(extra.ptr); |
| 15546 | | const ptr_ty = sema.typeOf(ptr); |
| 15547 | | const operand_ty = ptr_ty.elemType(); |
| 15548 | | try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty); |
| 15557 | const operand = sema.resolveInst(extra.operand); |
| 15558 | const elem_ty = sema.typeOf(operand); |
| 15559 | const uncasted_ptr = sema.resolveInst(extra.ptr); |
| 15560 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); |
| 15549 | 15561 | const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation); |
| 15550 | 15562 | |
| 15551 | | switch (operand_ty.zigTypeTag()) { |
| 15563 | switch (elem_ty.zigTypeTag()) { |
| 15552 | 15564 | .Enum => if (op != .Xchg) { |
| 15553 | 15565 | return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{}); |
| 15554 | 15566 | }, |
| ... | ... | @@ -15561,7 +15573,6 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15561 | 15573 | }, |
| 15562 | 15574 | else => {}, |
| 15563 | 15575 | } |
| 15564 | | const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src); |
| 15565 | 15576 | const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering); |
| 15566 | 15577 | |
| 15567 | 15578 | if (order == .Unordered) { |
| ... | ... | @@ -15569,8 +15580,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15569 | 15580 | } |
| 15570 | 15581 | |
| 15571 | 15582 | // special case zero bit types |
| 15572 | | if (try sema.typeHasOnePossibleValue(block, operand_ty_src, operand_ty)) |val| { |
| 15573 | | return sema.addConstant(operand_ty, val); |
| 15583 | if (try sema.typeHasOnePossibleValue(block, elem_ty_src, elem_ty)) |val| { |
| 15584 | return sema.addConstant(elem_ty, val); |
| 15574 | 15585 | } |
| 15575 | 15586 | |
| 15576 | 15587 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| ... | ... | @@ -15581,22 +15592,23 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15581 | 15592 | }; |
| 15582 | 15593 | if (ptr_val.isComptimeMutablePtr()) { |
| 15583 | 15594 | const target = sema.mod.getTarget(); |
| 15595 | const ptr_ty = sema.typeOf(ptr); |
| 15584 | 15596 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 15585 | 15597 | const new_val = switch (op) { |
| 15586 | 15598 | // zig fmt: off |
| 15587 | 15599 | .Xchg => operand_val, |
| 15588 | | .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target), |
| 15589 | | .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target), |
| 15590 | | .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena, target), |
| 15591 | | .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target), |
| 15592 | | .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena, target), |
| 15593 | | .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena, target), |
| 15594 | | .Max => stored_val.numberMax (operand_val, target), |
| 15595 | | .Min => stored_val.numberMin (operand_val, target), |
| 15600 | .Add => try stored_val.numberAddWrap(operand_val, elem_ty, sema.arena, target), |
| 15601 | .Sub => try stored_val.numberSubWrap(operand_val, elem_ty, sema.arena, target), |
| 15602 | .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, target), |
| 15603 | .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, target), |
| 15604 | .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, target), |
| 15605 | .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, target), |
| 15606 | .Max => stored_val.numberMax (operand_val, target), |
| 15607 | .Min => stored_val.numberMin (operand_val, target), |
| 15596 | 15608 | // zig fmt: on |
| 15597 | 15609 | }; |
| 15598 | | try sema.storePtrVal(block, src, ptr_val, new_val, operand_ty); |
| 15599 | | return sema.addConstant(operand_ty, stored_val); |
| 15610 | try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty); |
| 15611 | return sema.addConstant(elem_ty, stored_val); |
| 15600 | 15612 | } else break :rs ptr_src; |
| 15601 | 15613 | } else ptr_src; |
| 15602 | 15614 | |
| ... | ... | @@ -15620,15 +15632,15 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 15620 | 15632 | const extra = sema.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data; |
| 15621 | 15633 | const src = inst_data.src(); |
| 15622 | 15634 | // zig fmt: off |
| 15623 | | const operand_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15635 | const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15624 | 15636 | const ptr_src : LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 15625 | 15637 | const operand_src : LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 15626 | 15638 | const order_src : LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node }; |
| 15627 | 15639 | // zig fmt: on |
| 15628 | | const ptr = sema.resolveInst(extra.ptr); |
| 15629 | | const operand_ty = sema.typeOf(ptr).elemType(); |
| 15630 | | try sema.checkAtomicOperandType(block, operand_ty_src, operand_ty); |
| 15631 | | const operand = try sema.coerce(block, operand_ty, sema.resolveInst(extra.operand), operand_src); |
| 15640 | const operand = sema.resolveInst(extra.operand); |
| 15641 | const elem_ty = sema.typeOf(operand); |
| 15642 | const uncasted_ptr = sema.resolveInst(extra.ptr); |
| 15643 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); |
| 15632 | 15644 | const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering); |
| 15633 | 15645 | |
| 15634 | 15646 | const air_tag: Air.Inst.Tag = switch (order) { |