| author | |
| committer | |
| log | b6798c26efc4689cf35c5f4ac0436b4510a1f813 |
| tree | 9507321f623264de9c5bef41ff53c19c88f09bd3 |
| parent | 95f5e17e49d32a301d6a9d6f9948719d65469b09 |
This makes it so the result of doing pointer arithmetic creates a new
pointer type that has adjusted alignment.16 files changed, 464 insertions(+), 340 deletions(-)
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+53-17| ... | @@ -10610,28 +10610,55 @@ fn analyzePtrArithmetic( | ... | @@ -10610,28 +10610,55 @@ fn analyzePtrArithmetic( |
| 10610 | // TODO if the operand is comptime-known to be negative, or is a negative int, | 10610 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| 10611 | // coerce to isize instead of usize. | 10611 | // coerce to isize instead of usize. |
| 10612 | const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); | 10612 | 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(); | 10613 | const target = sema.mod.getTarget(); |
| 10615 | const runtime_src = rs: { | 10614 | const opt_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, ptr); |
| 10616 | if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { | 10615 | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); |
| 10617 | if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| { | 10616 | const ptr_ty = sema.typeOf(ptr); |
| 10618 | const ptr_ty = sema.typeOf(ptr); | 10617 | const ptr_info = ptr_ty.ptrInfo().data; |
| 10619 | const new_ptr_ty = ptr_ty; // TODO modify alignment | 10618 | const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array) |
| 10619 | ptr_info.pointee_type.childType() | ||
| 10620 | else | ||
| 10621 | ptr_info.pointee_type; | ||
| 10622 | |||
| 10623 | const new_ptr_ty = t: { | ||
| 10624 | // Calculate the new pointer alignment. | ||
| 10625 | if (ptr_info.@"align" == 0) { | ||
| 10626 | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. | ||
| 10627 | break :t ptr_ty; | ||
| 10628 | } | ||
| 10629 | // If the addend is not a comptime-known value we can still count on | ||
| 10630 | // it being a multiple of the type size. | ||
| 10631 | const elem_size = elem_ty.abiSize(target); | ||
| 10632 | const addend = if (opt_off_val) |off_val| a: { | ||
| 10633 | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target)); | ||
| 10634 | break :a elem_size * off_int; | ||
| 10635 | } else elem_size; | ||
| 10636 | |||
| 10637 | // The resulting pointer is aligned to the lcd between the offset (an | ||
| 10638 | // arbitrary number) and the alignment factor (always a power of two, | ||
| 10639 | // non zero). | ||
| 10640 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, addend | ptr_info.@"align")); | ||
| 10641 | |||
| 10642 | break :t try Type.ptr(sema.arena, sema.mod, .{ | ||
| 10643 | .pointee_type = ptr_info.pointee_type, | ||
| 10644 | .sentinel = ptr_info.sentinel, | ||
| 10645 | .@"align" = new_align, | ||
| 10646 | .@"addrspace" = ptr_info.@"addrspace", | ||
| 10647 | .mutable = ptr_info.mutable, | ||
| 10648 | .@"allowzero" = ptr_info.@"allowzero", | ||
| 10649 | .@"volatile" = ptr_info.@"volatile", | ||
| 10650 | .size = ptr_info.size, | ||
| 10651 | }); | ||
| 10652 | }; | ||
| 10620 | 10653 | ||
| 10621 | if (ptr_val.isUndef() or offset_val.isUndef()) { | 10654 | const runtime_src = rs: { |
| 10622 | return sema.addConstUndef(new_ptr_ty); | 10655 | if (opt_ptr_val) |ptr_val| { |
| 10623 | } | 10656 | if (opt_off_val) |offset_val| { |
| 10657 | if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty); | ||
| 10624 | 10658 | ||
| 10625 | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target)); | 10659 | 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; | 10660 | if (offset_int == 0) return ptr; |
| 10628 | if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| { | 10661 | 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); | 10662 | const elem_size = elem_ty.abiSize(target); |
| 10636 | const new_addr = switch (air_tag) { | 10663 | const new_addr = switch (air_tag) { |
| 10637 | .ptr_add => addr + elem_size * offset_int, | 10664 | .ptr_add => addr + elem_size * offset_int, |
| ... | @@ -10651,7 +10678,16 @@ fn analyzePtrArithmetic( | ... | @@ -10651,7 +10678,16 @@ fn analyzePtrArithmetic( |
| 10651 | }; | 10678 | }; |
| 10652 | 10679 | ||
| 10653 | try sema.requireRuntimeBlock(block, runtime_src); | 10680 | try sema.requireRuntimeBlock(block, runtime_src); |
| 10654 | return block.addBinOp(air_tag, ptr, offset); | 10681 | return block.addInst(.{ |
| 10682 | .tag = air_tag, | ||
| 10683 | .data = .{ .ty_pl = .{ | ||
| 10684 | .ty = try sema.addType(new_ptr_ty), | ||
| 10685 | .payload = try sema.addExtra(Air.Bin{ | ||
| 10686 | .lhs = ptr, | ||
| 10687 | .rhs = offset, | ||
| 10688 | }), | ||
| 10689 | } }, | ||
| 10690 | }); | ||
| 10655 | } | 10691 | } |
| 10656 | 10692 | ||
| 10657 | fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10693 | fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
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+4-2| ... | @@ -5679,7 +5679,8 @@ pub const FuncGen = struct { | ... | @@ -5679,7 +5679,8 @@ pub const FuncGen = struct { |
| 5679 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5679 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 5680 | if (self.liveness.isUnused(inst)) return null; | 5680 | if (self.liveness.isUnused(inst)) return null; |
| 5681 | 5681 | ||
| 5682 | 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; | ||
| 5683 | const base_ptr = try self.resolveInst(bin_op.lhs); | 5684 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5684 | const offset = try self.resolveInst(bin_op.rhs); | 5685 | const offset = try self.resolveInst(bin_op.rhs); |
| 5685 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 5686 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| ... | @@ -5698,7 +5699,8 @@ pub const FuncGen = struct { | ... | @@ -5698,7 +5699,8 @@ pub const FuncGen = struct { |
| 5698 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5699 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 5699 | if (self.liveness.isUnused(inst)) return null; | 5700 | if (self.liveness.isUnused(inst)) return null; |
| 5700 | 5701 | ||
| 5701 | 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; | ||
| 5702 | const base_ptr = try self.resolveInst(bin_op.lhs); | 5704 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5703 | const offset = try self.resolveInst(bin_op.rhs); | 5705 | const offset = try self.resolveInst(bin_op.rhs); |
| 5704 | 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/pointers.zig-2| ... | @@ -377,8 +377,6 @@ test "pointer to array at fixed address" { | ... | @@ -377,8 +377,6 @@ test "pointer to array at fixed address" { |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | test "pointer arithmetic affects the alignment" { | 379 | test "pointer arithmetic affects the alignment" { |
| 380 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | ||
| 381 | |||
| 382 | { | 380 | { |
| 383 | var ptr: [*]align(8) u32 = undefined; | 381 | var ptr: [*]align(8) u32 = undefined; |
| 384 | var x: usize = 1; | 382 | var x: usize = 1; |