| author | |
| committer | |
| log | 8660661af4626c4bd589e6c6331a6ac786143f12 |
| tree | 0c771125a45adab3a9d80cbc6b101cad2bed0fd1 |
| parent | e252f92b9947e82f2473a37a74d5f9dc278a1c1d |
| parent | 9031cc54f27b4483c62ab904dd94063a9499c842 |
| signature |
stage2: bug fixes towards more behavior tests passing20 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 | }; |
| 894 | 894 | ||
| 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; |
| 916 | 917 | ||
| 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; |
| 920 | 921 | ||
| 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; |
| 924 | 925 | ||
| 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); |
| 932 | 933 | ||
| 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 | }; |
| 936 | 937 | ||
| ... | @@ -954,7 +955,7 @@ const LinuxThreadImpl = struct { | ... | @@ -954,7 +955,7 @@ const LinuxThreadImpl = struct { |
| 954 | 955 | ||
| 955 | // map everything but the guard page as read/write | 956 | // 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 pages | 345 | // 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 | } |
| 350 | 350 | ||
| 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 the | 124 | /// 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), |
| 993 | 993 | ||
| 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 | }, |
| 443 | 441 | ||
| 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 vectors | 7023 | 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); |
| 7026 | 7026 | ||
| 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 | } |
| 7032 | 7032 | ||
| 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 == 0 | 7037 | // 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; |
| 7040 | 7043 | ||
| 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 shrinkage | 7064 | // range shrinkage |
| 7063 | // requirement: int value fits into target type | 7065 | // 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); |
| 7068 | 7074 | ||
| ... | @@ -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); |
| 7082 | 7088 | ||
| 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 loss | 7122 | // no shrinkage, yes sign loss |
| 7091 | // requirement: signed to unsigned >= 0 | 7123 | // 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 alignment | 10664 | 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 | }; | ||
| 10620 | 10699 | ||
| 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); | ||
| 10624 | 10704 | ||
| 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 | }; |
| 10652 | 10725 | ||
| 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 | } |
| 10656 | 10738 | ||
| 10657 | fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10739 | fn 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); |
| 14711 | 14793 | ||
| 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( |
| 15059 | fn checkIntOrVectorAllowComptime( | 15141 | fn 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 { |
| 545 | 545 | ||
| 546 | switch (air_tags[inst]) { | 546 | switch (air_tags[inst]) { |
| 547 | // zig fmt: off | 547 | // 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), |
| 597 | 609 | ||
| 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 { |
| 1260 | fn binOpRegister( | 1265 | fn 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]; |
| 1285 | 1290 | ||
| 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; |
| 1291 | 1295 | ||
| 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); |
| 1301 | 1305 | ||
| 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; |
| 1307 | 1310 | ||
| 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( |
| 1317 | 1320 | ||
| 1318 | const dest_reg = switch (mir_tag) { | 1321 | const dest_reg = switch (mir_tag) { |
| 1319 | .cmp_shifted_register => undefined, // cmp has no destination register | 1322 | .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( |
| 1407 | fn binOpImmediate( | 1408 | fn 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; |
| 1417 | 1418 | ||
| ... | @@ -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]; |
| 1425 | 1426 | ||
| 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; |
| 1433 | 1433 | ||
| ... | @@ -1443,18 +1443,16 @@ fn binOpImmediate( | ... | @@ -1443,18 +1443,16 @@ fn binOpImmediate( |
| 1443 | 1443 | ||
| 1444 | const dest_reg = switch (mir_tag) { | 1444 | const dest_reg = switch (mir_tag) { |
| 1445 | .cmp_immediate => undefined, // cmp has no destination register | 1445 | .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 | } |
| 1500 | 1498 | ||
| 1499 | const 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 generate | 1505 | /// For all your binary operation needs, this function will generate |
| 1502 | /// the corresponding Mir instruction(s). Returns the location of the | 1506 | /// 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( |
| 1513 | fn binOp( | 1517 | fn 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 | }; |
| 1563 | 1567 | ||
| 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 rhs | 1571 | // 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 multiplication | 1590 | // TODO add optimisations for multiplication |
| 1587 | // with immediates, for example a * 2 can be | 1591 | // with immediates, for example a * 2 can be |
| 1588 | // lowered to a << 1 | 1592 | // 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 | }; |
| 1607 | 1611 | ||
| 1608 | // Generate an add/sub/mul | 1612 | // 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); |
| 1610 | 1614 | ||
| 1611 | // Truncate if necessary | 1615 | // 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 | }; |
| 1644 | 1648 | ||
| 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 | }; |
| 1679 | 1683 | ||
| 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 | }; |
| 1700 | 1704 | ||
| 1701 | // Generate a shl_exact/shr_exact | 1705 | // 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); |
| 1703 | 1707 | ||
| 1704 | // Truncate if necessary | 1708 | // 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 | }; |
| 1737 | 1741 | ||
| 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 | }; |
| 1761 | 1765 | ||
| 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 by | 1768 | // convert the offset into a byte offset by |
| 1765 | // multiplying it with elem_size | 1769 | // 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 | } |
| 1777 | 1781 | ||
| 1778 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1782 | fn 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 | .dead | 1790 | .dead |
| 1788 | else | 1791 | 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 | |||
| 1800 | fn 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 | } |
| 1792 | 1818 | ||
| ... | @@ -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); |
| 1856 | 1882 | ||
| 1857 | // cmp dest, truncated | 1883 | // 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); |
| 1859 | 1885 | ||
| 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 { |
| 1894 | 1920 | ||
| 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 rhs | 1925 | // 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 | }; |
| 1905 | 1931 | ||
| ... | @@ -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 | }; |
| 1954 | 1980 | ||
| 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 { |
| 2136 | 2162 | ||
| 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 | ); |
| 2145 | 2171 | ||
| 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 { |
| 2156 | 2182 | ||
| 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; |
| 2219 | 2245 | ||
| 2220 | // lsl dest, lhs, rhs | 2246 | // 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); |
| 2225 | 2251 | ||
| 2226 | // asr/lsr reconstructed, dest, rhs | 2252 | // 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); |
| 2228 | 2254 | ||
| 2229 | // cmp lhs, reconstructed | 2255 | // 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); |
| 2231 | 2257 | ||
| 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); |
| 2494 | 2520 | ||
| 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 |
| 2933 | 2959 | ||
| 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 | ); |
| 2942 | 2968 | ||
| 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 { |
| 3302 | 3328 | ||
| 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 | }); | ||
| 3306 | 3336 | ||
| 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 { |
| 552 | 552 | ||
| 553 | switch (air_tags[inst]) { | 553 | switch (air_tags[inst]) { |
| 554 | // zig fmt: off | 554 | // 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), |
| 571 | 584 | ||
| 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), |
| 604 | 617 | ||
| 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 above | 1267 | assert(lhs_reg != rhs_reg); // see note above |
| 1262 | 1268 | ||
| 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); |
| 1264 | 1270 | ||
| 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 | } |
| 1342 | 1348 | ||
| 1343 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1349 | fn 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); |
| 1350 | 1355 | ||
| 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 | |||
| 1367 | fn 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 | } |
| 1354 | 1385 | ||
| ... | @@ -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); |
| 1416 | 1447 | ||
| 1417 | // cmp dest, truncated | 1448 | // 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); |
| 1419 | 1450 | ||
| 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 { |
| 1448 | 1479 | ||
| 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 rhs | 1484 | // 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 | }; |
| 1459 | 1490 | ||
| ... | @@ -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 | }; |
| 1509 | 1540 | ||
| 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); |
| 1521 | 1552 | ||
| 1522 | // cmp dest, truncated | 1553 | // 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); |
| 1524 | 1555 | ||
| 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 }); |
| 1595 | 1626 | ||
| 1596 | // cmp truncated, rdlo | 1627 | // 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); |
| 1598 | 1629 | ||
| 1599 | // mov rdlo, #0 | 1630 | // 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 | }); |
| 1619 | 1650 | ||
| 1620 | // cmp rdhi, #0 | 1651 | // 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); |
| 1622 | 1653 | ||
| 1623 | // movne rdlo, #1 | 1654 | // 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; |
| 1678 | 1709 | ||
| 1679 | // lsl dest, lhs, rhs | 1710 | // 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); |
| 1684 | 1715 | ||
| 1685 | // asr/lsr reconstructed, dest, rhs | 1716 | // 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); |
| 1687 | 1718 | ||
| 1688 | // cmp lhs, reconstructed | 1719 | // 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); |
| 1690 | 1721 | ||
| 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); |
| 2036 | 2067 | ||
| 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 { |
| 2051 | 2082 | ||
| 2052 | const slice_ty = self.air.typeOf(extra.lhs); | 2083 | const slice_ty = self.air.typeOf(extra.lhs); |
| 2053 | 2084 | ||
| 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 { |
| 2079 | 2110 | ||
| 2080 | const ptr_ty = self.air.typeOf(extra.lhs); | 2111 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2081 | 2112 | ||
| 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 |
| 2411 | 2442 | ||
| 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 | ); |
| 2420 | 2451 | ||
| 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 { |
| 2514 | fn binOpRegister( | 2545 | fn 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]; |
| 2533 | 2564 | ||
| 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; |
| 2539 | 2569 | ||
| 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); |
| 2548 | 2578 | ||
| 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; |
| 2554 | 2583 | ||
| 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( |
| 2563 | 2592 | ||
| 2564 | const dest_reg = switch (mir_tag) { | 2593 | const dest_reg = switch (mir_tag) { |
| 2565 | .cmp => .r0, // cmp has no destination regardless | 2594 | .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( |
| 2634 | fn binOpImmediate( | 2661 | fn 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; |
| 2644 | 2671 | ||
| ... | @@ -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]; |
| 2652 | 2679 | ||
| 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; |
| 2660 | 2686 | ||
| ... | @@ -2669,18 +2695,16 @@ fn binOpImmediate( | ... | @@ -2669,18 +2695,16 @@ fn binOpImmediate( |
| 2669 | 2695 | ||
| 2670 | const dest_reg = switch (mir_tag) { | 2696 | const dest_reg = switch (mir_tag) { |
| 2671 | .cmp => .r0, // cmp has no destination reg | 2697 | .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 | } |
| 2722 | 2746 | ||
| 2747 | const 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 generate | 2753 | /// For all your binary operation needs, this function will generate |
| 2724 | /// the corresponding Mir instruction(s). Returns the location of the | 2754 | /// 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( |
| 2735 | fn binOp( | 2765 | fn 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 | }; |
| 2781 | 2811 | ||
| 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 rhs | 2815 | // 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 multiplication | 2836 | // TODO add optimisations for multiplication |
| 2807 | // with immediates, for example a * 2 can be | 2837 | // with immediates, for example a * 2 can be |
| 2808 | // lowered to a << 1 | 2838 | // 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 | }; |
| 2827 | 2857 | ||
| 2828 | // Generate an add/sub/mul | 2858 | // 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); |
| 2830 | 2860 | ||
| 2831 | // Truncate if necessary | 2861 | // 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 | }; |
| 2870 | 2900 | ||
| 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 rhs | 2904 | // 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 | }; |
| 2904 | 2934 | ||
| 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 | }; |
| 2925 | 2955 | ||
| 2926 | // Generate a shl_exact/shr_exact | 2956 | // 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); |
| 2928 | 2958 | ||
| 2929 | // Truncate if necessary | 2959 | // Truncate if necessary |
| 2930 | switch (tag) { | 2960 | switch (tag) { |
| ... | @@ -2964,12 +2994,12 @@ fn binOp( | ... | @@ -2964,12 +2994,12 @@ fn binOp( |
| 2964 | }; | 2994 | }; |
| 2965 | 2995 | ||
| 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 rhs | 2999 | // 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 | }; |
| 2996 | 3026 | ||
| 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 by | 3029 | // convert the offset into a byte offset by |
| 3000 | // multiplying it with elem_size | 3030 | // 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; |
| 3577 | 3607 | ||
| 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 | }); | ||
| 3579 | 3613 | ||
| 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 | } |
| 3866 | 3900 | ||
| 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 | } |
| 3871 | 3905 |
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 { |
| 481 | 481 | ||
| 482 | switch (air_tags[inst]) { | 482 | switch (air_tags[inst]) { |
| 483 | // zig fmt: off | 483 | // 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 | } |
| 1093 | 1097 | ||
| 1094 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1098 | fn 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 | } |
| 1105 | 1108 | ||
| 1109 | fn 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 | |||
| 1106 | fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void { | 1121 | fn 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 { |
| 483 | 483 | ||
| 484 | switch (air_tags[inst]) { | 484 | switch (air_tags[inst]) { |
| 485 | // zig fmt: off | 485 | // 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 | } |
| 829 | 832 | ||
| 830 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 833 | fn 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 | } | ||
| 837 | 849 | ||
| 850 | fn 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 | .dead | 858 | .dead |
| 840 | else | 859 | 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 | } |
| 844 | 867 | ||
| ... | @@ -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 { |
| 1030 | 1053 | ||
| 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 { |
| 1053 | 1076 | ||
| 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 | }); | ||
| 1057 | 1084 | ||
| 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 modes | 1453 | // 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+I | 1454 | // 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); |
| 1431 | 1458 | ||
| 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 | } |
| 1597 | 1624 | ||
| 1625 | const 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 generate | 1631 | /// For all your binary operation needs, this function will generate |
| 1599 | /// the corresponding Mir instruction(s). Returns the location of the | 1632 | /// 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 { |
| 1610 | fn binOp( | 1643 | fn 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 | }; |
| 1650 | 1683 | ||
| 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 rhs | 1687 | // 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 adding | 1690 | // 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 instead | 1716 | // If it's a power of two immediate then we emit an shl instead |
| 1684 | // TODO add similar checks for LHS | 1717 | // 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 | } |
| 1688 | 1721 | ||
| 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 | }; |
| 1713 | 1746 | ||
| 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 by | 1749 | // convert the offset into a byte offset by |
| 1717 | // multiplying it with elem_size | 1750 | // multiplying it with elem_size |
| 1718 | 1751 | ||
| 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 | }; |
| 1733 | 1766 | ||
| 1734 | // Generate a shl_exact/shr_exact | 1767 | // 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); |
| 1736 | 1769 | ||
| 1737 | // Truncate if necessary | 1770 | // Truncate if necessary |
| 1738 | switch (tag) { | 1771 | switch (tag) { |
| ... | @@ -1768,9 +1801,9 @@ fn binOp( | ... | @@ -1768,9 +1801,9 @@ fn binOp( |
| 1768 | }; | 1801 | }; |
| 1769 | 1802 | ||
| 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_imm | 1825 | /// op dest, lhs, #rhs_imm |
| 1793 | /// | 1826 | /// |
| 1794 | /// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to | 1827 | /// 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. |
| 1799 | fn binOpImmediate( | 1831 | fn 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; |
| 1809 | 1841 | ||
| ... | @@ -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]; |
| 1817 | 1849 | ||
| 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; |
| 1825 | 1856 | ||
| ... | @@ -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); |
| 1834 | 1865 | ||
| 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( |
| 1896 | fn binOpRegister( | 1925 | fn 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]; |
| 1921 | 1950 | ||
| 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; |
| 1927 | 1955 | ||
| 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); |
| 1935 | 1963 | ||
| 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; |
| 1941 | 1968 | ||
| 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); |
| 1949 | 1976 | ||
| 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 |
| 3069 | 3094 | ||
| 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 | ); |
| 3078 | 3103 | ||
| 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 { |
| 3397 | 3397 | ||
| 3398 | fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | 3398 | fn 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 { |
| 574 | 574 | ||
| 575 | switch (air_tags[inst]) { | 575 | switch (air_tags[inst]) { |
| 576 | // zig fmt: off | 576 | // 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), |
| 595 | 605 | ||
| 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), |
| 628 | 638 | ||
| 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 | } |
| 1233 | 1236 | ||
| 1234 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | 1237 | fn 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; |
| 1236 | 1239 | ||
| 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 | } |
| 1240 | 1243 | ||
| 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); | ||
| 1246 | 1247 | ||
| 1247 | const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | 1248 | fn 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 | } | ||
| 1248 | 1255 | ||
| 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 | } |
| 1251 | 1259 | ||
| ... | @@ -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 | } |
| 1318 | 1326 | ||
| 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. |
| 3311 | fn genBinOp( | 3318 | fn 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), |
| 1713 | 1713 | ||
| 1714 | // TODO use a different strategy for add that communicates to the optimizer | 1714 | .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 optimizer | 1718 | // 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 | else | 1732 | 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"), | ||
| 1741 | 1737 | ||
| 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 | } |
| 2618 | 2614 | ||
| 2619 | fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { | 2615 | fn 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; | ||
| 2622 | 2617 | ||
| 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); |
| 2626 | 2622 |
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 | } |
| 397 | 397 | ||
| 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; |
| 401 | 401 | ||
| 402 | const mod = comp.bin_file.options.module.?; | 402 | const mod = self.module; |
| 403 | const target = mod.getTarget(); | 403 | const target = mod.getTarget(); |
| 404 | 404 | ||
| 405 | const llvm_ptr_ty = self.context.intType(8).pointerType(0); // TODO: Address space | 405 | 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); |
| 414 | 414 | ||
| 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); |
| 418 | 418 | ||
| 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 | } |
| 449 | 449 | ||
| 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(); |
| 455 | 455 | ||
| 456 | // Delete previous implementation. We replace it with every flush() because the | 456 | // 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 | } |
| 478 | 478 | ||
| 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 | } |
| 491 | 491 | ||
| 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(); |
| 497 | 534 | ||
| 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(); | ||
| 501 | 539 | ||
| 502 | if (self.di_builder) |dib| { | 540 | if (self.di_builder) |dib| { |
| 503 | // When lowering debug info for pointers, we emitted the element types as | 541 | // 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 | } |
| 763 | 801 | ||
| 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 to | 879 | // 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; |
| 5634 | 5681 | ||
| 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; |
| 5653 | 5701 | ||
| 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), |
| 235 | 239 | ||
| 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), |
| 277 | 281 | ||
| 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 | } |
| 480 | 478 | ||
| 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 | } |
| 1815 | 1815 | ||
| 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); |
| 3443 | 3422 | ||
| 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 | } |
| 3448 | 3426 |
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..]; | 21 | test "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 | } |
| 25 | 36 | ||
| 26 | test "default alignment allows unspecified in type syntax" { | 37 | test "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 | } |
| 798 | 798 | ||
| 799 | test "extern variable with non-pointer opaque type" { | 799 | test "extern variable with non-pointer opaque type" { |
| 800 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 800 | 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 | ||
| 801 | 805 | ||
| 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" { |
| 326 | 326 | ||
| 327 | @setRuntimeSafety(true); | 327 | @setRuntimeSafety(true); |
| 328 | 328 | ||
| 329 | // TODO implement @setRuntimeSafety in stage2 | 329 | 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 | } |
| 333 | 332 | ||
| ... | @@ -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 | } |
| 589 | 588 | ||
| 590 | test "vector casts" { | 589 | test "vector casts" { |
| 591 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 590 | 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 | ||
| 592 | 595 | ||
| 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 | |||
| 1114 | test "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 | } |
| 215 | 215 | ||
| 216 | test "assign null directly to C pointer and test null equality" { | 216 | test "assign null directly to C pointer and test null equality" { |
| 217 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 217 | 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 | ||
| 218 | 221 | ||
| 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); | ||
| 242 | 246 | ||
| 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 | } |
| 374 | 378 | ||
| 375 | test "pointer arithmetic affects the alignment" { | 379 | test "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; |