authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-18 15:29:19-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-18 15:29:19-04:00
log8660661af4626c4bd589e6c6331a6ac786143f12
tree0c771125a45adab3a9d80cbc6b101cad2bed0fd1
parente252f92b9947e82f2473a37a74d5f9dc278a1c1d
parent9031cc54f27b4483c62ab904dd94063a9499c842
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11660 from ziglang/stage2-behavior

stage2: bug fixes towards more behavior tests passing

20 files changed, 623 insertions(+), 388 deletions(-)

lib/std/Thread.zig+6-5
...@@ -893,6 +893,7 @@ const LinuxThreadImpl = struct {...@@ -893,6 +893,7 @@ const LinuxThreadImpl = struct {
893 };893 };
894894
895 fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {895 fn spawn(config: SpawnConfig, comptime f: anytype, args: anytype) !Impl {
896 const page_size = std.mem.page_size;
896 const Args = @TypeOf(args);897 const Args = @TypeOf(args);
897 const Instance = struct {898 const Instance = struct {
898 fn_args: Args,899 fn_args: Args,
...@@ -915,11 +916,11 @@ const LinuxThreadImpl = struct {...@@ -915,11 +916,11 @@ const LinuxThreadImpl = struct {
915 var instance_offset: usize = undefined;916 var instance_offset: usize = undefined;
916917
917 const map_bytes = blk: {918 const map_bytes = blk: {
918 var bytes: usize = std.mem.page_size;919 var bytes: usize = page_size;
919 guard_offset = bytes;920 guard_offset = bytes;
920921
921 bytes += std.math.max(std.mem.page_size, config.stack_size);922 bytes += std.math.max(page_size, config.stack_size);
922 bytes = std.mem.alignForward(bytes, std.mem.page_size);923 bytes = std.mem.alignForward(bytes, page_size);
923 stack_offset = bytes;924 stack_offset = bytes;
924925
925 bytes = std.mem.alignForward(bytes, linux.tls.tls_image.alloc_align);926 bytes = std.mem.alignForward(bytes, linux.tls.tls_image.alloc_align);
...@@ -930,7 +931,7 @@ const LinuxThreadImpl = struct {...@@ -930,7 +931,7 @@ const LinuxThreadImpl = struct {
930 instance_offset = bytes;931 instance_offset = bytes;
931 bytes += @sizeOf(Instance);932 bytes += @sizeOf(Instance);
932933
933 bytes = std.mem.alignForward(bytes, std.mem.page_size);934 bytes = std.mem.alignForward(bytes, page_size);
934 break :blk bytes;935 break :blk bytes;
935 };936 };
936937
...@@ -954,7 +955,7 @@ const LinuxThreadImpl = struct {...@@ -954,7 +955,7 @@ const LinuxThreadImpl = struct {
954955
955 // map everything but the guard page as read/write956 // map everything but the guard page as read/write
956 os.mprotect(957 os.mprotect(
957 mapped[guard_offset..],958 @alignCast(page_size, mapped[guard_offset..]),
958 os.PROT.READ | os.PROT.WRITE,959 os.PROT.READ | os.PROT.WRITE,
959 ) catch |err| switch (err) {960 ) catch |err| switch (err) {
960 error.AccessDenied => unreachable,961 error.AccessDenied => unreachable,
lib/std/heap.zig+1-1
...@@ -345,7 +345,7 @@ const PageAllocator = struct {...@@ -345,7 +345,7 @@ const PageAllocator = struct {
345 // Unmap extra pages345 // Unmap extra pages
346 const aligned_buffer_len = alloc_len - drop_len;346 const aligned_buffer_len = alloc_len - drop_len;
347 if (aligned_buffer_len > aligned_len) {347 if (aligned_buffer_len > aligned_len) {
348 os.munmap(result_ptr[aligned_len..aligned_buffer_len]);348 os.munmap(@alignCast(mem.page_size, result_ptr[aligned_len..aligned_buffer_len]));
349 }349 }
350350
351 const new_hint = @alignCast(mem.page_size, result_ptr + aligned_len);351 const new_hint = @alignCast(mem.page_size, result_ptr + aligned_len);
src/Air.zig+4-4
...@@ -113,13 +113,13 @@ pub const Inst = struct {...@@ -113,13 +113,13 @@ pub const Inst = struct {
113 /// The offset is in element type units, not bytes.113 /// The offset is in element type units, not bytes.
114 /// Wrapping is undefined behavior.114 /// Wrapping is undefined behavior.
115 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.115 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
116 /// Uses the `bin_op` field.116 /// Uses the `ty_pl` field. Payload is `Bin`.
117 ptr_add,117 ptr_add,
118 /// Subtract an offset from a pointer, returning a new pointer.118 /// Subtract an offset from a pointer, returning a new pointer.
119 /// The offset is in element type units, not bytes.119 /// The offset is in element type units, not bytes.
120 /// Wrapping is undefined behavior.120 /// Wrapping is undefined behavior.
121 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.121 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
122 /// Uses the `bin_op` field.122 /// Uses the `ty_pl` field. Payload is `Bin`.
123 ptr_sub,123 ptr_sub,
124 /// Given two operands which can be floats, integers, or vectors, returns the124 /// Given two operands which can be floats, integers, or vectors, returns the
125 /// greater of the operands. For vectors it operates element-wise.125 /// greater of the operands. For vectors it operates element-wise.
...@@ -916,8 +916,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -916,8 +916,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
916 .bit_and,916 .bit_and,
917 .bit_or,917 .bit_or,
918 .xor,918 .xor,
919 .ptr_add,
920 .ptr_sub,
921 .shr,919 .shr,
922 .shr_exact,920 .shr_exact,
923 .shl,921 .shl,
...@@ -989,6 +987,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -989,6 +987,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
989 .sub_with_overflow,987 .sub_with_overflow,
990 .mul_with_overflow,988 .mul_with_overflow,
991 .shl_with_overflow,989 .shl_with_overflow,
990 .ptr_add,
991 .ptr_sub,
992 => return air.getRefType(datas[inst].ty_pl.ty),992 => return air.getRefType(datas[inst].ty_pl.ty),
993993
994 .not,994 .not,
src/Liveness.zig+16-15
...@@ -312,8 +312,6 @@ fn analyzeInst(...@@ -312,8 +312,6 @@ fn analyzeInst(
312 .div_exact,312 .div_exact,
313 .rem,313 .rem,
314 .mod,314 .mod,
315 .ptr_add,
316 .ptr_sub,
317 .bit_and,315 .bit_and,
318 .bit_or,316 .bit_or,
319 .xor,317 .xor,
...@@ -441,6 +439,21 @@ fn analyzeInst(...@@ -441,6 +439,21 @@ fn analyzeInst(
441 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });439 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
442 },440 },
443441
442 .add_with_overflow,
443 .sub_with_overflow,
444 .mul_with_overflow,
445 .shl_with_overflow,
446 .ptr_add,
447 .ptr_sub,
448 .ptr_elem_ptr,
449 .slice_elem_ptr,
450 .slice,
451 => {
452 const ty_pl = inst_datas[inst].ty_pl;
453 const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
454 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
455 },
456
444 .dbg_var_ptr,457 .dbg_var_ptr,
445 .dbg_var_val,458 .dbg_var_val,
446 => {459 => {
...@@ -529,10 +542,6 @@ fn analyzeInst(...@@ -529,10 +542,6 @@ fn analyzeInst(
529 const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data;542 const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data;
530 return trackOperands(a, new_set, inst, main_tomb, .{ extra.field_ptr, .none, .none });543 return trackOperands(a, new_set, inst, main_tomb, .{ extra.field_ptr, .none, .none });
531 },544 },
532 .ptr_elem_ptr, .slice_elem_ptr, .slice => {
533 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
534 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
535 },
536 .cmpxchg_strong, .cmpxchg_weak => {545 .cmpxchg_strong, .cmpxchg_weak => {
537 const extra = a.air.extraData(Air.Cmpxchg, inst_datas[inst].ty_pl.payload).data;546 const extra = a.air.extraData(Air.Cmpxchg, inst_datas[inst].ty_pl.payload).data;
538 return trackOperands(a, new_set, inst, main_tomb, .{ extra.ptr, extra.expected_value, extra.new_value });547 return trackOperands(a, new_set, inst, main_tomb, .{ extra.ptr, extra.expected_value, extra.new_value });
...@@ -558,15 +567,7 @@ fn analyzeInst(...@@ -558,15 +567,7 @@ fn analyzeInst(
558 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;567 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
559 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });568 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
560 },569 },
561 .add_with_overflow,570
562 .sub_with_overflow,
563 .mul_with_overflow,
564 .shl_with_overflow,
565 => {
566 const ty_pl = inst_datas[inst].ty_pl;
567 const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
568 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
569 },
570 .br => {571 .br => {
571 const br = inst_datas[inst].br;572 const br = inst_datas[inst].br;
572 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });573 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });
src/Sema.zig+123-42
...@@ -7020,22 +7020,25 @@ fn intCast(...@@ -7020,22 +7020,25 @@ fn intCast(
7020 operand_src: LazySrcLoc,7020 operand_src: LazySrcLoc,
7021 runtime_safety: bool,7021 runtime_safety: bool,
7022) CompileError!Air.Inst.Ref {7022) CompileError!Air.Inst.Ref {
7023 // TODO: Add support for vectors7023 const operand_ty = sema.typeOf(operand);
7024 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty);7024 const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src);
7025 _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));7025 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
70267026
7027 if (try sema.isComptimeKnown(block, operand_src, operand)) {7027 if (try sema.isComptimeKnown(block, operand_src, operand)) {
7028 return sema.coerce(block, dest_ty, operand, operand_src);7028 return sema.coerce(block, dest_ty, operand, operand_src);
7029 } else if (dest_is_comptime_int) {7029 } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) {
7030 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});7030 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
7031 }7031 }
70327032
7033 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
7034 const is_vector = dest_ty.zigTypeTag() == .Vector;
7035
7033 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {7036 if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| {
7034 // requirement: intCast(u0, input) iff input == 07037 // requirement: intCast(u0, input) iff input == 0
7035 if (runtime_safety and block.wantSafety()) {7038 if (runtime_safety and block.wantSafety()) {
7036 try sema.requireRuntimeBlock(block, operand_src);7039 try sema.requireRuntimeBlock(block, operand_src);
7037 const target = sema.mod.getTarget();7040 const target = sema.mod.getTarget();
7038 const wanted_info = dest_ty.intInfo(target);7041 const wanted_info = dest_scalar_ty.intInfo(target);
7039 const wanted_bits = wanted_info.bits;7042 const wanted_bits = wanted_info.bits;
70407043
7041 if (wanted_bits == 0) {7044 if (wanted_bits == 0) {
...@@ -7051,9 +7054,8 @@ fn intCast(...@@ -7051,9 +7054,8 @@ fn intCast(
7051 try sema.requireRuntimeBlock(block, operand_src);7054 try sema.requireRuntimeBlock(block, operand_src);
7052 if (runtime_safety and block.wantSafety()) {7055 if (runtime_safety and block.wantSafety()) {
7053 const target = sema.mod.getTarget();7056 const target = sema.mod.getTarget();
7054 const operand_ty = sema.typeOf(operand);7057 const actual_info = operand_scalar_ty.intInfo(target);
7055 const actual_info = operand_ty.intInfo(target);7058 const wanted_info = dest_scalar_ty.intInfo(target);
7056 const wanted_info = dest_ty.intInfo(target);
7057 const actual_bits = actual_info.bits;7059 const actual_bits = actual_info.bits;
7058 const wanted_bits = wanted_info.bits;7060 const wanted_bits = wanted_info.bits;
7059 const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed);7061 const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed);
...@@ -7062,7 +7064,11 @@ fn intCast(...@@ -7062,7 +7064,11 @@ fn intCast(
7062 // range shrinkage7064 // range shrinkage
7063 // requirement: int value fits into target type7065 // requirement: int value fits into target type
7064 if (wanted_value_bits < actual_value_bits) {7066 if (wanted_value_bits < actual_value_bits) {
7065 const dest_max_val = try dest_ty.maxInt(sema.arena, target);7067 const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target);
7068 const dest_max_val = if (is_vector)
7069 try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar)
7070 else
7071 dest_max_val_scalar;
7066 const dest_max = try sema.addConstant(operand_ty, dest_max_val);7072 const dest_max = try sema.addConstant(operand_ty, dest_max_val);
7067 const diff = try block.addBinOp(.subwrap, dest_max, operand);7073 const diff = try block.addBinOp(.subwrap, dest_max, operand);
70687074
...@@ -7080,19 +7086,59 @@ fn intCast(...@@ -7080,19 +7086,59 @@ fn intCast(
7080 } else dest_max_val;7086 } else dest_max_val;
7081 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);7087 const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
70827088
7083 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);7089 const ok = if (is_vector) ok: {
7084 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);7090 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
7091 const all_in_range = try block.addInst(.{
7092 .tag = .reduce,
7093 .data = .{ .reduce = .{
7094 .operand = is_in_range,
7095 .operation = .And,
7096 } },
7097 });
7098 break :ok all_in_range;
7099 } else ok: {
7100 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
7101 break :ok is_in_range;
7102 };
7103 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
7085 } else {7104 } else {
7086 const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max);7105 const ok = if (is_vector) ok: {
7087 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);7106 const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
7107 const all_in_range = try block.addInst(.{
7108 .tag = .reduce,
7109 .data = .{ .reduce = .{
7110 .operand = is_in_range,
7111 .operation = .And,
7112 } },
7113 });
7114 break :ok all_in_range;
7115 } else ok: {
7116 const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max);
7117 break :ok is_in_range;
7118 };
7119 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
7088 }7120 }
7089 }7121 } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {
7090 // no shrinkage, yes sign loss7122 // no shrinkage, yes sign loss
7091 // requirement: signed to unsigned >= 07123 // requirement: signed to unsigned >= 0
7092 else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {7124 const ok = if (is_vector) ok: {
7093 const zero_inst = try sema.addConstant(operand_ty, Value.zero);7125 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
7094 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);7126 const zero_inst = try sema.addConstant(operand_ty, zero_val);
7095 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);7127 const is_in_range = try block.addCmpVector(operand, zero_inst, .lte, try sema.addType(operand_ty));
7128 const all_in_range = try block.addInst(.{
7129 .tag = .reduce,
7130 .data = .{ .reduce = .{
7131 .operand = is_in_range,
7132 .operation = .And,
7133 } },
7134 });
7135 break :ok all_in_range;
7136 } else ok: {
7137 const zero_inst = try sema.addConstant(operand_ty, Value.zero);
7138 const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
7139 break :ok is_in_range;
7140 };
7141 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
7096 }7142 }
7097 }7143 }
7098 return block.addTyOp(.intcast, dest_ty, operand);7144 return block.addTyOp(.intcast, dest_ty, operand);
...@@ -10610,28 +10656,55 @@ fn analyzePtrArithmetic(...@@ -10610,28 +10656,55 @@ fn analyzePtrArithmetic(
10610 // TODO if the operand is comptime-known to be negative, or is a negative int,10656 // TODO if the operand is comptime-known to be negative, or is a negative int,
10611 // coerce to isize instead of usize.10657 // coerce to isize instead of usize.
10612 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);10658 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
10613 // TODO adjust the return type according to alignment and other factors
10614 const target = sema.mod.getTarget();10659 const target = sema.mod.getTarget();
10615 const runtime_src = rs: {10660 const opt_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, ptr);
10616 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {10661 const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset);
10617 if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| {10662 const ptr_ty = sema.typeOf(ptr);
10618 const ptr_ty = sema.typeOf(ptr);10663 const ptr_info = ptr_ty.ptrInfo().data;
10619 const new_ptr_ty = ptr_ty; // TODO modify alignment10664 const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array)
10665 ptr_info.pointee_type.childType()
10666 else
10667 ptr_info.pointee_type;
10668
10669 const new_ptr_ty = t: {
10670 // Calculate the new pointer alignment.
10671 if (ptr_info.@"align" == 0) {
10672 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
10673 break :t ptr_ty;
10674 }
10675 // If the addend is not a comptime-known value we can still count on
10676 // it being a multiple of the type size.
10677 const elem_size = elem_ty.abiSize(target);
10678 const addend = if (opt_off_val) |off_val| a: {
10679 const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target));
10680 break :a elem_size * off_int;
10681 } else elem_size;
10682
10683 // The resulting pointer is aligned to the lcd between the offset (an
10684 // arbitrary number) and the alignment factor (always a power of two,
10685 // non zero).
10686 const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, addend | ptr_info.@"align"));
10687
10688 break :t try Type.ptr(sema.arena, sema.mod, .{
10689 .pointee_type = ptr_info.pointee_type,
10690 .sentinel = ptr_info.sentinel,
10691 .@"align" = new_align,
10692 .@"addrspace" = ptr_info.@"addrspace",
10693 .mutable = ptr_info.mutable,
10694 .@"allowzero" = ptr_info.@"allowzero",
10695 .@"volatile" = ptr_info.@"volatile",
10696 .size = ptr_info.size,
10697 });
10698 };
1062010699
10621 if (ptr_val.isUndef() or offset_val.isUndef()) {10700 const runtime_src = rs: {
10622 return sema.addConstUndef(new_ptr_ty);10701 if (opt_ptr_val) |ptr_val| {
10623 }10702 if (opt_off_val) |offset_val| {
10703 if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty);
1062410704
10625 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));10705 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));
10626 // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons
10627 if (offset_int == 0) return ptr;10706 if (offset_int == 0) return ptr;
10628 if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| {10707 if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| {
10629 const ptr_child_ty = ptr_ty.childType();
10630 const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array)
10631 ptr_child_ty.childType()
10632 else
10633 ptr_child_ty;
10634
10635 const elem_size = elem_ty.abiSize(target);10708 const elem_size = elem_ty.abiSize(target);
10636 const new_addr = switch (air_tag) {10709 const new_addr = switch (air_tag) {
10637 .ptr_add => addr + elem_size * offset_int,10710 .ptr_add => addr + elem_size * offset_int,
...@@ -10651,7 +10724,16 @@ fn analyzePtrArithmetic(...@@ -10651,7 +10724,16 @@ fn analyzePtrArithmetic(
10651 };10724 };
1065210725
10653 try sema.requireRuntimeBlock(block, runtime_src);10726 try sema.requireRuntimeBlock(block, runtime_src);
10654 return block.addBinOp(air_tag, ptr, offset);10727 return block.addInst(.{
10728 .tag = air_tag,
10729 .data = .{ .ty_pl = .{
10730 .ty = try sema.addType(new_ptr_ty),
10731 .payload = try sema.addExtra(Air.Bin{
10732 .lhs = ptr,
10733 .rhs = offset,
10734 }),
10735 } },
10736 });
10655}10737}
1065610738
10657fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10739fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -14481,8 +14563,8 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14481,8 +14563,8 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14481 const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);14563 const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
14482 const operand = sema.resolveInst(extra.rhs);14564 const operand = sema.resolveInst(extra.rhs);
14483 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);14565 const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);
14484 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src);
14485 const operand_ty = sema.typeOf(operand);14566 const operand_ty = sema.typeOf(operand);
14567 const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
14486 const is_vector = operand_ty.zigTypeTag() == .Vector;14568 const is_vector = operand_ty.zigTypeTag() == .Vector;
14487 const dest_ty = if (is_vector)14569 const dest_ty = if (is_vector)
14488 try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty)14570 try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty)
...@@ -14650,7 +14732,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14650,7 +14732,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14650 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };14732 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
14651 const operand = sema.resolveInst(inst_data.operand);14733 const operand = sema.resolveInst(inst_data.operand);
14652 const operand_ty = sema.typeOf(operand);14734 const operand_ty = sema.typeOf(operand);
14653 const scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src);14735 const scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
14654 const target = sema.mod.getTarget();14736 const target = sema.mod.getTarget();
14655 const bits = scalar_ty.intInfo(target).bits;14737 const bits = scalar_ty.intInfo(target).bits;
14656 if (bits % 8 != 0) {14738 if (bits % 8 != 0) {
...@@ -14707,7 +14789,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -14707,7 +14789,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
14707 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };14789 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
14708 const operand = sema.resolveInst(inst_data.operand);14790 const operand = sema.resolveInst(inst_data.operand);
14709 const operand_ty = sema.typeOf(operand);14791 const operand_ty = sema.typeOf(operand);
14710 _ = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src);14792 _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
1471114793
14712 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {14794 if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| {
14713 return sema.addConstant(operand_ty, val);14795 return sema.addConstant(operand_ty, val);
...@@ -15059,10 +15141,9 @@ fn checkIntOrVector(...@@ -15059,10 +15141,9 @@ fn checkIntOrVector(
15059fn checkIntOrVectorAllowComptime(15141fn checkIntOrVectorAllowComptime(
15060 sema: *Sema,15142 sema: *Sema,
15061 block: *Block,15143 block: *Block,
15062 operand: Air.Inst.Ref,15144 operand_ty: Type,
15063 operand_src: LazySrcLoc,15145 operand_src: LazySrcLoc,
15064) CompileError!Type {15146) CompileError!Type {
15065 const operand_ty = sema.typeOf(operand);
15066 switch (try operand_ty.zigTypeTagOrPoison()) {15147 switch (try operand_ty.zigTypeTagOrPoison()) {
15067 .Int, .ComptimeInt => return operand_ty,15148 .Int, .ComptimeInt => return operand_ty,
15068 .Vector => {15149 .Vector => {
src/arch/aarch64/CodeGen.zig+98-68
...@@ -545,18 +545,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -545,18 +545,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
545545
546 switch (air_tags[inst]) {546 switch (air_tags[inst]) {
547 // zig fmt: off547 // zig fmt: off
548 .add, .ptr_add => try self.airBinOp(inst),548 .add => try self.airBinOp(inst, .add),
549 .addwrap => try self.airBinOp(inst),549 .addwrap => try self.airBinOp(inst, .addwrap),
550 .sub => try self.airBinOp(inst, .sub),
551 .subwrap => try self.airBinOp(inst, .subwrap),
552 .mul => try self.airBinOp(inst, .mul),
553 .mulwrap => try self.airBinOp(inst, .mulwrap),
554 .shl => try self.airBinOp(inst, .shl),
555 .shl_exact => try self.airBinOp(inst, .shl_exact),
556 .bool_and => try self.airBinOp(inst, .bool_and),
557 .bool_or => try self.airBinOp(inst, .bool_or),
558 .bit_and => try self.airBinOp(inst, .bit_and),
559 .bit_or => try self.airBinOp(inst, .bit_or),
560 .xor => try self.airBinOp(inst, .xor),
561 .shr => try self.airBinOp(inst, .shr),
562 .shr_exact => try self.airBinOp(inst, .shr_exact),
563
564 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
565 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
566
550 .add_sat => try self.airAddSat(inst),567 .add_sat => try self.airAddSat(inst),
551 .sub, .ptr_sub => try self.airBinOp(inst),
552 .subwrap => try self.airBinOp(inst),
553 .sub_sat => try self.airSubSat(inst),568 .sub_sat => try self.airSubSat(inst),
554 .mul => try self.airBinOp(inst),
555 .mulwrap => try self.airBinOp(inst),
556 .mul_sat => try self.airMulSat(inst),569 .mul_sat => try self.airMulSat(inst),
557 .rem => try self.airRem(inst),570 .rem => try self.airRem(inst),
558 .mod => try self.airMod(inst),571 .mod => try self.airMod(inst),
559 .shl, .shl_exact => try self.airBinOp(inst),
560 .shl_sat => try self.airShlSat(inst),572 .shl_sat => try self.airShlSat(inst),
561 .min => try self.airMin(inst),573 .min => try self.airMin(inst),
562 .max => try self.airMax(inst),574 .max => try self.airMax(inst),
...@@ -595,13 +607,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -595,13 +607,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
595 .cmp_vector => try self.airCmpVector(inst),607 .cmp_vector => try self.airCmpVector(inst),
596 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),608 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
597609
598 .bool_and => try self.airBinOp(inst),
599 .bool_or => try self.airBinOp(inst),
600 .bit_and => try self.airBinOp(inst),
601 .bit_or => try self.airBinOp(inst),
602 .xor => try self.airBinOp(inst),
603 .shr, .shr_exact => try self.airBinOp(inst),
604
605 .alloc => try self.airAlloc(inst),610 .alloc => try self.airAlloc(inst),
606 .ret_ptr => try self.airRetPtr(inst),611 .ret_ptr => try self.airRetPtr(inst),
607 .arg => try self.airArg(inst),612 .arg => try self.airArg(inst),
...@@ -1260,11 +1265,11 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1260,11 +1265,11 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1260fn binOpRegister(1265fn binOpRegister(
1261 self: *Self,1266 self: *Self,
1262 mir_tag: Mir.Inst.Tag,1267 mir_tag: Mir.Inst.Tag,
1263 maybe_inst: ?Air.Inst.Index,
1264 lhs: MCValue,1268 lhs: MCValue,
1265 rhs: MCValue,1269 rhs: MCValue,
1266 lhs_ty: Type,1270 lhs_ty: Type,
1267 rhs_ty: Type,1271 rhs_ty: Type,
1272 metadata: ?BinOpMetadata,
1268) !MCValue {1273) !MCValue {
1269 const lhs_is_register = lhs == .register;1274 const lhs_is_register = lhs == .register;
1270 const rhs_is_register = rhs == .register;1275 const rhs_is_register = rhs == .register;
...@@ -1284,9 +1289,8 @@ fn binOpRegister(...@@ -1284,9 +1289,8 @@ fn binOpRegister(
1284 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1289 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
12851290
1286 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1291 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1287 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1292 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1288 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1293 break :inst Air.refToIndex(md.lhs).?;
1289 break :inst Air.refToIndex(bin_op.lhs).?;
1290 } else null;1294 } else null;
12911295
1292 const raw_reg = try self.register_manager.allocReg(track_inst);1296 const raw_reg = try self.register_manager.allocReg(track_inst);
...@@ -1300,9 +1304,8 @@ fn binOpRegister(...@@ -1300,9 +1304,8 @@ fn binOpRegister(
1300 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1304 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
13011305
1302 const rhs_reg = if (rhs_is_register) rhs.register else blk: {1306 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1303 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1307 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1304 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1308 break :inst Air.refToIndex(md.rhs).?;
1305 break :inst Air.refToIndex(bin_op.rhs).?;
1306 } else null;1309 } else null;
13071310
1308 const raw_reg = try self.register_manager.allocReg(track_inst);1311 const raw_reg = try self.register_manager.allocReg(track_inst);
...@@ -1317,15 +1320,13 @@ fn binOpRegister(...@@ -1317,15 +1320,13 @@ fn binOpRegister(
13171320
1318 const dest_reg = switch (mir_tag) {1321 const dest_reg = switch (mir_tag) {
1319 .cmp_shifted_register => undefined, // cmp has no destination register1322 .cmp_shifted_register => undefined, // cmp has no destination register
1320 else => if (maybe_inst) |inst| blk: {1323 else => if (metadata) |md| blk: {
1321 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1324 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
1322
1323 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1324 break :blk lhs_reg;1325 break :blk lhs_reg;
1325 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1326 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1326 break :blk rhs_reg;1327 break :blk rhs_reg;
1327 } else {1328 } else {
1328 const raw_reg = try self.register_manager.allocReg(inst);1329 const raw_reg = try self.register_manager.allocReg(md.inst);
1329 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1330 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1330 }1331 }
1331 } else blk: {1332 } else blk: {
...@@ -1407,11 +1408,11 @@ fn binOpRegister(...@@ -1407,11 +1408,11 @@ fn binOpRegister(
1407fn binOpImmediate(1408fn binOpImmediate(
1408 self: *Self,1409 self: *Self,
1409 mir_tag: Mir.Inst.Tag,1410 mir_tag: Mir.Inst.Tag,
1410 maybe_inst: ?Air.Inst.Index,
1411 lhs: MCValue,1411 lhs: MCValue,
1412 rhs: MCValue,1412 rhs: MCValue,
1413 lhs_ty: Type,1413 lhs_ty: Type,
1414 lhs_and_rhs_swapped: bool,1414 lhs_and_rhs_swapped: bool,
1415 metadata: ?BinOpMetadata,
1415) !MCValue {1416) !MCValue {
1416 const lhs_is_register = lhs == .register;1417 const lhs_is_register = lhs == .register;
14171418
...@@ -1424,10 +1425,9 @@ fn binOpImmediate(...@@ -1424,10 +1425,9 @@ fn binOpImmediate(
1424 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1425 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
14251426
1426 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1427 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1427 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1428 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1428 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1429 break :inst Air.refToIndex(1429 break :inst Air.refToIndex(
1430 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1430 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1431 ).?;1431 ).?;
1432 } else null;1432 } else null;
14331433
...@@ -1443,18 +1443,16 @@ fn binOpImmediate(...@@ -1443,18 +1443,16 @@ fn binOpImmediate(
14431443
1444 const dest_reg = switch (mir_tag) {1444 const dest_reg = switch (mir_tag) {
1445 .cmp_immediate => undefined, // cmp has no destination register1445 .cmp_immediate => undefined, // cmp has no destination register
1446 else => if (maybe_inst) |inst| blk: {1446 else => if (metadata) |md| blk: {
1447 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1448
1449 if (lhs_is_register and self.reuseOperand(1447 if (lhs_is_register and self.reuseOperand(
1450 inst,1448 md.inst,
1451 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1449 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1452 if (lhs_and_rhs_swapped) 1 else 0,1450 if (lhs_and_rhs_swapped) 1 else 0,
1453 lhs,1451 lhs,
1454 )) {1452 )) {
1455 break :blk lhs_reg;1453 break :blk lhs_reg;
1456 } else {1454 } else {
1457 const raw_reg = try self.register_manager.allocReg(inst);1455 const raw_reg = try self.register_manager.allocReg(md.inst);
1458 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1456 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1459 }1457 }
1460 } else blk: {1458 } else blk: {
...@@ -1498,6 +1496,12 @@ fn binOpImmediate(...@@ -1498,6 +1496,12 @@ fn binOpImmediate(
1498 return MCValue{ .register = dest_reg };1496 return MCValue{ .register = dest_reg };
1499}1497}
15001498
1499const BinOpMetadata = struct {
1500 inst: Air.Inst.Index,
1501 lhs: Air.Inst.Ref,
1502 rhs: Air.Inst.Ref,
1503};
1504
1501/// For all your binary operation needs, this function will generate1505/// For all your binary operation needs, this function will generate
1502/// the corresponding Mir instruction(s). Returns the location of the1506/// the corresponding Mir instruction(s). Returns the location of the
1503/// result.1507/// result.
...@@ -1513,11 +1517,11 @@ fn binOpImmediate(...@@ -1513,11 +1517,11 @@ fn binOpImmediate(
1513fn binOp(1517fn binOp(
1514 self: *Self,1518 self: *Self,
1515 tag: Air.Inst.Tag,1519 tag: Air.Inst.Tag,
1516 maybe_inst: ?Air.Inst.Index,
1517 lhs: MCValue,1520 lhs: MCValue,
1518 rhs: MCValue,1521 rhs: MCValue,
1519 lhs_ty: Type,1522 lhs_ty: Type,
1520 rhs_ty: Type,1523 rhs_ty: Type,
1524 metadata: ?BinOpMetadata,
1521) InnerError!MCValue {1525) InnerError!MCValue {
1522 const mod = self.bin_file.options.module.?;1526 const mod = self.bin_file.options.module.?;
1523 switch (tag) {1527 switch (tag) {
...@@ -1562,12 +1566,12 @@ fn binOp(...@@ -1562,12 +1566,12 @@ fn binOp(
1562 };1566 };
15631567
1564 if (rhs_immediate_ok) {1568 if (rhs_immediate_ok) {
1565 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);1569 return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata);
1566 } else if (lhs_immediate_ok) {1570 } else if (lhs_immediate_ok) {
1567 // swap lhs and rhs1571 // swap lhs and rhs
1568 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, rhs, lhs, rhs_ty, true);1572 return try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, metadata);
1569 } else {1573 } else {
1570 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1574 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1571 }1575 }
1572 } else {1576 } else {
1573 return self.fail("TODO binary operations on int with bits > 64", .{});1577 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1586,7 +1590,7 @@ fn binOp(...@@ -1586,7 +1590,7 @@ fn binOp(
1586 // TODO add optimisations for multiplication1590 // TODO add optimisations for multiplication
1587 // with immediates, for example a * 2 can be1591 // with immediates, for example a * 2 can be
1588 // lowered to a << 11592 // lowered to a << 1
1589 return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1593 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
1590 } else {1594 } else {
1591 return self.fail("TODO binary operations on int with bits > 64", .{});1595 return self.fail("TODO binary operations on int with bits > 64", .{});
1592 }1596 }
...@@ -1606,7 +1610,7 @@ fn binOp(...@@ -1606,7 +1610,7 @@ fn binOp(
1606 };1610 };
16071611
1608 // Generate an add/sub/mul1612 // Generate an add/sub/mul
1609 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1613 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
16101614
1611 // Truncate if necessary1615 // Truncate if necessary
1612 switch (lhs_ty.zigTypeTag()) {1616 switch (lhs_ty.zigTypeTag()) {
...@@ -1642,7 +1646,7 @@ fn binOp(...@@ -1642,7 +1646,7 @@ fn binOp(
1642 else => unreachable,1646 else => unreachable,
1643 };1647 };
16441648
1645 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1649 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1646 } else {1650 } else {
1647 return self.fail("TODO binary operations on int with bits > 64", .{});1651 return self.fail("TODO binary operations on int with bits > 64", .{});
1648 }1652 }
...@@ -1678,9 +1682,9 @@ fn binOp(...@@ -1678,9 +1682,9 @@ fn binOp(
1678 };1682 };
16791683
1680 if (rhs_immediate_ok) {1684 if (rhs_immediate_ok) {
1681 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);1685 return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata);
1682 } else {1686 } else {
1683 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1687 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1684 }1688 }
1685 } else {1689 } else {
1686 return self.fail("TODO binary operations on int with bits > 64", .{});1690 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1699,7 +1703,7 @@ fn binOp(...@@ -1699,7 +1703,7 @@ fn binOp(
1699 };1703 };
17001704
1701 // Generate a shl_exact/shr_exact1705 // Generate a shl_exact/shr_exact
1702 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1706 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
17031707
1704 // Truncate if necessary1708 // Truncate if necessary
1705 switch (tag) {1709 switch (tag) {
...@@ -1735,7 +1739,7 @@ fn binOp(...@@ -1735,7 +1739,7 @@ fn binOp(
1735 else => unreachable,1739 else => unreachable,
1736 };1740 };
17371741
1738 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1742 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1739 },1743 },
1740 else => unreachable,1744 else => unreachable,
1741 }1745 }
...@@ -1759,12 +1763,12 @@ fn binOp(...@@ -1759,12 +1763,12 @@ fn binOp(
1759 else => unreachable,1763 else => unreachable,
1760 };1764 };
17611765
1762 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1766 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1763 } else {1767 } else {
1764 // convert the offset into a byte offset by1768 // convert the offset into a byte offset by
1765 // multiplying it with elem_size1769 // multiplying it with elem_size
1766 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);1770 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
1767 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);1771 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
1768 return addr;1772 return addr;
1769 }1773 }
1770 },1774 },
...@@ -1775,8 +1779,7 @@ fn binOp(...@@ -1775,8 +1779,7 @@ fn binOp(
1775 }1779 }
1776}1780}
17771781
1778fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1782fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1779 const tag = self.air.instructions.items(.tag)[inst];
1780 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1783 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1781 const lhs = try self.resolveInst(bin_op.lhs);1784 const lhs = try self.resolveInst(bin_op.lhs);
1782 const rhs = try self.resolveInst(bin_op.rhs);1785 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -1786,7 +1789,30 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1786,7 +1789,30 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1786 const result: MCValue = if (self.liveness.isUnused(inst))1789 const result: MCValue = if (self.liveness.isUnused(inst))
1787 .dead1790 .dead
1788 else1791 else
1789 try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1792 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1793 .inst = inst,
1794 .lhs = bin_op.lhs,
1795 .rhs = bin_op.rhs,
1796 });
1797 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1798}
1799
1800fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1801 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1802 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1803 const lhs = try self.resolveInst(bin_op.lhs);
1804 const rhs = try self.resolveInst(bin_op.rhs);
1805 const lhs_ty = self.air.typeOf(bin_op.lhs);
1806 const rhs_ty = self.air.typeOf(bin_op.rhs);
1807
1808 const result: MCValue = if (self.liveness.isUnused(inst))
1809 .dead
1810 else
1811 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1812 .inst = inst,
1813 .lhs = bin_op.lhs,
1814 .rhs = bin_op.rhs,
1815 });
1790 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1816 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1791}1817}
17921818
...@@ -1841,7 +1867,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1841,7 +1867,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1841 .sub_with_overflow => .sub,1867 .sub_with_overflow => .sub,
1842 else => unreachable,1868 else => unreachable,
1843 };1869 };
1844 const dest = try self.binOp(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1870 const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1845 const dest_reg = dest.register;1871 const dest_reg = dest.register;
1846 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1872 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1847 defer self.register_manager.unlockReg(dest_reg_lock);1873 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1855,7 +1881,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1855,7 +1881,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1855 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1881 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
18561882
1857 // cmp dest, truncated1883 // cmp dest, truncated
1858 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1884 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
18591885
1860 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1886 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1861 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1887 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1894,12 +1920,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1894,12 +1920,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18941920
1895 const dest = blk: {1921 const dest = blk: {
1896 if (rhs_immediate_ok) {1922 if (rhs_immediate_ok) {
1897 break :blk try self.binOpImmediate(mir_tag_immediate, null, lhs, rhs, lhs_ty, false);1923 break :blk try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, null);
1898 } else if (lhs_immediate_ok) {1924 } else if (lhs_immediate_ok) {
1899 // swap lhs and rhs1925 // swap lhs and rhs
1900 break :blk try self.binOpImmediate(mir_tag_immediate, null, rhs, lhs, rhs_ty, true);1926 break :blk try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, null);
1901 } else {1927 } else {
1902 break :blk try self.binOpRegister(mir_tag_register, null, lhs, rhs, lhs_ty, rhs_ty);1928 break :blk try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, null);
1903 }1929 }
1904 };1930 };
19051931
...@@ -1952,7 +1978,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1952,7 +1978,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1952 .unsigned => .umull,1978 .unsigned => .umull,
1953 };1979 };
19541980
1955 const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1981 const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1956 const dest_reg = dest.register;1982 const dest_reg = dest.register;
1957 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1983 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1958 defer self.register_manager.unlockReg(dest_reg_lock);1984 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -2136,11 +2162,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2136,11 +2162,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21362162
2137 _ = try self.binOp(2163 _ = try self.binOp(
2138 .cmp_eq,2164 .cmp_eq,
2139 null,
2140 .{ .register = dest_high_reg },2165 .{ .register = dest_high_reg },
2141 .{ .immediate = 0 },2166 .{ .immediate = 0 },
2142 Type.usize,2167 Type.usize,
2143 Type.usize,2168 Type.usize,
2169 null,
2144 );2170 );
21452171
2146 if (int_info.bits < 64) {2172 if (int_info.bits < 64) {
...@@ -2156,11 +2182,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2156,11 +2182,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21562182
2157 _ = try self.binOp(2183 _ = try self.binOp(
2158 .cmp_eq,2184 .cmp_eq,
2159 null,
2160 .{ .register = dest_high_reg },2185 .{ .register = dest_high_reg },
2161 .{ .immediate = 0 },2186 .{ .immediate = 0 },
2162 Type.usize,2187 Type.usize,
2163 Type.usize,2188 Type.usize,
2189 null,
2164 );2190 );
2165 }2191 }
2166 },2192 },
...@@ -2218,16 +2244,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2218,16 +2244,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2218 self.compare_flags_inst = null;2244 self.compare_flags_inst = null;
22192245
2220 // lsl dest, lhs, rhs2246 // lsl dest, lhs, rhs
2221 const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty);2247 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
2222 const dest_reg = dest.register;2248 const dest_reg = dest.register;
2223 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);2249 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
2224 defer self.register_manager.unlockReg(dest_reg_lock);2250 defer self.register_manager.unlockReg(dest_reg_lock);
22252251
2226 // asr/lsr reconstructed, dest, rhs2252 // asr/lsr reconstructed, dest, rhs
2227 const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty);2253 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
22282254
2229 // cmp lhs, reconstructed2255 // cmp lhs, reconstructed
2230 _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty);2256 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
22312257
2232 try self.genSetStack(lhs_ty, stack_offset, dest);2258 try self.genSetStack(lhs_ty, stack_offset, dest);
2233 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{2259 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
...@@ -2489,7 +2515,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2489,7 +2515,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2489 switch (elem_size) {2515 switch (elem_size) {
2490 else => {2516 else => {
2491 const dest = try self.allocRegOrMem(inst, true);2517 const dest = try self.allocRegOrMem(inst, true);
2492 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);2518 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2493 try self.load(dest, addr, slice_ptr_field_type);2519 try self.load(dest, addr, slice_ptr_field_type);
24942520
2495 break :result dest;2521 break :result dest;
...@@ -2933,11 +2959,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2933,11 +2959,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
29332959
2934 const dest = try self.binOp(2960 const dest = try self.binOp(
2935 .add,2961 .add,
2936 null,
2937 .{ .register = addr_reg },2962 .{ .register = addr_reg },
2938 .{ .register = offset_reg },2963 .{ .register = offset_reg },
2939 Type.usize,2964 Type.usize,
2940 Type.usize,2965 Type.usize,
2966 null,
2941 );2967 );
29422968
2943 break :result dest;2969 break :result dest;
...@@ -3302,7 +3328,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3302,7 +3328,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
33023328
3303 const int_info = int_ty.intInfo(self.target.*);3329 const int_info = int_ty.intInfo(self.target.*);
3304 if (int_info.bits <= 64) {3330 if (int_info.bits <= 64) {
3305 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);3331 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
3332 .inst = inst,
3333 .lhs = bin_op.lhs,
3334 .rhs = bin_op.rhs,
3335 });
33063336
3307 try self.spillCompareFlagsIfOccupied();3337 try self.spillCompareFlagsIfOccupied();
3308 self.compare_flags_inst = inst;3338 self.compare_flags_inst = inst;
src/arch/arm/CodeGen.zig+113-79
...@@ -552,21 +552,34 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -552,21 +552,34 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
552552
553 switch (air_tags[inst]) {553 switch (air_tags[inst]) {
554 // zig fmt: off554 // zig fmt: off
555 .add, .ptr_add => try self.airBinOp(inst),555 .add, => try self.airBinOp(inst, .add),
556 .addwrap => try self.airBinOp(inst),556 .addwrap => try self.airBinOp(inst, .addwrap),
557 .sub, => try self.airBinOp(inst, .sub),
558 .subwrap => try self.airBinOp(inst, .subwrap),
559 .mul => try self.airBinOp(inst, .mul),
560 .mulwrap => try self.airBinOp(inst, .mulwrap),
561 .shl => try self.airBinOp(inst, .shl),
562 .shl_exact => try self.airBinOp(inst, .shl_exact),
563 .bool_and => try self.airBinOp(inst, .bool_and),
564 .bool_or => try self.airBinOp(inst, .bool_or),
565 .bit_and => try self.airBinOp(inst, .bit_and),
566 .bit_or => try self.airBinOp(inst, .bit_or),
567 .xor => try self.airBinOp(inst, .xor),
568 .shr => try self.airBinOp(inst, .shr),
569 .shr_exact => try self.airBinOp(inst, .shr_exact),
570
571 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
572 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
573
574 .min => try self.airMinMax(inst),
575 .max => try self.airMinMax(inst),
576
557 .add_sat => try self.airAddSat(inst),577 .add_sat => try self.airAddSat(inst),
558 .sub, .ptr_sub => try self.airBinOp(inst),
559 .subwrap => try self.airBinOp(inst),
560 .sub_sat => try self.airSubSat(inst),578 .sub_sat => try self.airSubSat(inst),
561 .mul => try self.airBinOp(inst),
562 .mulwrap => try self.airBinOp(inst),
563 .mul_sat => try self.airMulSat(inst),579 .mul_sat => try self.airMulSat(inst),
564 .rem => try self.airRem(inst),580 .rem => try self.airRem(inst),
565 .mod => try self.airMod(inst),581 .mod => try self.airMod(inst),
566 .shl, .shl_exact => try self.airBinOp(inst),
567 .shl_sat => try self.airShlSat(inst),582 .shl_sat => try self.airShlSat(inst),
568 .min => try self.airMinMax(inst),
569 .max => try self.airMinMax(inst),
570 .slice => try self.airSlice(inst),583 .slice => try self.airSlice(inst),
571584
572 .sqrt,585 .sqrt,
...@@ -602,13 +615,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -602,13 +615,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
602 .cmp_vector => try self.airCmpVector(inst),615 .cmp_vector => try self.airCmpVector(inst),
603 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),616 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
604617
605 .bool_and => try self.airBinOp(inst),
606 .bool_or => try self.airBinOp(inst),
607 .bit_and => try self.airBinOp(inst),
608 .bit_or => try self.airBinOp(inst),
609 .xor => try self.airBinOp(inst),
610 .shr, .shr_exact => try self.airBinOp(inst),
611
612 .alloc => try self.airAlloc(inst),618 .alloc => try self.airAlloc(inst),
613 .ret_ptr => try self.airRetPtr(inst),619 .ret_ptr => try self.airRetPtr(inst),
614 .arg => try self.airArg(inst),620 .arg => try self.airArg(inst),
...@@ -1260,7 +1266,7 @@ fn minMax(...@@ -1260,7 +1266,7 @@ fn minMax(
1260 // register.1266 // register.
1261 assert(lhs_reg != rhs_reg); // see note above1267 assert(lhs_reg != rhs_reg); // see note above
12621268
1263 _ = try self.binOpRegister(.cmp, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty);1269 _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null);
12641270
1265 const cond_choose_lhs: Condition = switch (tag) {1271 const cond_choose_lhs: Condition = switch (tag) {
1266 .max => switch (int_info.signedness) {1272 .max => switch (int_info.signedness) {
...@@ -1340,15 +1346,40 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1340,15 +1346,40 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1340 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1346 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1341}1347}
13421348
1343fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1349fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1344 const tag = self.air.instructions.items(.tag)[inst];
1345 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1350 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1346 const lhs = try self.resolveInst(bin_op.lhs);1351 const lhs = try self.resolveInst(bin_op.lhs);
1347 const rhs = try self.resolveInst(bin_op.rhs);1352 const rhs = try self.resolveInst(bin_op.rhs);
1348 const lhs_ty = self.air.typeOf(bin_op.lhs);1353 const lhs_ty = self.air.typeOf(bin_op.lhs);
1349 const rhs_ty = self.air.typeOf(bin_op.rhs);1354 const rhs_ty = self.air.typeOf(bin_op.rhs);
13501355
1351 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1356 const result: MCValue = if (self.liveness.isUnused(inst))
1357 .dead
1358 else
1359 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1360 .lhs = bin_op.lhs,
1361 .rhs = bin_op.rhs,
1362 .inst = inst,
1363 });
1364 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1365}
1366
1367fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1368 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1369 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1370 const lhs = try self.resolveInst(bin_op.lhs);
1371 const rhs = try self.resolveInst(bin_op.rhs);
1372 const lhs_ty = self.air.typeOf(bin_op.lhs);
1373 const rhs_ty = self.air.typeOf(bin_op.rhs);
1374
1375 const result: MCValue = if (self.liveness.isUnused(inst))
1376 .dead
1377 else
1378 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1379 .lhs = bin_op.lhs,
1380 .rhs = bin_op.rhs,
1381 .inst = inst,
1382 });
1352 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1383 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1353}1384}
13541385
...@@ -1402,7 +1433,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1402,7 +1433,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1402 .sub_with_overflow => .sub,1433 .sub_with_overflow => .sub,
1403 else => unreachable,1434 else => unreachable,
1404 };1435 };
1405 const dest = try self.binOp(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1436 const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1406 const dest_reg = dest.register;1437 const dest_reg = dest.register;
1407 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1438 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1408 defer self.register_manager.unlockReg(dest_reg_lock);1439 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1415,7 +1446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1415,7 +1446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1415 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1446 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
14161447
1417 // cmp dest, truncated1448 // cmp dest, truncated
1418 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1449 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
14191450
1420 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1451 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1421 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1452 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1448,12 +1479,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1448,12 +1479,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14481479
1449 const dest = blk: {1480 const dest = blk: {
1450 if (rhs_immediate_ok) {1481 if (rhs_immediate_ok) {
1451 break :blk try self.binOpImmediate(mir_tag, null, lhs, rhs, lhs_ty, false);1482 break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null);
1452 } else if (lhs_immediate_ok) {1483 } else if (lhs_immediate_ok) {
1453 // swap lhs and rhs1484 // swap lhs and rhs
1454 break :blk try self.binOpImmediate(mir_tag, null, rhs, lhs, rhs_ty, true);1485 break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null);
1455 } else {1486 } else {
1456 break :blk try self.binOpRegister(mir_tag, null, lhs, rhs, lhs_ty, rhs_ty);1487 break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1457 }1488 }
1458 };1489 };
14591490
...@@ -1507,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1507,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1507 .unsigned => .mul,1538 .unsigned => .mul,
1508 };1539 };
15091540
1510 const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1541 const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1511 const dest_reg = dest.register;1542 const dest_reg = dest.register;
1512 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1543 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1513 defer self.register_manager.unlockReg(dest_reg_lock);1544 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1520,7 +1551,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1520,7 +1551,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1520 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1551 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
15211552
1522 // cmp dest, truncated1553 // cmp dest, truncated
1523 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1554 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
15241555
1525 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1556 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1526 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1557 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1594,7 +1625,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1594,7 +1625,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1594 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1625 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
15951626
1596 // cmp truncated, rdlo1627 // cmp truncated, rdlo
1597 _ = try self.binOp(.cmp_eq, null, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize);1628 _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null);
15981629
1599 // mov rdlo, #01630 // mov rdlo, #0
1600 _ = try self.addInst(.{1631 _ = try self.addInst(.{
...@@ -1618,7 +1649,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1618,7 +1649,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1618 });1649 });
16191650
1620 // cmp rdhi, #01651 // cmp rdhi, #0
1621 _ = try self.binOp(.cmp_eq, null, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize);1652 _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null);
16221653
1623 // movne rdlo, #11654 // movne rdlo, #1
1624 _ = try self.addInst(.{1655 _ = try self.addInst(.{
...@@ -1677,16 +1708,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1677,16 +1708,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1677 self.compare_flags_inst = null;1708 self.compare_flags_inst = null;
16781709
1679 // lsl dest, lhs, rhs1710 // lsl dest, lhs, rhs
1680 const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty);1711 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
1681 const dest_reg = dest.register;1712 const dest_reg = dest.register;
1682 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1713 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1683 defer self.register_manager.unlockReg(dest_lock);1714 defer self.register_manager.unlockReg(dest_lock);
16841715
1685 // asr/lsr reconstructed, dest, rhs1716 // asr/lsr reconstructed, dest, rhs
1686 const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty);1717 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
16871718
1688 // cmp lhs, reconstructed1719 // cmp lhs, reconstructed
1689 _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty);1720 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
16901721
1691 try self.genSetStack(lhs_ty, stack_offset, dest);1722 try self.genSetStack(lhs_ty, stack_offset, dest);
1692 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1723 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -2031,7 +2062,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2031,7 +2062,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2031 },2062 },
2032 else => {2063 else => {
2033 const dest = try self.allocRegOrMem(inst, true);2064 const dest = try self.allocRegOrMem(inst, true);
2034 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);2065 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2035 try self.load(dest, addr, slice_ptr_field_type);2066 try self.load(dest, addr, slice_ptr_field_type);
20362067
2037 break :result dest;2068 break :result dest;
...@@ -2051,7 +2082,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2051,7 +2082,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
20512082
2052 const slice_ty = self.air.typeOf(extra.lhs);2083 const slice_ty = self.air.typeOf(extra.lhs);
20532084
2054 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize);2085 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);
2055 break :result addr;2086 break :result addr;
2056 };2087 };
2057 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2088 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2079,7 +2110,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2079,7 +2110,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
20792110
2080 const ptr_ty = self.air.typeOf(extra.lhs);2111 const ptr_ty = self.air.typeOf(extra.lhs);
20812112
2082 const addr = try self.binOp(.ptr_add, null, ptr_mcv, index_mcv, ptr_ty, Type.usize);2113 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);
2083 break :result addr;2114 break :result addr;
2084 };2115 };
2085 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2116 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2411,11 +2442,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2411,11 +2442,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
24112442
2412 const dest = try self.binOp(2443 const dest = try self.binOp(
2413 .add,2444 .add,
2414 null,
2415 .{ .register = addr_reg },2445 .{ .register = addr_reg },
2416 .{ .register = offset_reg },2446 .{ .register = offset_reg },
2417 Type.usize,2447 Type.usize,
2418 Type.usize,2448 Type.usize,
2449 null,
2419 );2450 );
24202451
2421 break :result dest;2452 break :result dest;
...@@ -2514,11 +2545,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2514,11 +2545,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2514fn binOpRegister(2545fn binOpRegister(
2515 self: *Self,2546 self: *Self,
2516 mir_tag: Mir.Inst.Tag,2547 mir_tag: Mir.Inst.Tag,
2517 maybe_inst: ?Air.Inst.Index,
2518 lhs: MCValue,2548 lhs: MCValue,
2519 rhs: MCValue,2549 rhs: MCValue,
2520 lhs_ty: Type,2550 lhs_ty: Type,
2521 rhs_ty: Type,2551 rhs_ty: Type,
2552 metadata: ?BinOpMetadata,
2522) !MCValue {2553) !MCValue {
2523 const lhs_is_register = lhs == .register;2554 const lhs_is_register = lhs == .register;
2524 const rhs_is_register = rhs == .register;2555 const rhs_is_register = rhs == .register;
...@@ -2532,9 +2563,8 @@ fn binOpRegister(...@@ -2532,9 +2563,8 @@ fn binOpRegister(
2532 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];2563 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
25332564
2534 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2565 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2535 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2566 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2536 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2567 break :inst Air.refToIndex(md.lhs).?;
2537 break :inst Air.refToIndex(bin_op.lhs).?;
2538 } else null;2568 } else null;
25392569
2540 const reg = try self.register_manager.allocReg(track_inst);2570 const reg = try self.register_manager.allocReg(track_inst);
...@@ -2547,9 +2577,8 @@ fn binOpRegister(...@@ -2547,9 +2577,8 @@ fn binOpRegister(
2547 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);2577 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
25482578
2549 const rhs_reg = if (rhs_is_register) rhs.register else blk: {2579 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2550 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2580 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2551 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2581 break :inst Air.refToIndex(md.rhs).?;
2552 break :inst Air.refToIndex(bin_op.rhs).?;
2553 } else null;2582 } else null;
25542583
2555 const reg = try self.register_manager.allocReg(track_inst);2584 const reg = try self.register_manager.allocReg(track_inst);
...@@ -2563,15 +2592,13 @@ fn binOpRegister(...@@ -2563,15 +2592,13 @@ fn binOpRegister(
25632592
2564 const dest_reg = switch (mir_tag) {2593 const dest_reg = switch (mir_tag) {
2565 .cmp => .r0, // cmp has no destination regardless2594 .cmp => .r0, // cmp has no destination regardless
2566 else => if (maybe_inst) |inst| blk: {2595 else => if (metadata) |md| blk: {
2567 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2596 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
2568
2569 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
2570 break :blk lhs_reg;2597 break :blk lhs_reg;
2571 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {2598 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
2572 break :blk rhs_reg;2599 break :blk rhs_reg;
2573 } else {2600 } else {
2574 break :blk try self.register_manager.allocReg(inst);2601 break :blk try self.register_manager.allocReg(md.inst);
2575 }2602 }
2576 } else try self.register_manager.allocReg(null),2603 } else try self.register_manager.allocReg(null),
2577 };2604 };
...@@ -2634,11 +2661,11 @@ fn binOpRegister(...@@ -2634,11 +2661,11 @@ fn binOpRegister(
2634fn binOpImmediate(2661fn binOpImmediate(
2635 self: *Self,2662 self: *Self,
2636 mir_tag: Mir.Inst.Tag,2663 mir_tag: Mir.Inst.Tag,
2637 maybe_inst: ?Air.Inst.Index,
2638 lhs: MCValue,2664 lhs: MCValue,
2639 rhs: MCValue,2665 rhs: MCValue,
2640 lhs_ty: Type,2666 lhs_ty: Type,
2641 lhs_and_rhs_swapped: bool,2667 lhs_and_rhs_swapped: bool,
2668 metadata: ?BinOpMetadata,
2642) !MCValue {2669) !MCValue {
2643 const lhs_is_register = lhs == .register;2670 const lhs_is_register = lhs == .register;
26442671
...@@ -2651,10 +2678,9 @@ fn binOpImmediate(...@@ -2651,10 +2678,9 @@ fn binOpImmediate(
2651 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];2678 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
26522679
2653 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2680 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2654 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2681 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2655 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2656 break :inst Air.refToIndex(2682 break :inst Air.refToIndex(
2657 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,2683 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2658 ).?;2684 ).?;
2659 } else null;2685 } else null;
26602686
...@@ -2669,18 +2695,16 @@ fn binOpImmediate(...@@ -2669,18 +2695,16 @@ fn binOpImmediate(
26692695
2670 const dest_reg = switch (mir_tag) {2696 const dest_reg = switch (mir_tag) {
2671 .cmp => .r0, // cmp has no destination reg2697 .cmp => .r0, // cmp has no destination reg
2672 else => if (maybe_inst) |inst| blk: {2698 else => if (metadata) |md| blk: {
2673 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2674
2675 if (lhs_is_register and self.reuseOperand(2699 if (lhs_is_register and self.reuseOperand(
2676 inst,2700 md.inst,
2677 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,2701 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2678 if (lhs_and_rhs_swapped) 1 else 0,2702 if (lhs_and_rhs_swapped) 1 else 0,
2679 lhs,2703 lhs,
2680 )) {2704 )) {
2681 break :blk lhs_reg;2705 break :blk lhs_reg;
2682 } else {2706 } else {
2683 break :blk try self.register_manager.allocReg(inst);2707 break :blk try self.register_manager.allocReg(md.inst);
2684 }2708 }
2685 } else try self.register_manager.allocReg(null),2709 } else try self.register_manager.allocReg(null),
2686 };2710 };
...@@ -2720,6 +2744,12 @@ fn binOpImmediate(...@@ -2720,6 +2744,12 @@ fn binOpImmediate(
2720 return MCValue{ .register = dest_reg };2744 return MCValue{ .register = dest_reg };
2721}2745}
27222746
2747const BinOpMetadata = struct {
2748 inst: Air.Inst.Index,
2749 lhs: Air.Inst.Ref,
2750 rhs: Air.Inst.Ref,
2751};
2752
2723/// For all your binary operation needs, this function will generate2753/// For all your binary operation needs, this function will generate
2724/// the corresponding Mir instruction(s). Returns the location of the2754/// the corresponding Mir instruction(s). Returns the location of the
2725/// result.2755/// result.
...@@ -2735,11 +2765,11 @@ fn binOpImmediate(...@@ -2735,11 +2765,11 @@ fn binOpImmediate(
2735fn binOp(2765fn binOp(
2736 self: *Self,2766 self: *Self,
2737 tag: Air.Inst.Tag,2767 tag: Air.Inst.Tag,
2738 maybe_inst: ?Air.Inst.Index,
2739 lhs: MCValue,2768 lhs: MCValue,
2740 rhs: MCValue,2769 rhs: MCValue,
2741 lhs_ty: Type,2770 lhs_ty: Type,
2742 rhs_ty: Type,2771 rhs_ty: Type,
2772 metadata: ?BinOpMetadata,
2743) InnerError!MCValue {2773) InnerError!MCValue {
2744 switch (tag) {2774 switch (tag) {
2745 .add,2775 .add,
...@@ -2780,12 +2810,12 @@ fn binOp(...@@ -2780,12 +2810,12 @@ fn binOp(
2780 };2810 };
27812811
2782 if (rhs_immediate_ok) {2812 if (rhs_immediate_ok) {
2783 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2813 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2784 } else if (lhs_immediate_ok) {2814 } else if (lhs_immediate_ok) {
2785 // swap lhs and rhs2815 // swap lhs and rhs
2786 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);2816 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2787 } else {2817 } else {
2788 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2818 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2789 }2819 }
2790 } else {2820 } else {
2791 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2821 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2806,7 +2836,7 @@ fn binOp(...@@ -2806,7 +2836,7 @@ fn binOp(
2806 // TODO add optimisations for multiplication2836 // TODO add optimisations for multiplication
2807 // with immediates, for example a * 2 can be2837 // with immediates, for example a * 2 can be
2808 // lowered to a << 12838 // lowered to a << 1
2809 return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2839 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
2810 } else {2840 } else {
2811 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2841 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2812 }2842 }
...@@ -2826,7 +2856,7 @@ fn binOp(...@@ -2826,7 +2856,7 @@ fn binOp(
2826 };2856 };
28272857
2828 // Generate an add/sub/mul2858 // Generate an add/sub/mul
2829 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2859 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
28302860
2831 // Truncate if necessary2861 // Truncate if necessary
2832 switch (lhs_ty.zigTypeTag()) {2862 switch (lhs_ty.zigTypeTag()) {
...@@ -2869,12 +2899,12 @@ fn binOp(...@@ -2869,12 +2899,12 @@ fn binOp(
2869 };2899 };
28702900
2871 if (rhs_immediate_ok) {2901 if (rhs_immediate_ok) {
2872 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2902 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2873 } else if (lhs_immediate_ok) {2903 } else if (lhs_immediate_ok) {
2874 // swap lhs and rhs2904 // swap lhs and rhs
2875 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);2905 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2876 } else {2906 } else {
2877 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2907 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2878 }2908 }
2879 } else {2909 } else {
2880 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2910 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2903,9 +2933,9 @@ fn binOp(...@@ -2903,9 +2933,9 @@ fn binOp(
2903 };2933 };
29042934
2905 if (rhs_immediate_ok) {2935 if (rhs_immediate_ok) {
2906 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2936 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2907 } else {2937 } else {
2908 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2938 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2909 }2939 }
2910 } else {2940 } else {
2911 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2941 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2924,7 +2954,7 @@ fn binOp(...@@ -2924,7 +2954,7 @@ fn binOp(
2924 };2954 };
29252955
2926 // Generate a shl_exact/shr_exact2956 // Generate a shl_exact/shr_exact
2927 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2957 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
29282958
2929 // Truncate if necessary2959 // Truncate if necessary
2930 switch (tag) {2960 switch (tag) {
...@@ -2964,12 +2994,12 @@ fn binOp(...@@ -2964,12 +2994,12 @@ fn binOp(
2964 };2994 };
29652995
2966 if (rhs_immediate_ok) {2996 if (rhs_immediate_ok) {
2967 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2997 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2968 } else if (lhs_immediate_ok) {2998 } else if (lhs_immediate_ok) {
2969 // swap lhs and rhs2999 // swap lhs and rhs
2970 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);3000 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2971 } else {3001 } else {
2972 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);3002 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2973 }3003 }
2974 },3004 },
2975 else => unreachable,3005 else => unreachable,
...@@ -2994,12 +3024,12 @@ fn binOp(...@@ -2994,12 +3024,12 @@ fn binOp(
2994 else => unreachable,3024 else => unreachable,
2995 };3025 };
29963026
2997 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);3027 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2998 } else {3028 } else {
2999 // convert the offset into a byte offset by3029 // convert the offset into a byte offset by
3000 // multiplying it with elem_size3030 // multiplying it with elem_size
3001 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);3031 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
3002 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);3032 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
3003 return addr;3033 return addr;
3004 }3034 }
3005 },3035 },
...@@ -3575,7 +3605,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3575,7 +3605,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3575 try self.spillCompareFlagsIfOccupied();3605 try self.spillCompareFlagsIfOccupied();
3576 self.compare_flags_inst = inst;3606 self.compare_flags_inst = inst;
35773607
3578 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);3608 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
3609 .lhs = bin_op.lhs,
3610 .rhs = bin_op.rhs,
3611 .inst = inst,
3612 });
35793613
3580 break :result switch (int_info.signedness) {3614 break :result switch (int_info.signedness) {
3581 .signed => MCValue{ .compare_flags_signed = op },3615 .signed => MCValue{ .compare_flags_signed = op },
...@@ -3865,7 +3899,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3865,7 +3899,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3865 }3899 }
38663900
3867 const error_mcv = try self.errUnionErr(operand, ty);3901 const error_mcv = try self.errUnionErr(operand, ty);
3868 _ = try self.binOp(.cmp_eq, null, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type);3902 _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
3869 return MCValue{ .compare_flags_unsigned = .gt };3903 return MCValue{ .compare_flags_unsigned = .gt };
3870}3904}
38713905
src/arch/riscv64/CodeGen.zig+19-4
...@@ -481,10 +481,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -481,10 +481,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
481481
482 switch (air_tags[inst]) {482 switch (air_tags[inst]) {
483 // zig fmt: off483 // zig fmt: off
484 .add, .ptr_add => try self.airBinOp(inst),484 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
485 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
486
487 .add => try self.airBinOp(inst, .add),
488 .sub => try self.airBinOp(inst, .sub),
489
485 .addwrap => try self.airAddWrap(inst),490 .addwrap => try self.airAddWrap(inst),
486 .add_sat => try self.airAddSat(inst),491 .add_sat => try self.airAddSat(inst),
487 .sub, .ptr_sub => try self.airBinOp(inst),
488 .subwrap => try self.airSubWrap(inst),492 .subwrap => try self.airSubWrap(inst),
489 .sub_sat => try self.airSubSat(inst),493 .sub_sat => try self.airSubSat(inst),
490 .mul => try self.airMul(inst),494 .mul => try self.airMul(inst),
...@@ -1091,8 +1095,7 @@ fn binOp(...@@ -1091,8 +1095,7 @@ fn binOp(
1091 }1095 }
1092}1096}
10931097
1094fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1098fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1095 const tag = self.air.instructions.items(.tag)[inst];
1096 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1099 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1097 const lhs = try self.resolveInst(bin_op.lhs);1100 const lhs = try self.resolveInst(bin_op.lhs);
1098 const rhs = try self.resolveInst(bin_op.rhs);1101 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -1103,6 +1106,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1103,6 +1106,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1103 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1106 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1104}1107}
11051108
1109fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1110 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1111 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1112 const lhs = try self.resolveInst(bin_op.lhs);
1113 const rhs = try self.resolveInst(bin_op.rhs);
1114 const lhs_ty = self.air.typeOf(bin_op.lhs);
1115 const rhs_ty = self.air.typeOf(bin_op.rhs);
1116
1117 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1118 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1119}
1120
1106fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {1121fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
1107 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1122 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1108 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});1123 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});
src/arch/sparc64/CodeGen.zig+71-46
...@@ -483,10 +483,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -483,10 +483,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
483483
484 switch (air_tags[inst]) {484 switch (air_tags[inst]) {
485 // zig fmt: off485 // zig fmt: off
486 .add, .ptr_add => try self.airBinOp(inst),486 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
487 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
488
489 .add => try self.airBinOp(inst, .add),
487 .addwrap => @panic("TODO try self.airAddWrap(inst)"),490 .addwrap => @panic("TODO try self.airAddWrap(inst)"),
488 .add_sat => @panic("TODO try self.airAddSat(inst)"),491 .add_sat => @panic("TODO try self.airAddSat(inst)"),
489 .sub, .ptr_sub => @panic("TODO try self.airBinOp(inst)"),492 .sub => @panic("TODO try self.airBinOp(inst)"),
490 .subwrap => @panic("TODO try self.airSubWrap(inst)"),493 .subwrap => @panic("TODO try self.airSubWrap(inst)"),
491 .sub_sat => @panic("TODO try self.airSubSat(inst)"),494 .sub_sat => @panic("TODO try self.airSubSat(inst)"),
492 .mul => @panic("TODO try self.airMul(inst)"),495 .mul => @panic("TODO try self.airMul(inst)"),
...@@ -827,18 +830,38 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -827,18 +830,38 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
827 return self.finishAir(inst, mcv, .{ .none, .none, .none });830 return self.finishAir(inst, mcv, .{ .none, .none, .none });
828}831}
829832
830fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {833fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
831 const tag = self.air.instructions.items(.tag)[inst];
832 const bin_op = self.air.instructions.items(.data)[inst].bin_op;834 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
833 const lhs = try self.resolveInst(bin_op.lhs);835 const lhs = try self.resolveInst(bin_op.lhs);
834 const rhs = try self.resolveInst(bin_op.rhs);836 const rhs = try self.resolveInst(bin_op.rhs);
835 const lhs_ty = self.air.typeOf(bin_op.lhs);837 const lhs_ty = self.air.typeOf(bin_op.lhs);
836 const rhs_ty = self.air.typeOf(bin_op.rhs);838 const rhs_ty = self.air.typeOf(bin_op.rhs);
839 const result: MCValue = if (self.liveness.isUnused(inst))
840 .dead
841 else
842 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
843 .lhs = bin_op.lhs,
844 .rhs = bin_op.rhs,
845 .inst = inst,
846 });
847 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
848}
837849
850fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
851 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
852 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
853 const lhs = try self.resolveInst(bin_op.lhs);
854 const rhs = try self.resolveInst(bin_op.rhs);
855 const lhs_ty = self.air.typeOf(bin_op.lhs);
856 const rhs_ty = self.air.typeOf(bin_op.rhs);
838 const result: MCValue = if (self.liveness.isUnused(inst))857 const result: MCValue = if (self.liveness.isUnused(inst))
839 .dead858 .dead
840 else859 else
841 try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);860 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
861 .lhs = bin_op.lhs,
862 .rhs = bin_op.rhs,
863 .inst = inst,
864 });
842 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });865 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
843}866}
844867
...@@ -1030,7 +1053,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1030,7 +1053,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
10301053
1031 var int_buffer: Type.Payload.Bits = undefined;1054 var int_buffer: Type.Payload.Bits = undefined;
1032 const int_ty = switch (lhs_ty.zigTypeTag()) {1055 const int_ty = switch (lhs_ty.zigTypeTag()) {
1033 .Vector => unreachable, // Should be handled by cmp_vector?1056 .Vector => unreachable, // Handled by cmp_vector.
1034 .Enum => lhs_ty.intTagType(&int_buffer),1057 .Enum => lhs_ty.intTagType(&int_buffer),
1035 .Int => lhs_ty,1058 .Int => lhs_ty,
1036 .Bool => Type.initTag(.u1),1059 .Bool => Type.initTag(.u1),
...@@ -1053,7 +1076,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1053,7 +1076,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
10531076
1054 const int_info = int_ty.intInfo(self.target.*);1077 const int_info = int_ty.intInfo(self.target.*);
1055 if (int_info.bits <= 64) {1078 if (int_info.bits <= 64) {
1056 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);1079 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
1080 .lhs = bin_op.lhs,
1081 .rhs = bin_op.rhs,
1082 .inst = inst,
1083 });
10571084
1058 try self.spillCompareFlagsIfOccupied();1085 try self.spillCompareFlagsIfOccupied();
1059 self.compare_flags_inst = inst;1086 self.compare_flags_inst = inst;
...@@ -1426,7 +1453,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1426,7 +1453,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1426 // TODO skip the ptr_add emission entirely and use native addressing modes1453 // TODO skip the ptr_add emission entirely and use native addressing modes
1427 // i.e sllx/mulx then R+R or scale immediate then R+I1454 // i.e sllx/mulx then R+R or scale immediate then R+I
1428 const dest = try self.allocRegOrMem(inst, true);1455 const dest = try self.allocRegOrMem(inst, true);
1429 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);1456 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
1430 try self.load(dest, addr, slice_ptr_field_type);1457 try self.load(dest, addr, slice_ptr_field_type);
14311458
1432 break :result dest;1459 break :result dest;
...@@ -1595,6 +1622,12 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1595,6 +1622,12 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1595 return MCValue{ .stack_offset = stack_offset };1622 return MCValue{ .stack_offset = stack_offset };
1596}1623}
15971624
1625const BinOpMetadata = struct {
1626 inst: Air.Inst.Index,
1627 lhs: Air.Inst.Ref,
1628 rhs: Air.Inst.Ref,
1629};
1630
1598/// For all your binary operation needs, this function will generate1631/// For all your binary operation needs, this function will generate
1599/// the corresponding Mir instruction(s). Returns the location of the1632/// the corresponding Mir instruction(s). Returns the location of the
1600/// result.1633/// result.
...@@ -1610,11 +1643,11 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1610,11 +1643,11 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1610fn binOp(1643fn binOp(
1611 self: *Self,1644 self: *Self,
1612 tag: Air.Inst.Tag,1645 tag: Air.Inst.Tag,
1613 maybe_inst: ?Air.Inst.Index,
1614 lhs: MCValue,1646 lhs: MCValue,
1615 rhs: MCValue,1647 rhs: MCValue,
1616 lhs_ty: Type,1648 lhs_ty: Type,
1617 rhs_ty: Type,1649 rhs_ty: Type,
1650 metadata: ?BinOpMetadata,
1618) InnerError!MCValue {1651) InnerError!MCValue {
1619 const mod = self.bin_file.options.module.?;1652 const mod = self.bin_file.options.module.?;
1620 switch (tag) {1653 switch (tag) {
...@@ -1649,13 +1682,13 @@ fn binOp(...@@ -1649,13 +1682,13 @@ fn binOp(
1649 };1682 };
16501683
1651 if (rhs_immediate_ok) {1684 if (rhs_immediate_ok) {
1652 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);1685 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
1653 } else if (lhs_immediate_ok) {1686 } else if (lhs_immediate_ok) {
1654 // swap lhs and rhs1687 // swap lhs and rhs
1655 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);1688 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
1656 } else {1689 } else {
1657 // TODO convert large immediates to register before adding1690 // TODO convert large immediates to register before adding
1658 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1691 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1659 }1692 }
1660 } else {1693 } else {
1661 return self.fail("TODO binary operations on int with bits > 64", .{});1694 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1683,10 +1716,10 @@ fn binOp(...@@ -1683,10 +1716,10 @@ fn binOp(
1683 // If it's a power of two immediate then we emit an shl instead1716 // If it's a power of two immediate then we emit an shl instead
1684 // TODO add similar checks for LHS1717 // TODO add similar checks for LHS
1685 if (new_rhs == .immediate and math.isPowerOfTwo(new_rhs.immediate)) {1718 if (new_rhs == .immediate and math.isPowerOfTwo(new_rhs.immediate)) {
1686 return try self.binOp(.shl, maybe_inst, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize);1719 return try self.binOp(.shl, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize, metadata);
1687 }1720 }
16881721
1689 return try self.binOpRegister(.mulx, maybe_inst, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty);1722 return try self.binOpRegister(.mulx, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty, metadata);
1690 } else {1723 } else {
1691 return self.fail("TODO binary operations on int with bits > 64", .{});1724 return self.fail("TODO binary operations on int with bits > 64", .{});
1692 }1725 }
...@@ -1711,13 +1744,13 @@ fn binOp(...@@ -1711,13 +1744,13 @@ fn binOp(
1711 else => unreachable,1744 else => unreachable,
1712 };1745 };
17131746
1714 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1747 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1715 } else {1748 } else {
1716 // convert the offset into a byte offset by1749 // convert the offset into a byte offset by
1717 // multiplying it with elem_size1750 // multiplying it with elem_size
17181751
1719 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);1752 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
1720 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);1753 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
1721 return addr;1754 return addr;
1722 }1755 }
1723 },1756 },
...@@ -1732,7 +1765,7 @@ fn binOp(...@@ -1732,7 +1765,7 @@ fn binOp(
1732 };1765 };
17331766
1734 // Generate a shl_exact/shr_exact1767 // Generate a shl_exact/shr_exact
1735 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1768 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
17361769
1737 // Truncate if necessary1770 // Truncate if necessary
1738 switch (tag) {1771 switch (tag) {
...@@ -1768,9 +1801,9 @@ fn binOp(...@@ -1768,9 +1801,9 @@ fn binOp(
1768 };1801 };
17691802
1770 if (rhs_immediate_ok) {1803 if (rhs_immediate_ok) {
1771 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);1804 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
1772 } else {1805 } else {
1773 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1806 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1774 }1807 }
1775 } else {1808 } else {
1776 return self.fail("TODO binary operations on int with bits > 64", .{});1809 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1792,18 +1825,17 @@ fn binOp(...@@ -1792,18 +1825,17 @@ fn binOp(
1792/// op dest, lhs, #rhs_imm1825/// op dest, lhs, #rhs_imm
1793///1826///
1794/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to1827/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
1795/// rhs and vice versa. This parameter is only used when maybe_inst !=1828/// rhs and vice versa. This parameter is only used when metadata != null.
1796/// null.
1797///1829///
1798/// Asserts that generating an instruction of that form is possible.1830/// Asserts that generating an instruction of that form is possible.
1799fn binOpImmediate(1831fn binOpImmediate(
1800 self: *Self,1832 self: *Self,
1801 mir_tag: Mir.Inst.Tag,1833 mir_tag: Mir.Inst.Tag,
1802 maybe_inst: ?Air.Inst.Index,
1803 lhs: MCValue,1834 lhs: MCValue,
1804 rhs: MCValue,1835 rhs: MCValue,
1805 lhs_ty: Type,1836 lhs_ty: Type,
1806 lhs_and_rhs_swapped: bool,1837 lhs_and_rhs_swapped: bool,
1838 metadata: ?BinOpMetadata,
1807) !MCValue {1839) !MCValue {
1808 const lhs_is_register = lhs == .register;1840 const lhs_is_register = lhs == .register;
18091841
...@@ -1816,10 +1848,9 @@ fn binOpImmediate(...@@ -1816,10 +1848,9 @@ fn binOpImmediate(
1816 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1848 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
18171849
1818 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1850 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1819 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1851 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1820 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1821 break :inst Air.refToIndex(1852 break :inst Air.refToIndex(
1822 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1853 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1823 ).?;1854 ).?;
1824 } else null;1855 } else null;
18251856
...@@ -1833,18 +1864,16 @@ fn binOpImmediate(...@@ -1833,18 +1864,16 @@ fn binOpImmediate(
1833 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1864 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
18341865
1835 const dest_reg = switch (mir_tag) {1866 const dest_reg = switch (mir_tag) {
1836 else => if (maybe_inst) |inst| blk: {1867 else => if (metadata) |md| blk: {
1837 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1838
1839 if (lhs_is_register and self.reuseOperand(1868 if (lhs_is_register and self.reuseOperand(
1840 inst,1869 md.inst,
1841 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1870 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1842 if (lhs_and_rhs_swapped) 1 else 0,1871 if (lhs_and_rhs_swapped) 1 else 0,
1843 lhs,1872 lhs,
1844 )) {1873 )) {
1845 break :blk lhs_reg;1874 break :blk lhs_reg;
1846 } else {1875 } else {
1847 break :blk try self.register_manager.allocReg(inst);1876 break :blk try self.register_manager.allocReg(md.inst);
1848 }1877 }
1849 } else blk: {1878 } else blk: {
1850 break :blk try self.register_manager.allocReg(null);1879 break :blk try self.register_manager.allocReg(null);
...@@ -1896,11 +1925,11 @@ fn binOpImmediate(...@@ -1896,11 +1925,11 @@ fn binOpImmediate(
1896fn binOpRegister(1925fn binOpRegister(
1897 self: *Self,1926 self: *Self,
1898 mir_tag: Mir.Inst.Tag,1927 mir_tag: Mir.Inst.Tag,
1899 maybe_inst: ?Air.Inst.Index,
1900 lhs: MCValue,1928 lhs: MCValue,
1901 rhs: MCValue,1929 rhs: MCValue,
1902 lhs_ty: Type,1930 lhs_ty: Type,
1903 rhs_ty: Type,1931 rhs_ty: Type,
1932 metadata: ?BinOpMetadata,
1904) !MCValue {1933) !MCValue {
1905 const lhs_is_register = lhs == .register;1934 const lhs_is_register = lhs == .register;
1906 const rhs_is_register = rhs == .register;1935 const rhs_is_register = rhs == .register;
...@@ -1920,9 +1949,8 @@ fn binOpRegister(...@@ -1920,9 +1949,8 @@ fn binOpRegister(
1920 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1949 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
19211950
1922 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1951 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1923 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1952 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1924 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1953 break :inst Air.refToIndex(md.lhs).?;
1925 break :inst Air.refToIndex(bin_op.lhs).?;
1926 } else null;1954 } else null;
19271955
1928 const reg = try self.register_manager.allocReg(track_inst);1956 const reg = try self.register_manager.allocReg(track_inst);
...@@ -1934,9 +1962,8 @@ fn binOpRegister(...@@ -1934,9 +1962,8 @@ fn binOpRegister(
1934 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1962 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
19351963
1936 const rhs_reg = if (rhs_is_register) rhs.register else blk: {1964 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1937 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1965 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1938 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1966 break :inst Air.refToIndex(md.rhs).?;
1939 break :inst Air.refToIndex(bin_op.rhs).?;
1940 } else null;1967 } else null;
19411968
1942 const reg = try self.register_manager.allocReg(track_inst);1969 const reg = try self.register_manager.allocReg(track_inst);
...@@ -1948,15 +1975,13 @@ fn binOpRegister(...@@ -1948,15 +1975,13 @@ fn binOpRegister(
1948 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);1975 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
19491976
1950 const dest_reg = switch (mir_tag) {1977 const dest_reg = switch (mir_tag) {
1951 else => if (maybe_inst) |inst| blk: {1978 else => if (metadata) |md| blk: {
1952 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1979 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
1953
1954 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1955 break :blk lhs_reg;1980 break :blk lhs_reg;
1956 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1981 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1957 break :blk rhs_reg;1982 break :blk rhs_reg;
1958 } else {1983 } else {
1959 break :blk try self.register_manager.allocReg(inst);1984 break :blk try self.register_manager.allocReg(md.inst);
1960 }1985 }
1961 } else blk: {1986 } else blk: {
1962 break :blk try self.register_manager.allocReg(null);1987 break :blk try self.register_manager.allocReg(null);
...@@ -3069,11 +3094,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -3069,11 +3094,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
30693094
3070 const dest = try self.binOp(3095 const dest = try self.binOp(
3071 .add,3096 .add,
3072 null,
3073 .{ .register = addr_reg },3097 .{ .register = addr_reg },
3074 .{ .register = offset_reg },3098 .{ .register = offset_reg },
3075 Type.usize,3099 Type.usize,
3076 Type.usize,3100 Type.usize,
3101 null,
3077 );3102 );
30783103
3079 break :result dest;3104 break :result dest;
src/arch/wasm/CodeGen.zig+2-1
...@@ -3397,7 +3397,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3397,7 +3397,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33973397
3398fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {3398fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
3399 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3399 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3400 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3400 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3401 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3401 const ptr = try self.resolveInst(bin_op.lhs);3402 const ptr = try self.resolveInst(bin_op.lhs);
3402 const offset = try self.resolveInst(bin_op.rhs);3403 const offset = try self.resolveInst(bin_op.rhs);
3403 const ptr_ty = self.air.typeOf(bin_op.lhs);3404 const ptr_ty = self.air.typeOf(bin_op.lhs);
src/arch/x86_64/CodeGen.zig+45-37
...@@ -574,23 +574,33 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -574,23 +574,33 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
574574
575 switch (air_tags[inst]) {575 switch (air_tags[inst]) {
576 // zig fmt: off576 // zig fmt: off
577 .add => try self.airBinOp(inst),577 .add => try self.airBinOp(inst, .add),
578 .addwrap => try self.airBinOp(inst),578 .addwrap => try self.airBinOp(inst, .addwrap),
579 .add_sat => try self.airAddSat(inst),579 .sub => try self.airBinOp(inst, .sub),
580 .sub => try self.airBinOp(inst),580 .subwrap => try self.airBinOp(inst, .subwrap),
581 .subwrap => try self.airBinOp(inst),581 .bool_and => try self.airBinOp(inst, .bool_and),
582 .sub_sat => try self.airSubSat(inst),582 .bool_or => try self.airBinOp(inst, .bool_or),
583 .bit_and => try self.airBinOp(inst, .bit_and),
584 .bit_or => try self.airBinOp(inst, .bit_or),
585 .xor => try self.airBinOp(inst, .xor),
586
587 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
588 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
589
590 .shr, .shr_exact => try self.airShlShrBinOp(inst),
591 .shl, .shl_exact => try self.airShlShrBinOp(inst),
592
583 .mul => try self.airMulDivBinOp(inst),593 .mul => try self.airMulDivBinOp(inst),
584 .mulwrap => try self.airMulDivBinOp(inst),594 .mulwrap => try self.airMulDivBinOp(inst),
585 .mul_sat => try self.airMulSat(inst),
586 .rem => try self.airMulDivBinOp(inst),595 .rem => try self.airMulDivBinOp(inst),
587 .mod => try self.airMulDivBinOp(inst),596 .mod => try self.airMulDivBinOp(inst),
588 .shl, .shl_exact => try self.airShlShrBinOp(inst),597
598 .add_sat => try self.airAddSat(inst),
599 .sub_sat => try self.airSubSat(inst),
600 .mul_sat => try self.airMulSat(inst),
589 .shl_sat => try self.airShlSat(inst),601 .shl_sat => try self.airShlSat(inst),
590 .min => try self.airMin(inst),602 .min => try self.airMin(inst),
591 .max => try self.airMax(inst),603 .max => try self.airMax(inst),
592 .ptr_add => try self.airBinOp(inst),
593 .ptr_sub => try self.airBinOp(inst),
594 .slice => try self.airSlice(inst),604 .slice => try self.airSlice(inst),
595605
596 .sqrt,606 .sqrt,
...@@ -626,13 +636,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -626,13 +636,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
626 .cmp_vector => try self.airCmpVector(inst),636 .cmp_vector => try self.airCmpVector(inst),
627 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),637 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
628638
629 .bool_and => try self.airBinOp(inst),
630 .bool_or => try self.airBinOp(inst),
631 .bit_and => try self.airBinOp(inst),
632 .bit_or => try self.airBinOp(inst),
633 .xor => try self.airBinOp(inst),
634 .shr, .shr_exact => try self.airShlShrBinOp(inst),
635
636 .alloc => try self.airAlloc(inst),639 .alloc => try self.airAlloc(inst),
637 .ret_ptr => try self.airRetPtr(inst),640 .ret_ptr => try self.airRetPtr(inst),
638 .arg => try self.airArg(inst),641 .arg => try self.airArg(inst),
...@@ -1231,21 +1234,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1231,21 +1234,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1231 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1234 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1232}1235}
12331236
1234fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1237fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1235 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1238 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12361239
1237 if (self.liveness.isUnused(inst)) {1240 if (self.liveness.isUnused(inst)) {
1238 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1241 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1239 }1242 }
12401243
1241 const tag = self.air.instructions.items(.tag)[inst];1244 const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1242 const lhs = try self.resolveInst(bin_op.lhs);1245 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1243 const rhs = try self.resolveInst(bin_op.rhs);1246}
1244 const lhs_ty = self.air.typeOf(bin_op.lhs);
1245 const rhs_ty = self.air.typeOf(bin_op.rhs);
12461247
1247 const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1248fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1249 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1250 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1251
1252 if (self.liveness.isUnused(inst)) {
1253 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1254 }
12481255
1256 const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1249 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1257 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1250}1258}
12511259
...@@ -1316,13 +1324,12 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1316,13 +1324,12 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1316 try self.spillRegisters(1, .{.rcx});1324 try self.spillRegisters(1, .{.rcx});
1317 }1325 }
13181326
1319 const lhs = try self.resolveInst(bin_op.lhs);
1320 const rhs = try self.resolveInst(bin_op.rhs);
1321
1322 const partial: MCValue = switch (tag) {1327 const partial: MCValue = switch (tag) {
1323 .add_with_overflow => try self.genBinOp(.add, null, lhs, rhs, ty, ty),1328 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
1324 .sub_with_overflow => try self.genBinOp(.sub, null, lhs, rhs, ty, ty),1329 .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),
1325 .shl_with_overflow => blk: {1330 .shl_with_overflow => blk: {
1331 const lhs = try self.resolveInst(bin_op.lhs);
1332 const rhs = try self.resolveInst(bin_op.rhs);
1326 const shift_ty = self.air.typeOf(bin_op.rhs);1333 const shift_ty = self.air.typeOf(bin_op.rhs);
1327 break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty);1334 break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty);
1328 },1335 },
...@@ -3310,13 +3317,15 @@ fn genMulDivBinOp(...@@ -3310,13 +3317,15 @@ fn genMulDivBinOp(
3310/// Result is always a register.3317/// Result is always a register.
3311fn genBinOp(3318fn genBinOp(
3312 self: *Self,3319 self: *Self,
3313 tag: Air.Inst.Tag,
3314 maybe_inst: ?Air.Inst.Index,3320 maybe_inst: ?Air.Inst.Index,
3315 lhs: MCValue,3321 tag: Air.Inst.Tag,
3316 rhs: MCValue,3322 lhs_air: Air.Inst.Ref,
3317 lhs_ty: Type,3323 rhs_air: Air.Inst.Ref,
3318 rhs_ty: Type,
3319) !MCValue {3324) !MCValue {
3325 const lhs = try self.resolveInst(lhs_air);
3326 const rhs = try self.resolveInst(rhs_air);
3327 const lhs_ty = self.air.typeOf(lhs_air);
3328 const rhs_ty = self.air.typeOf(rhs_air);
3320 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {3329 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
3321 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});3330 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
3322 }3331 }
...@@ -3352,11 +3361,10 @@ fn genBinOp(...@@ -3352,11 +3361,10 @@ fn genBinOp(
3352 var flipped: bool = false;3361 var flipped: bool = false;
3353 const dst_mcv: MCValue = blk: {3362 const dst_mcv: MCValue = blk: {
3354 if (maybe_inst) |inst| {3363 if (maybe_inst) |inst| {
3355 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3364 if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) {
3356 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
3357 break :blk lhs;3365 break :blk lhs;
3358 }3366 }
3359 if (is_commutative and self.reuseOperand(inst, bin_op.rhs, 1, rhs) and rhs.isRegister()) {3367 if (is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs) and rhs.isRegister()) {
3360 flipped = true;3368 flipped = true;
3361 break :blk rhs;3369 break :blk rhs;
3362 }3370 }
src/codegen/c.zig+16-20
...@@ -1711,21 +1711,18 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1711,21 +1711,18 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1711 .unreach => try airUnreach(f),1711 .unreach => try airUnreach(f),
1712 .fence => try airFence(f, inst),1712 .fence => try airFence(f, inst),
17131713
1714 // TODO use a different strategy for add that communicates to the optimizer1714 .ptr_add => try airPtrAddSub(f, inst, " + "),
1715 // that wrapping is UB.1715 .ptr_sub => try airPtrAddSub(f, inst, " - "),
1716 .add => try airBinOp (f, inst, " + "),1716
1717 .ptr_add => try airPtrAddSub (f, inst, " + "),1717 // TODO use a different strategy for add, sub, mul, div
1718 // TODO use a different strategy for sub that communicates to the optimizer1718 // that communicates to the optimizer that wrapping is UB.
1719 // that wrapping is UB.1719 .add => try airBinOp (f, inst, " + "),
1720 .sub => try airBinOp (f, inst, " - "),1720 .sub => try airBinOp (f, inst, " - "),
1721 .ptr_sub => try airPtrAddSub (f, inst, " - "),1721 .mul => try airBinOp (f, inst, " * "),
1722 // TODO use a different strategy for mul that communicates to the optimizer
1723 // that wrapping is UB.
1724 .mul => try airBinOp (f, inst, " * "),
1725 // TODO use a different strategy for div that communicates to the optimizer
1726 // that wrapping is UB.
1727 .div_float, .div_exact => try airBinOp( f, inst, " / "),1722 .div_float, .div_exact => try airBinOp( f, inst, " / "),
1728 .div_trunc => blk: {1723 .rem => try airBinOp( f, inst, " % "),
1724
1725 .div_trunc => blk: {
1729 const bin_op = f.air.instructions.items(.data)[inst].bin_op;1726 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1730 const lhs_ty = f.air.typeOf(bin_op.lhs);1727 const lhs_ty = f.air.typeOf(bin_op.lhs);
1731 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),1728 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
...@@ -1735,9 +1732,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1735,9 +1732,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1735 else1732 else
1736 try airBinOpBuiltinCall(f, inst, "div_trunc");1733 try airBinOpBuiltinCall(f, inst, "div_trunc");
1737 },1734 },
1738 .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),1735 .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),
1739 .rem => try airBinOp( f, inst, " % "),1736 .mod => try airBinOpBuiltinCall(f, inst, "mod"),
1740 .mod => try airBinOpBuiltinCall(f, inst, "mod"),
17411737
1742 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),1738 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
1743 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),1739 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
...@@ -2617,10 +2613,10 @@ fn airEquality(...@@ -2617,10 +2613,10 @@ fn airEquality(
2617}2613}
26182614
2619fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {2615fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
2620 if (f.liveness.isUnused(inst))2616 if (f.liveness.isUnused(inst)) return CValue.none;
2621 return CValue.none;
26222617
2623 const bin_op = f.air.instructions.items(.data)[inst].bin_op;2618 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2619 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
2624 const lhs = try f.resolveInst(bin_op.lhs);2620 const lhs = try f.resolveInst(bin_op.lhs);
2625 const rhs = try f.resolveInst(bin_op.rhs);2621 const rhs = try f.resolveInst(bin_op.rhs);
26262622
src/codegen/llvm.zig+63-14
...@@ -395,11 +395,11 @@ pub const Object = struct {...@@ -395,11 +395,11 @@ pub const Object = struct {
395 return slice.ptr;395 return slice.ptr;
396 }396 }
397397
398 fn genErrorNameTable(self: *Object, comp: *Compilation) !void {398 fn genErrorNameTable(self: *Object) !void {
399 // If self.error_name_table is null, there was no instruction that actually referenced the error table.399 // If self.error_name_table is null, there was no instruction that actually referenced the error table.
400 const error_name_table_ptr_global = self.error_name_table orelse return;400 const error_name_table_ptr_global = self.error_name_table orelse return;
401401
402 const mod = comp.bin_file.options.module.?;402 const mod = self.module;
403 const target = mod.getTarget();403 const target = mod.getTarget();
404404
405 const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space405 const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space
...@@ -413,8 +413,8 @@ pub const Object = struct {...@@ -413,8 +413,8 @@ pub const Object = struct {
413 const slice_alignment = slice_ty.abiAlignment(target);413 const slice_alignment = slice_ty.abiAlignment(target);
414414
415 const error_name_list = mod.error_name_list.items;415 const error_name_list = mod.error_name_list.items;
416 const llvm_errors = try comp.gpa.alloc(*const llvm.Value, error_name_list.len);416 const llvm_errors = try mod.gpa.alloc(*const llvm.Value, error_name_list.len);
417 defer comp.gpa.free(llvm_errors);417 defer mod.gpa.free(llvm_errors);
418418
419 llvm_errors[0] = llvm_slice_ty.getUndef();419 llvm_errors[0] = llvm_slice_ty.getUndef();
420 for (llvm_errors[1..]) |*llvm_error, i| {420 for (llvm_errors[1..]) |*llvm_error, i| {
...@@ -447,10 +447,10 @@ pub const Object = struct {...@@ -447,10 +447,10 @@ pub const Object = struct {
447 error_name_table_ptr_global.setInitializer(error_name_table_ptr);447 error_name_table_ptr_global.setInitializer(error_name_table_ptr);
448 }448 }
449449
450 fn genCmpLtErrorsLenFunction(object: *Object, comp: *Compilation) !void {450 fn genCmpLtErrorsLenFunction(object: *Object) !void {
451 // If there is no such function in the module, it means the source code does not need it.451 // If there is no such function in the module, it means the source code does not need it.
452 const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return;452 const llvm_fn = object.llvm_module.getNamedFunction(lt_errors_fn_name) orelse return;
453 const mod = comp.bin_file.options.module.?;453 const mod = object.module;
454 const errors_len = mod.global_error_set.count();454 const errors_len = mod.global_error_set.count();
455455
456 // Delete previous implementation. We replace it with every flush() because the456 // Delete previous implementation. We replace it with every flush() because the
...@@ -476,10 +476,10 @@ pub const Object = struct {...@@ -476,10 +476,10 @@ pub const Object = struct {
476 _ = builder.buildRet(is_lt);476 _ = builder.buildRet(is_lt);
477 }477 }
478478
479 fn genModuleLevelAssembly(object: *Object, comp: *Compilation) !void {479 fn genModuleLevelAssembly(object: *Object) !void {
480 const mod = comp.bin_file.options.module.?;480 const mod = object.module;
481 if (mod.global_assembly.count() == 0) return;481 if (mod.global_assembly.count() == 0) return;
482 var buffer = std.ArrayList(u8).init(comp.gpa);482 var buffer = std.ArrayList(u8).init(mod.gpa);
483 defer buffer.deinit();483 defer buffer.deinit();
484 var it = mod.global_assembly.iterator();484 var it = mod.global_assembly.iterator();
485 while (it.next()) |kv| {485 while (it.next()) |kv| {
...@@ -489,15 +489,53 @@ pub const Object = struct {...@@ -489,15 +489,53 @@ pub const Object = struct {
489 object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);489 object.llvm_module.setModuleInlineAsm2(buffer.items.ptr, buffer.items.len - 1);
490 }490 }
491491
492 fn resolveExportExternCollisions(object: *Object) !void {
493 const mod = object.module;
494
495 const export_keys = mod.decl_exports.keys();
496 for (mod.decl_exports.values()) |export_list, i| {
497 const decl_index = export_keys[i];
498 const llvm_global = object.decl_map.get(decl_index) orelse continue;
499 for (export_list) |exp| {
500 // Detect if the LLVM global has already been created as an extern. In such
501 // case, we need to replace all uses of it with this exported global.
502 // TODO update std.builtin.ExportOptions to have the name be a
503 // null-terminated slice.
504 const exp_name_z = try mod.gpa.dupeZ(u8, exp.options.name);
505 defer mod.gpa.free(exp_name_z);
506
507 const other_global = object.getLlvmGlobal(exp_name_z.ptr) orelse continue;
508 if (other_global == llvm_global) continue;
509
510 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
511 // the new global to the old type and use that as the thing to replace
512 // old uses.
513 const new_global_ptr = llvm_global.constBitCast(other_global.typeOf());
514 other_global.replaceAllUsesWith(new_global_ptr);
515 llvm_global.takeName(other_global);
516 other_global.deleteGlobal();
517 // Problem: now we need to replace in the decl_map that
518 // the extern decl index points to this new global. However we don't
519 // know the decl index.
520 // Even if we did, a future incremental update to the extern would then
521 // treat the LLVM global as an extern rather than an export, so it would
522 // need a way to check that.
523 // This is a TODO that needs to be solved when making
524 // the LLVM backend support incremental compilation.
525 }
526 }
527 }
528
492 pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {529 pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {
493 var sub_prog_node = prog_node.start("LLVM Emit Object", 0);530 var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
494 sub_prog_node.activate();531 sub_prog_node.activate();
495 sub_prog_node.context.refresh();532 sub_prog_node.context.refresh();
496 defer sub_prog_node.end();533 defer sub_prog_node.end();
497534
498 try self.genErrorNameTable(comp);535 try self.resolveExportExternCollisions();
499 try self.genCmpLtErrorsLenFunction(comp);536 try self.genErrorNameTable();
500 try self.genModuleLevelAssembly(comp);537 try self.genCmpLtErrorsLenFunction();
538 try self.genModuleLevelAssembly();
501539
502 if (self.di_builder) |dib| {540 if (self.di_builder) |dib| {
503 // When lowering debug info for pointers, we emitted the element types as541 // When lowering debug info for pointers, we emitted the element types as
...@@ -761,6 +799,14 @@ pub const Object = struct {...@@ -761,6 +799,14 @@ pub const Object = struct {
761 try self.updateDeclExports(module, decl_index, decl_exports);799 try self.updateDeclExports(module, decl_index, decl_exports);
762 }800 }
763801
802 /// TODO replace this with a call to `Module::getNamedValue`. This will require adding
803 /// a new wrapper in zig_llvm.h/zig_llvm.cpp.
804 fn getLlvmGlobal(o: Object, name: [*:0]const u8) ?*const llvm.Value {
805 if (o.llvm_module.getNamedFunction(name)) |x| return x;
806 if (o.llvm_module.getNamedGlobal(name)) |x| return x;
807 return null;
808 }
809
764 pub fn updateDeclExports(810 pub fn updateDeclExports(
765 self: *Object,811 self: *Object,
766 module: *Module,812 module: *Module,
...@@ -827,6 +873,7 @@ pub const Object = struct {...@@ -827,6 +873,7 @@ pub const Object = struct {
827 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);873 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
828 }874 }
829 }875 }
876
830 // If a Decl is exported more than one time (which is rare),877 // If a Decl is exported more than one time (which is rare),
831 // we add aliases for all but the first export.878 // we add aliases for all but the first export.
832 // TODO LLVM C API does not support deleting aliases. We need to879 // TODO LLVM C API does not support deleting aliases. We need to
...@@ -5632,7 +5679,8 @@ pub const FuncGen = struct {...@@ -5632,7 +5679,8 @@ pub const FuncGen = struct {
5632 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5679 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5633 if (self.liveness.isUnused(inst)) return null;5680 if (self.liveness.isUnused(inst)) return null;
56345681
5635 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5682 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5683 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
5636 const base_ptr = try self.resolveInst(bin_op.lhs);5684 const base_ptr = try self.resolveInst(bin_op.lhs);
5637 const offset = try self.resolveInst(bin_op.rhs);5685 const offset = try self.resolveInst(bin_op.rhs);
5638 const ptr_ty = self.air.typeOf(bin_op.lhs);5686 const ptr_ty = self.air.typeOf(bin_op.lhs);
...@@ -5651,7 +5699,8 @@ pub const FuncGen = struct {...@@ -5651,7 +5699,8 @@ pub const FuncGen = struct {
5651 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5699 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5652 if (self.liveness.isUnused(inst)) return null;5700 if (self.liveness.isUnused(inst)) return null;
56535701
5654 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5702 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5703 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
5655 const base_ptr = try self.resolveInst(bin_op.lhs);5704 const base_ptr = try self.resolveInst(bin_op.lhs);
5656 const offset = try self.resolveInst(bin_op.rhs);5705 const offset = try self.resolveInst(bin_op.rhs);
5657 const negative_offset = self.builder.buildNeg(offset, "");5706 const negative_offset = self.builder.buildNeg(offset, "");
src/print_air.zig+6-17
...@@ -114,8 +114,6 @@ const Writer = struct {...@@ -114,8 +114,6 @@ const Writer = struct {
114 .div_exact,114 .div_exact,
115 .rem,115 .rem,
116 .mod,116 .mod,
117 .ptr_add,
118 .ptr_sub,
119 .bit_and,117 .bit_and,
120 .bit_or,118 .bit_or,
121 .xor,119 .xor,
...@@ -231,6 +229,12 @@ const Writer = struct {...@@ -231,6 +229,12 @@ const Writer = struct {
231 .slice,229 .slice,
232 .slice_elem_ptr,230 .slice_elem_ptr,
233 .ptr_elem_ptr,231 .ptr_elem_ptr,
232 .ptr_add,
233 .ptr_sub,
234 .add_with_overflow,
235 .sub_with_overflow,
236 .mul_with_overflow,
237 .shl_with_overflow,
234 => try w.writeTyPlBin(s, inst),238 => try w.writeTyPlBin(s, inst),
235239
236 .call,240 .call,
...@@ -275,12 +279,6 @@ const Writer = struct {...@@ -275,12 +279,6 @@ const Writer = struct {
275 .reduce => try w.writeReduce(s, inst),279 .reduce => try w.writeReduce(s, inst),
276 .cmp_vector => try w.writeCmpVector(s, inst),280 .cmp_vector => try w.writeCmpVector(s, inst),
277281
278 .add_with_overflow,
279 .sub_with_overflow,
280 .mul_with_overflow,
281 .shl_with_overflow,
282 => try w.writeOverflow(s, inst),
283
284 .dbg_block_begin, .dbg_block_end => {},282 .dbg_block_begin, .dbg_block_end => {},
285 }283 }
286 }284 }
...@@ -478,15 +476,6 @@ const Writer = struct {...@@ -478,15 +476,6 @@ const Writer = struct {
478 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });476 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
479 }477 }
480478
481 fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
482 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
483 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
484
485 try w.writeOperand(s, inst, 0, extra.lhs);
486 try s.writeAll(", ");
487 try w.writeOperand(s, inst, 1, extra.rhs);
488 }
489
490 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {479 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
491 const pl_op = w.air.instructions.items(.data)[inst].pl_op;480 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
492 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;481 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
src/value.zig-22
...@@ -1813,27 +1813,6 @@ pub const Value = extern union {...@@ -1813,27 +1813,6 @@ pub const Value = extern union {
1813 };1813 };
1814 }1814 }
18151815
1816 /// Asserts the value is numeric
1817 pub fn isZero(self: Value) bool {
1818 return switch (self.tag()) {
1819 .zero, .the_only_possible_value => true,
1820 .one => false,
1821
1822 .int_u64 => self.castTag(.int_u64).?.data == 0,
1823 .int_i64 => self.castTag(.int_i64).?.data == 0,
1824
1825 .float_16 => self.castTag(.float_16).?.data == 0,
1826 .float_32 => self.castTag(.float_32).?.data == 0,
1827 .float_64 => self.castTag(.float_64).?.data == 0,
1828 .float_80 => self.castTag(.float_80).?.data == 0,
1829 .float_128 => self.castTag(.float_128).?.data == 0,
1830
1831 .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
1832 .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(),
1833 else => unreachable,
1834 };
1835 }
1836
1837 pub fn orderAgainstZero(lhs: Value) std.math.Order {1816 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1838 return orderAgainstZeroAdvanced(lhs, null) catch unreachable;1817 return orderAgainstZeroAdvanced(lhs, null) catch unreachable;
1839 }1818 }
...@@ -3442,7 +3421,6 @@ pub const Value = extern union {...@@ -3442,7 +3421,6 @@ pub const Value = extern union {
3442 const info = ty.intInfo(target);3421 const info = ty.intInfo(target);
34433422
3444 if (info.bits == 0) {3423 if (info.bits == 0) {
3445 assert(val.isZero()); // Sema should guarantee
3446 return val;3424 return val;
3447 }3425 }
34483426
test/behavior/align.zig+16-5
...@@ -16,11 +16,22 @@ test "global variable alignment" {...@@ -16,11 +16,22 @@ test "global variable alignment" {
16 const slice = @as(*align(4) [1]u8, &foo)[0..];16 const slice = @as(*align(4) [1]u8, &foo)[0..];
17 comptime try expect(@TypeOf(slice) == *align(4) [1]u8);17 comptime try expect(@TypeOf(slice) == *align(4) [1]u8);
18 }18 }
19 {19}
20 var runtime_zero: usize = 0;20
21 const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];21test "slicing array of length 1 can assume runtime index is always zero" {
22 comptime try expect(@TypeOf(slice) == []align(4) u8);22 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
23 }23
24 // TODO reevaluate this test case, because notice that you can
25 // change `runtime_zero` to be `1` and the test still passes for stage1.
26 // Reconsider also this code:
27 // var array: [4]u8 = undefined;
28 // var runtime: usize = 4;
29 // var ptr = array[runtime..];
30 // _ = ptr;
31
32 var runtime_zero: usize = 0;
33 const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];
34 comptime try expect(@TypeOf(slice) == []align(4) u8);
24}35}
2536
26test "default alignment allows unspecified in type syntax" {37test "default alignment allows unspecified in type syntax" {
test/behavior/basic.zig+5-1
...@@ -797,7 +797,11 @@ test "auto created variables have correct alignment" {...@@ -797,7 +797,11 @@ test "auto created variables have correct alignment" {
797}797}
798798
799test "extern variable with non-pointer opaque type" {799test "extern variable with non-pointer opaque type" {
800 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO800 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
801 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
801805
802 @export(var_to_export, .{ .name = "opaque_extern_var" });806 @export(var_to_export, .{ .name = "opaque_extern_var" });
803 try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42);807 try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42);
test/behavior/cast.zig+6-3
...@@ -326,8 +326,7 @@ test "array coersion to undefined at runtime" {...@@ -326,8 +326,7 @@ test "array coersion to undefined at runtime" {
326326
327 @setRuntimeSafety(true);327 @setRuntimeSafety(true);
328328
329 // TODO implement @setRuntimeSafety in stage2329 if (builtin.mode != .Debug and builtin.mode != .ReleaseSafe) {
330 if (builtin.zig_backend != .stage1 and builtin.mode != .Debug and builtin.mode != .ReleaseSafe) {
331 return error.SkipZigTest;330 return error.SkipZigTest;
332 }331 }
333332
...@@ -588,7 +587,11 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {...@@ -588,7 +587,11 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
588}587}
589588
590test "vector casts" {589test "vector casts" {
591 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO590 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
591 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
592 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
594 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
592595
593 const S = struct {596 const S = struct {
594 fn doTheTest() !void {597 fn doTheTest() !void {
test/behavior/eval.zig+7
...@@ -1110,3 +1110,10 @@ test "no dependency loop for alignment of self tagged union" {...@@ -1110,3 +1110,10 @@ test "no dependency loop for alignment of self tagged union" {
1110 };1110 };
1111 try S.doTheTest();1111 try S.doTheTest();
1112}1112}
1113
1114test "equality of pointers to comptime const" {
1115 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1116
1117 const a: i32 = undefined;
1118 comptime assert(&a == &a);
1119}
test/behavior/pointers.zig+6-4
...@@ -214,7 +214,10 @@ test "allowzero pointer and slice" {...@@ -214,7 +214,10 @@ test "allowzero pointer and slice" {
214}214}
215215
216test "assign null directly to C pointer and test null equality" {216test "assign null directly to C pointer and test null equality" {
217 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO217 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
218 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
218221
219 var x: [*c]i32 = null;222 var x: [*c]i32 = null;
220 try expect(x == null);223 try expect(x == null);
...@@ -238,7 +241,8 @@ test "assign null directly to C pointer and test null equality" {...@@ -238,7 +241,8 @@ test "assign null directly to C pointer and test null equality" {
238 @panic("fail");241 @panic("fail");
239 }242 }
240 const othery: i32 = undefined;243 const othery: i32 = undefined;
241 comptime try expect((y orelse &othery) == &othery);244 const ptr_othery = &othery;
245 comptime try expect((y orelse ptr_othery) == ptr_othery);
242246
243 var n: i32 = 1234;247 var n: i32 = 1234;
244 var x1: [*c]i32 = &n;248 var x1: [*c]i32 = &n;
...@@ -373,8 +377,6 @@ test "pointer to array at fixed address" {...@@ -373,8 +377,6 @@ test "pointer to array at fixed address" {
373}377}
374378
375test "pointer arithmetic affects the alignment" {379test "pointer arithmetic affects the alignment" {
376 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
377
378 {380 {
379 var ptr: [*]align(8) u32 = undefined;381 var ptr: [*]align(8) u32 = undefined;
380 var x: usize = 1;382 var x: usize = 1;