authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-17 01:52:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-17 23:50:38-07:00
logb6798c26efc4689cf35c5f4ac0436b4510a1f813
tree9507321f623264de9c5bef41ff53c19c88f09bd3
parent95f5e17e49d32a301d6a9d6f9948719d65469b09

stage2: fix pointer arithmetic result type

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 pages345 // Unmap extra pages
346 const aligned_buffer_len = alloc_len - drop_len;346 const aligned_buffer_len = alloc_len - drop_len;
347 if (aligned_buffer_len > aligned_len) {347 if (aligned_buffer_len > aligned_len) {
348 os.munmap(result_ptr[aligned_len..aligned_buffer_len]);348 os.munmap(@alignCast(mem.page_size, result_ptr[aligned_len..aligned_buffer_len]));
349 }349 }
350350
351 const new_hint = @alignCast(mem.page_size, result_ptr + aligned_len);351 const new_hint = @alignCast(mem.page_size, result_ptr + aligned_len);
src/Air.zig+4-4
...@@ -113,13 +113,13 @@ pub const Inst = struct {...@@ -113,13 +113,13 @@ pub const Inst = struct {
113 /// The offset is in element type units, not bytes.113 /// The offset is in element type units, not bytes.
114 /// Wrapping is undefined behavior.114 /// Wrapping is undefined behavior.
115 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.115 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
116 /// Uses the `bin_op` field.116 /// Uses the `ty_pl` field. Payload is `Bin`.
117 ptr_add,117 ptr_add,
118 /// Subtract an offset from a pointer, returning a new pointer.118 /// Subtract an offset from a pointer, returning a new pointer.
119 /// The offset is in element type units, not bytes.119 /// The offset is in element type units, not bytes.
120 /// Wrapping is undefined behavior.120 /// Wrapping is undefined behavior.
121 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.121 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
122 /// Uses the `bin_op` field.122 /// Uses the `ty_pl` field. Payload is `Bin`.
123 ptr_sub,123 ptr_sub,
124 /// Given two operands which can be floats, integers, or vectors, returns the124 /// Given two operands which can be floats, integers, or vectors, returns the
125 /// greater of the operands. For vectors it operates element-wise.125 /// greater of the operands. For vectors it operates element-wise.
...@@ -916,8 +916,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -916,8 +916,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
916 .bit_and,916 .bit_and,
917 .bit_or,917 .bit_or,
918 .xor,918 .xor,
919 .ptr_add,
920 .ptr_sub,
921 .shr,919 .shr,
922 .shr_exact,920 .shr_exact,
923 .shl,921 .shl,
...@@ -989,6 +987,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -989,6 +987,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
989 .sub_with_overflow,987 .sub_with_overflow,
990 .mul_with_overflow,988 .mul_with_overflow,
991 .shl_with_overflow,989 .shl_with_overflow,
990 .ptr_add,
991 .ptr_sub,
992 => return air.getRefType(datas[inst].ty_pl.ty),992 => return air.getRefType(datas[inst].ty_pl.ty),
993993
994 .not,994 .not,
src/Liveness.zig+16-15
...@@ -312,8 +312,6 @@ fn analyzeInst(...@@ -312,8 +312,6 @@ fn analyzeInst(
312 .div_exact,312 .div_exact,
313 .rem,313 .rem,
314 .mod,314 .mod,
315 .ptr_add,
316 .ptr_sub,
317 .bit_and,315 .bit_and,
318 .bit_or,316 .bit_or,
319 .xor,317 .xor,
...@@ -441,6 +439,21 @@ fn analyzeInst(...@@ -441,6 +439,21 @@ fn analyzeInst(
441 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });439 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
442 },440 },
443441
442 .add_with_overflow,
443 .sub_with_overflow,
444 .mul_with_overflow,
445 .shl_with_overflow,
446 .ptr_add,
447 .ptr_sub,
448 .ptr_elem_ptr,
449 .slice_elem_ptr,
450 .slice,
451 => {
452 const ty_pl = inst_datas[inst].ty_pl;
453 const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
454 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
455 },
456
444 .dbg_var_ptr,457 .dbg_var_ptr,
445 .dbg_var_val,458 .dbg_var_val,
446 => {459 => {
...@@ -529,10 +542,6 @@ fn analyzeInst(...@@ -529,10 +542,6 @@ fn analyzeInst(
529 const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data;542 const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data;
530 return trackOperands(a, new_set, inst, main_tomb, .{ extra.field_ptr, .none, .none });543 return trackOperands(a, new_set, inst, main_tomb, .{ extra.field_ptr, .none, .none });
531 },544 },
532 .ptr_elem_ptr, .slice_elem_ptr, .slice => {
533 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
534 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
535 },
536 .cmpxchg_strong, .cmpxchg_weak => {545 .cmpxchg_strong, .cmpxchg_weak => {
537 const extra = a.air.extraData(Air.Cmpxchg, inst_datas[inst].ty_pl.payload).data;546 const extra = a.air.extraData(Air.Cmpxchg, inst_datas[inst].ty_pl.payload).data;
538 return trackOperands(a, new_set, inst, main_tomb, .{ extra.ptr, extra.expected_value, extra.new_value });547 return trackOperands(a, new_set, inst, main_tomb, .{ extra.ptr, extra.expected_value, extra.new_value });
...@@ -558,15 +567,7 @@ fn analyzeInst(...@@ -558,15 +567,7 @@ fn analyzeInst(
558 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;567 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
559 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });568 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
560 },569 },
561 .add_with_overflow,570
562 .sub_with_overflow,
563 .mul_with_overflow,
564 .shl_with_overflow,
565 => {
566 const ty_pl = inst_datas[inst].ty_pl;
567 const extra = a.air.extraData(Air.Bin, ty_pl.payload).data;
568 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
569 },
570 .br => {571 .br => {
571 const br = inst_datas[inst].br;572 const br = inst_datas[inst].br;
572 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });573 return trackOperands(a, new_set, inst, main_tomb, .{ br.operand, .none, .none });
src/Sema.zig+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 alignment10618 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 };
1062010653
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);
1062410658
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 };
1065210679
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}
1065610692
10657fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10693fn 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 {
545545
546 switch (air_tags[inst]) {546 switch (air_tags[inst]) {
547 // zig fmt: off547 // zig fmt: off
548 .add, .ptr_add => try self.airBinOp(inst),548 .add => try self.airBinOp(inst, .add),
549 .addwrap => try self.airBinOp(inst),549 .addwrap => try self.airBinOp(inst, .addwrap),
550 .sub => try self.airBinOp(inst, .sub),
551 .subwrap => try self.airBinOp(inst, .subwrap),
552 .mul => try self.airBinOp(inst, .mul),
553 .mulwrap => try self.airBinOp(inst, .mulwrap),
554 .shl => try self.airBinOp(inst, .shl),
555 .shl_exact => try self.airBinOp(inst, .shl_exact),
556 .bool_and => try self.airBinOp(inst, .bool_and),
557 .bool_or => try self.airBinOp(inst, .bool_or),
558 .bit_and => try self.airBinOp(inst, .bit_and),
559 .bit_or => try self.airBinOp(inst, .bit_or),
560 .xor => try self.airBinOp(inst, .xor),
561 .shr => try self.airBinOp(inst, .shr),
562 .shr_exact => try self.airBinOp(inst, .shr_exact),
563
564 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
565 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
566
550 .add_sat => try self.airAddSat(inst),567 .add_sat => try self.airAddSat(inst),
551 .sub, .ptr_sub => try self.airBinOp(inst),
552 .subwrap => try self.airBinOp(inst),
553 .sub_sat => try self.airSubSat(inst),568 .sub_sat => try self.airSubSat(inst),
554 .mul => try self.airBinOp(inst),
555 .mulwrap => try self.airBinOp(inst),
556 .mul_sat => try self.airMulSat(inst),569 .mul_sat => try self.airMulSat(inst),
557 .rem => try self.airRem(inst),570 .rem => try self.airRem(inst),
558 .mod => try self.airMod(inst),571 .mod => try self.airMod(inst),
559 .shl, .shl_exact => try self.airBinOp(inst),
560 .shl_sat => try self.airShlSat(inst),572 .shl_sat => try self.airShlSat(inst),
561 .min => try self.airMin(inst),573 .min => try self.airMin(inst),
562 .max => try self.airMax(inst),574 .max => try self.airMax(inst),
...@@ -595,13 +607,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -595,13 +607,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
595 .cmp_vector => try self.airCmpVector(inst),607 .cmp_vector => try self.airCmpVector(inst),
596 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),608 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
597609
598 .bool_and => try self.airBinOp(inst),
599 .bool_or => try self.airBinOp(inst),
600 .bit_and => try self.airBinOp(inst),
601 .bit_or => try self.airBinOp(inst),
602 .xor => try self.airBinOp(inst),
603 .shr, .shr_exact => try self.airBinOp(inst),
604
605 .alloc => try self.airAlloc(inst),610 .alloc => try self.airAlloc(inst),
606 .ret_ptr => try self.airRetPtr(inst),611 .ret_ptr => try self.airRetPtr(inst),
607 .arg => try self.airArg(inst),612 .arg => try self.airArg(inst),
...@@ -1260,11 +1265,11 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1260,11 +1265,11 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1260fn binOpRegister(1265fn binOpRegister(
1261 self: *Self,1266 self: *Self,
1262 mir_tag: Mir.Inst.Tag,1267 mir_tag: Mir.Inst.Tag,
1263 maybe_inst: ?Air.Inst.Index,
1264 lhs: MCValue,1268 lhs: MCValue,
1265 rhs: MCValue,1269 rhs: MCValue,
1266 lhs_ty: Type,1270 lhs_ty: Type,
1267 rhs_ty: Type,1271 rhs_ty: Type,
1272 metadata: ?BinOpMetadata,
1268) !MCValue {1273) !MCValue {
1269 const lhs_is_register = lhs == .register;1274 const lhs_is_register = lhs == .register;
1270 const rhs_is_register = rhs == .register;1275 const rhs_is_register = rhs == .register;
...@@ -1284,9 +1289,8 @@ fn binOpRegister(...@@ -1284,9 +1289,8 @@ fn binOpRegister(
1284 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1289 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
12851290
1286 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1291 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1287 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1292 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1288 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1293 break :inst Air.refToIndex(md.lhs).?;
1289 break :inst Air.refToIndex(bin_op.lhs).?;
1290 } else null;1294 } else null;
12911295
1292 const raw_reg = try self.register_manager.allocReg(track_inst);1296 const raw_reg = try self.register_manager.allocReg(track_inst);
...@@ -1300,9 +1304,8 @@ fn binOpRegister(...@@ -1300,9 +1304,8 @@ fn binOpRegister(
1300 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1304 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
13011305
1302 const rhs_reg = if (rhs_is_register) rhs.register else blk: {1306 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1303 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1307 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1304 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1308 break :inst Air.refToIndex(md.rhs).?;
1305 break :inst Air.refToIndex(bin_op.rhs).?;
1306 } else null;1309 } else null;
13071310
1308 const raw_reg = try self.register_manager.allocReg(track_inst);1311 const raw_reg = try self.register_manager.allocReg(track_inst);
...@@ -1317,15 +1320,13 @@ fn binOpRegister(...@@ -1317,15 +1320,13 @@ fn binOpRegister(
13171320
1318 const dest_reg = switch (mir_tag) {1321 const dest_reg = switch (mir_tag) {
1319 .cmp_shifted_register => undefined, // cmp has no destination register1322 .cmp_shifted_register => undefined, // cmp has no destination register
1320 else => if (maybe_inst) |inst| blk: {1323 else => if (metadata) |md| blk: {
1321 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1324 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
1322
1323 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1324 break :blk lhs_reg;1325 break :blk lhs_reg;
1325 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1326 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1326 break :blk rhs_reg;1327 break :blk rhs_reg;
1327 } else {1328 } else {
1328 const raw_reg = try self.register_manager.allocReg(inst);1329 const raw_reg = try self.register_manager.allocReg(md.inst);
1329 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1330 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1330 }1331 }
1331 } else blk: {1332 } else blk: {
...@@ -1407,11 +1408,11 @@ fn binOpRegister(...@@ -1407,11 +1408,11 @@ fn binOpRegister(
1407fn binOpImmediate(1408fn binOpImmediate(
1408 self: *Self,1409 self: *Self,
1409 mir_tag: Mir.Inst.Tag,1410 mir_tag: Mir.Inst.Tag,
1410 maybe_inst: ?Air.Inst.Index,
1411 lhs: MCValue,1411 lhs: MCValue,
1412 rhs: MCValue,1412 rhs: MCValue,
1413 lhs_ty: Type,1413 lhs_ty: Type,
1414 lhs_and_rhs_swapped: bool,1414 lhs_and_rhs_swapped: bool,
1415 metadata: ?BinOpMetadata,
1415) !MCValue {1416) !MCValue {
1416 const lhs_is_register = lhs == .register;1417 const lhs_is_register = lhs == .register;
14171418
...@@ -1424,10 +1425,9 @@ fn binOpImmediate(...@@ -1424,10 +1425,9 @@ fn binOpImmediate(
1424 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1425 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
14251426
1426 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1427 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1427 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1428 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1428 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1429 break :inst Air.refToIndex(1429 break :inst Air.refToIndex(
1430 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1430 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1431 ).?;1431 ).?;
1432 } else null;1432 } else null;
14331433
...@@ -1443,18 +1443,16 @@ fn binOpImmediate(...@@ -1443,18 +1443,16 @@ fn binOpImmediate(
14431443
1444 const dest_reg = switch (mir_tag) {1444 const dest_reg = switch (mir_tag) {
1445 .cmp_immediate => undefined, // cmp has no destination register1445 .cmp_immediate => undefined, // cmp has no destination register
1446 else => if (maybe_inst) |inst| blk: {1446 else => if (metadata) |md| blk: {
1447 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1448
1449 if (lhs_is_register and self.reuseOperand(1447 if (lhs_is_register and self.reuseOperand(
1450 inst,1448 md.inst,
1451 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1449 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1452 if (lhs_and_rhs_swapped) 1 else 0,1450 if (lhs_and_rhs_swapped) 1 else 0,
1453 lhs,1451 lhs,
1454 )) {1452 )) {
1455 break :blk lhs_reg;1453 break :blk lhs_reg;
1456 } else {1454 } else {
1457 const raw_reg = try self.register_manager.allocReg(inst);1455 const raw_reg = try self.register_manager.allocReg(md.inst);
1458 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));1456 break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1459 }1457 }
1460 } else blk: {1458 } else blk: {
...@@ -1498,6 +1496,12 @@ fn binOpImmediate(...@@ -1498,6 +1496,12 @@ fn binOpImmediate(
1498 return MCValue{ .register = dest_reg };1496 return MCValue{ .register = dest_reg };
1499}1497}
15001498
1499const BinOpMetadata = struct {
1500 inst: Air.Inst.Index,
1501 lhs: Air.Inst.Ref,
1502 rhs: Air.Inst.Ref,
1503};
1504
1501/// For all your binary operation needs, this function will generate1505/// For all your binary operation needs, this function will generate
1502/// the corresponding Mir instruction(s). Returns the location of the1506/// the corresponding Mir instruction(s). Returns the location of the
1503/// result.1507/// result.
...@@ -1513,11 +1517,11 @@ fn binOpImmediate(...@@ -1513,11 +1517,11 @@ fn binOpImmediate(
1513fn binOp(1517fn binOp(
1514 self: *Self,1518 self: *Self,
1515 tag: Air.Inst.Tag,1519 tag: Air.Inst.Tag,
1516 maybe_inst: ?Air.Inst.Index,
1517 lhs: MCValue,1520 lhs: MCValue,
1518 rhs: MCValue,1521 rhs: MCValue,
1519 lhs_ty: Type,1522 lhs_ty: Type,
1520 rhs_ty: Type,1523 rhs_ty: Type,
1524 metadata: ?BinOpMetadata,
1521) InnerError!MCValue {1525) InnerError!MCValue {
1522 const mod = self.bin_file.options.module.?;1526 const mod = self.bin_file.options.module.?;
1523 switch (tag) {1527 switch (tag) {
...@@ -1562,12 +1566,12 @@ fn binOp(...@@ -1562,12 +1566,12 @@ fn binOp(
1562 };1566 };
15631567
1564 if (rhs_immediate_ok) {1568 if (rhs_immediate_ok) {
1565 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);1569 return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata);
1566 } else if (lhs_immediate_ok) {1570 } else if (lhs_immediate_ok) {
1567 // swap lhs and rhs1571 // swap lhs and rhs
1568 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, rhs, lhs, rhs_ty, true);1572 return try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, metadata);
1569 } else {1573 } else {
1570 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1574 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1571 }1575 }
1572 } else {1576 } else {
1573 return self.fail("TODO binary operations on int with bits > 64", .{});1577 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1586,7 +1590,7 @@ fn binOp(...@@ -1586,7 +1590,7 @@ fn binOp(
1586 // TODO add optimisations for multiplication1590 // TODO add optimisations for multiplication
1587 // with immediates, for example a * 2 can be1591 // with immediates, for example a * 2 can be
1588 // lowered to a << 11592 // lowered to a << 1
1589 return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1593 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
1590 } else {1594 } else {
1591 return self.fail("TODO binary operations on int with bits > 64", .{});1595 return self.fail("TODO binary operations on int with bits > 64", .{});
1592 }1596 }
...@@ -1606,7 +1610,7 @@ fn binOp(...@@ -1606,7 +1610,7 @@ fn binOp(
1606 };1610 };
16071611
1608 // Generate an add/sub/mul1612 // Generate an add/sub/mul
1609 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1613 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
16101614
1611 // Truncate if necessary1615 // Truncate if necessary
1612 switch (lhs_ty.zigTypeTag()) {1616 switch (lhs_ty.zigTypeTag()) {
...@@ -1642,7 +1646,7 @@ fn binOp(...@@ -1642,7 +1646,7 @@ fn binOp(
1642 else => unreachable,1646 else => unreachable,
1643 };1647 };
16441648
1645 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1649 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1646 } else {1650 } else {
1647 return self.fail("TODO binary operations on int with bits > 64", .{});1651 return self.fail("TODO binary operations on int with bits > 64", .{});
1648 }1652 }
...@@ -1678,9 +1682,9 @@ fn binOp(...@@ -1678,9 +1682,9 @@ fn binOp(
1678 };1682 };
16791683
1680 if (rhs_immediate_ok) {1684 if (rhs_immediate_ok) {
1681 return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false);1685 return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata);
1682 } else {1686 } else {
1683 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1687 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1684 }1688 }
1685 } else {1689 } else {
1686 return self.fail("TODO binary operations on int with bits > 64", .{});1690 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1699,7 +1703,7 @@ fn binOp(...@@ -1699,7 +1703,7 @@ fn binOp(
1699 };1703 };
17001704
1701 // Generate a shl_exact/shr_exact1705 // Generate a shl_exact/shr_exact
1702 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1706 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
17031707
1704 // Truncate if necessary1708 // Truncate if necessary
1705 switch (tag) {1709 switch (tag) {
...@@ -1735,7 +1739,7 @@ fn binOp(...@@ -1735,7 +1739,7 @@ fn binOp(
1735 else => unreachable,1739 else => unreachable,
1736 };1740 };
17371741
1738 return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1742 return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata);
1739 },1743 },
1740 else => unreachable,1744 else => unreachable,
1741 }1745 }
...@@ -1759,12 +1763,12 @@ fn binOp(...@@ -1759,12 +1763,12 @@ fn binOp(
1759 else => unreachable,1763 else => unreachable,
1760 };1764 };
17611765
1762 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1766 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1763 } else {1767 } else {
1764 // convert the offset into a byte offset by1768 // convert the offset into a byte offset by
1765 // multiplying it with elem_size1769 // multiplying it with elem_size
1766 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);1770 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
1767 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);1771 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
1768 return addr;1772 return addr;
1769 }1773 }
1770 },1774 },
...@@ -1775,8 +1779,7 @@ fn binOp(...@@ -1775,8 +1779,7 @@ fn binOp(
1775 }1779 }
1776}1780}
17771781
1778fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1782fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1779 const tag = self.air.instructions.items(.tag)[inst];
1780 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1783 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1781 const lhs = try self.resolveInst(bin_op.lhs);1784 const lhs = try self.resolveInst(bin_op.lhs);
1782 const rhs = try self.resolveInst(bin_op.rhs);1785 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -1786,7 +1789,30 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1786,7 +1789,30 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1786 const result: MCValue = if (self.liveness.isUnused(inst))1789 const result: MCValue = if (self.liveness.isUnused(inst))
1787 .dead1790 .dead
1788 else1791 else
1789 try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1792 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1793 .inst = inst,
1794 .lhs = bin_op.lhs,
1795 .rhs = bin_op.rhs,
1796 });
1797 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1798}
1799
1800fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1801 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1802 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1803 const lhs = try self.resolveInst(bin_op.lhs);
1804 const rhs = try self.resolveInst(bin_op.rhs);
1805 const lhs_ty = self.air.typeOf(bin_op.lhs);
1806 const rhs_ty = self.air.typeOf(bin_op.rhs);
1807
1808 const result: MCValue = if (self.liveness.isUnused(inst))
1809 .dead
1810 else
1811 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1812 .inst = inst,
1813 .lhs = bin_op.lhs,
1814 .rhs = bin_op.rhs,
1815 });
1790 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1816 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1791}1817}
17921818
...@@ -1841,7 +1867,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1841,7 +1867,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1841 .sub_with_overflow => .sub,1867 .sub_with_overflow => .sub,
1842 else => unreachable,1868 else => unreachable,
1843 };1869 };
1844 const dest = try self.binOp(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1870 const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1845 const dest_reg = dest.register;1871 const dest_reg = dest.register;
1846 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1872 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1847 defer self.register_manager.unlockReg(dest_reg_lock);1873 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1855,7 +1881,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1855,7 +1881,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1855 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1881 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
18561882
1857 // cmp dest, truncated1883 // cmp dest, truncated
1858 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1884 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
18591885
1860 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1886 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1861 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1887 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1894,12 +1920,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1894,12 +1920,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18941920
1895 const dest = blk: {1921 const dest = blk: {
1896 if (rhs_immediate_ok) {1922 if (rhs_immediate_ok) {
1897 break :blk try self.binOpImmediate(mir_tag_immediate, null, lhs, rhs, lhs_ty, false);1923 break :blk try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, null);
1898 } else if (lhs_immediate_ok) {1924 } else if (lhs_immediate_ok) {
1899 // swap lhs and rhs1925 // swap lhs and rhs
1900 break :blk try self.binOpImmediate(mir_tag_immediate, null, rhs, lhs, rhs_ty, true);1926 break :blk try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, null);
1901 } else {1927 } else {
1902 break :blk try self.binOpRegister(mir_tag_register, null, lhs, rhs, lhs_ty, rhs_ty);1928 break :blk try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, null);
1903 }1929 }
1904 };1930 };
19051931
...@@ -1952,7 +1978,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1952,7 +1978,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1952 .unsigned => .umull,1978 .unsigned => .umull,
1953 };1979 };
19541980
1955 const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1981 const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1956 const dest_reg = dest.register;1982 const dest_reg = dest.register;
1957 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1983 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1958 defer self.register_manager.unlockReg(dest_reg_lock);1984 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -2136,11 +2162,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2136,11 +2162,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21362162
2137 _ = try self.binOp(2163 _ = try self.binOp(
2138 .cmp_eq,2164 .cmp_eq,
2139 null,
2140 .{ .register = dest_high_reg },2165 .{ .register = dest_high_reg },
2141 .{ .immediate = 0 },2166 .{ .immediate = 0 },
2142 Type.usize,2167 Type.usize,
2143 Type.usize,2168 Type.usize,
2169 null,
2144 );2170 );
21452171
2146 if (int_info.bits < 64) {2172 if (int_info.bits < 64) {
...@@ -2156,11 +2182,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2156,11 +2182,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
21562182
2157 _ = try self.binOp(2183 _ = try self.binOp(
2158 .cmp_eq,2184 .cmp_eq,
2159 null,
2160 .{ .register = dest_high_reg },2185 .{ .register = dest_high_reg },
2161 .{ .immediate = 0 },2186 .{ .immediate = 0 },
2162 Type.usize,2187 Type.usize,
2163 Type.usize,2188 Type.usize,
2189 null,
2164 );2190 );
2165 }2191 }
2166 },2192 },
...@@ -2218,16 +2244,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2218,16 +2244,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2218 self.compare_flags_inst = null;2244 self.compare_flags_inst = null;
22192245
2220 // lsl dest, lhs, rhs2246 // lsl dest, lhs, rhs
2221 const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty);2247 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
2222 const dest_reg = dest.register;2248 const dest_reg = dest.register;
2223 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);2249 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
2224 defer self.register_manager.unlockReg(dest_reg_lock);2250 defer self.register_manager.unlockReg(dest_reg_lock);
22252251
2226 // asr/lsr reconstructed, dest, rhs2252 // asr/lsr reconstructed, dest, rhs
2227 const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty);2253 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
22282254
2229 // cmp lhs, reconstructed2255 // cmp lhs, reconstructed
2230 _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty);2256 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
22312257
2232 try self.genSetStack(lhs_ty, stack_offset, dest);2258 try self.genSetStack(lhs_ty, stack_offset, dest);
2233 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{2259 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{
...@@ -2489,7 +2515,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2489,7 +2515,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2489 switch (elem_size) {2515 switch (elem_size) {
2490 else => {2516 else => {
2491 const dest = try self.allocRegOrMem(inst, true);2517 const dest = try self.allocRegOrMem(inst, true);
2492 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);2518 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2493 try self.load(dest, addr, slice_ptr_field_type);2519 try self.load(dest, addr, slice_ptr_field_type);
24942520
2495 break :result dest;2521 break :result dest;
...@@ -2933,11 +2959,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2933,11 +2959,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
29332959
2934 const dest = try self.binOp(2960 const dest = try self.binOp(
2935 .add,2961 .add,
2936 null,
2937 .{ .register = addr_reg },2962 .{ .register = addr_reg },
2938 .{ .register = offset_reg },2963 .{ .register = offset_reg },
2939 Type.usize,2964 Type.usize,
2940 Type.usize,2965 Type.usize,
2966 null,
2941 );2967 );
29422968
2943 break :result dest;2969 break :result dest;
...@@ -3302,7 +3328,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3302,7 +3328,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
33023328
3303 const int_info = int_ty.intInfo(self.target.*);3329 const int_info = int_ty.intInfo(self.target.*);
3304 if (int_info.bits <= 64) {3330 if (int_info.bits <= 64) {
3305 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);3331 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
3332 .inst = inst,
3333 .lhs = bin_op.lhs,
3334 .rhs = bin_op.rhs,
3335 });
33063336
3307 try self.spillCompareFlagsIfOccupied();3337 try self.spillCompareFlagsIfOccupied();
3308 self.compare_flags_inst = inst;3338 self.compare_flags_inst = inst;
src/arch/arm/CodeGen.zig+113-79
...@@ -552,21 +552,34 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -552,21 +552,34 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
552552
553 switch (air_tags[inst]) {553 switch (air_tags[inst]) {
554 // zig fmt: off554 // zig fmt: off
555 .add, .ptr_add => try self.airBinOp(inst),555 .add, => try self.airBinOp(inst, .add),
556 .addwrap => try self.airBinOp(inst),556 .addwrap => try self.airBinOp(inst, .addwrap),
557 .sub, => try self.airBinOp(inst, .sub),
558 .subwrap => try self.airBinOp(inst, .subwrap),
559 .mul => try self.airBinOp(inst, .mul),
560 .mulwrap => try self.airBinOp(inst, .mulwrap),
561 .shl => try self.airBinOp(inst, .shl),
562 .shl_exact => try self.airBinOp(inst, .shl_exact),
563 .bool_and => try self.airBinOp(inst, .bool_and),
564 .bool_or => try self.airBinOp(inst, .bool_or),
565 .bit_and => try self.airBinOp(inst, .bit_and),
566 .bit_or => try self.airBinOp(inst, .bit_or),
567 .xor => try self.airBinOp(inst, .xor),
568 .shr => try self.airBinOp(inst, .shr),
569 .shr_exact => try self.airBinOp(inst, .shr_exact),
570
571 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
572 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
573
574 .min => try self.airMinMax(inst),
575 .max => try self.airMinMax(inst),
576
557 .add_sat => try self.airAddSat(inst),577 .add_sat => try self.airAddSat(inst),
558 .sub, .ptr_sub => try self.airBinOp(inst),
559 .subwrap => try self.airBinOp(inst),
560 .sub_sat => try self.airSubSat(inst),578 .sub_sat => try self.airSubSat(inst),
561 .mul => try self.airBinOp(inst),
562 .mulwrap => try self.airBinOp(inst),
563 .mul_sat => try self.airMulSat(inst),579 .mul_sat => try self.airMulSat(inst),
564 .rem => try self.airRem(inst),580 .rem => try self.airRem(inst),
565 .mod => try self.airMod(inst),581 .mod => try self.airMod(inst),
566 .shl, .shl_exact => try self.airBinOp(inst),
567 .shl_sat => try self.airShlSat(inst),582 .shl_sat => try self.airShlSat(inst),
568 .min => try self.airMinMax(inst),
569 .max => try self.airMinMax(inst),
570 .slice => try self.airSlice(inst),583 .slice => try self.airSlice(inst),
571584
572 .sqrt,585 .sqrt,
...@@ -602,13 +615,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -602,13 +615,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
602 .cmp_vector => try self.airCmpVector(inst),615 .cmp_vector => try self.airCmpVector(inst),
603 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),616 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
604617
605 .bool_and => try self.airBinOp(inst),
606 .bool_or => try self.airBinOp(inst),
607 .bit_and => try self.airBinOp(inst),
608 .bit_or => try self.airBinOp(inst),
609 .xor => try self.airBinOp(inst),
610 .shr, .shr_exact => try self.airBinOp(inst),
611
612 .alloc => try self.airAlloc(inst),618 .alloc => try self.airAlloc(inst),
613 .ret_ptr => try self.airRetPtr(inst),619 .ret_ptr => try self.airRetPtr(inst),
614 .arg => try self.airArg(inst),620 .arg => try self.airArg(inst),
...@@ -1260,7 +1266,7 @@ fn minMax(...@@ -1260,7 +1266,7 @@ fn minMax(
1260 // register.1266 // register.
1261 assert(lhs_reg != rhs_reg); // see note above1267 assert(lhs_reg != rhs_reg); // see note above
12621268
1263 _ = try self.binOpRegister(.cmp, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty);1269 _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null);
12641270
1265 const cond_choose_lhs: Condition = switch (tag) {1271 const cond_choose_lhs: Condition = switch (tag) {
1266 .max => switch (int_info.signedness) {1272 .max => switch (int_info.signedness) {
...@@ -1340,15 +1346,40 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1340,15 +1346,40 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1340 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1346 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1341}1347}
13421348
1343fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1349fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1344 const tag = self.air.instructions.items(.tag)[inst];
1345 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1350 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1346 const lhs = try self.resolveInst(bin_op.lhs);1351 const lhs = try self.resolveInst(bin_op.lhs);
1347 const rhs = try self.resolveInst(bin_op.rhs);1352 const rhs = try self.resolveInst(bin_op.rhs);
1348 const lhs_ty = self.air.typeOf(bin_op.lhs);1353 const lhs_ty = self.air.typeOf(bin_op.lhs);
1349 const rhs_ty = self.air.typeOf(bin_op.rhs);1354 const rhs_ty = self.air.typeOf(bin_op.rhs);
13501355
1351 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1356 const result: MCValue = if (self.liveness.isUnused(inst))
1357 .dead
1358 else
1359 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1360 .lhs = bin_op.lhs,
1361 .rhs = bin_op.rhs,
1362 .inst = inst,
1363 });
1364 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1365}
1366
1367fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1368 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1369 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1370 const lhs = try self.resolveInst(bin_op.lhs);
1371 const rhs = try self.resolveInst(bin_op.rhs);
1372 const lhs_ty = self.air.typeOf(bin_op.lhs);
1373 const rhs_ty = self.air.typeOf(bin_op.rhs);
1374
1375 const result: MCValue = if (self.liveness.isUnused(inst))
1376 .dead
1377 else
1378 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
1379 .lhs = bin_op.lhs,
1380 .rhs = bin_op.rhs,
1381 .inst = inst,
1382 });
1352 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1383 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1353}1384}
13541385
...@@ -1402,7 +1433,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1402,7 +1433,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1402 .sub_with_overflow => .sub,1433 .sub_with_overflow => .sub,
1403 else => unreachable,1434 else => unreachable,
1404 };1435 };
1405 const dest = try self.binOp(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1436 const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1406 const dest_reg = dest.register;1437 const dest_reg = dest.register;
1407 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1438 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1408 defer self.register_manager.unlockReg(dest_reg_lock);1439 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1415,7 +1446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1415,7 +1446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1415 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1446 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
14161447
1417 // cmp dest, truncated1448 // cmp dest, truncated
1418 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1449 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
14191450
1420 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1451 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1421 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1452 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1448,12 +1479,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1448,12 +1479,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
14481479
1449 const dest = blk: {1480 const dest = blk: {
1450 if (rhs_immediate_ok) {1481 if (rhs_immediate_ok) {
1451 break :blk try self.binOpImmediate(mir_tag, null, lhs, rhs, lhs_ty, false);1482 break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null);
1452 } else if (lhs_immediate_ok) {1483 } else if (lhs_immediate_ok) {
1453 // swap lhs and rhs1484 // swap lhs and rhs
1454 break :blk try self.binOpImmediate(mir_tag, null, rhs, lhs, rhs_ty, true);1485 break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null);
1455 } else {1486 } else {
1456 break :blk try self.binOpRegister(mir_tag, null, lhs, rhs, lhs_ty, rhs_ty);1487 break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1457 }1488 }
1458 };1489 };
14591490
...@@ -1507,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1507,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1507 .unsigned => .mul,1538 .unsigned => .mul,
1508 };1539 };
15091540
1510 const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty);1541 const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null);
1511 const dest_reg = dest.register;1542 const dest_reg = dest.register;
1512 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1543 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1513 defer self.register_manager.unlockReg(dest_reg_lock);1544 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1520,7 +1551,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1520,7 +1551,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1520 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);1551 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
15211552
1522 // cmp dest, truncated1553 // cmp dest, truncated
1523 _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize);1554 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);
15241555
1525 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1556 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1526 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1557 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -1594,7 +1625,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1594,7 +1625,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1594 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });1625 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
15951626
1596 // cmp truncated, rdlo1627 // cmp truncated, rdlo
1597 _ = try self.binOp(.cmp_eq, null, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize);1628 _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null);
15981629
1599 // mov rdlo, #01630 // mov rdlo, #0
1600 _ = try self.addInst(.{1631 _ = try self.addInst(.{
...@@ -1618,7 +1649,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1618,7 +1649,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1618 });1649 });
16191650
1620 // cmp rdhi, #01651 // cmp rdhi, #0
1621 _ = try self.binOp(.cmp_eq, null, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize);1652 _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null);
16221653
1623 // movne rdlo, #11654 // movne rdlo, #1
1624 _ = try self.addInst(.{1655 _ = try self.addInst(.{
...@@ -1677,16 +1708,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1677,16 +1708,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1677 self.compare_flags_inst = null;1708 self.compare_flags_inst = null;
16781709
1679 // lsl dest, lhs, rhs1710 // lsl dest, lhs, rhs
1680 const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty);1711 const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null);
1681 const dest_reg = dest.register;1712 const dest_reg = dest.register;
1682 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1713 const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1683 defer self.register_manager.unlockReg(dest_lock);1714 defer self.register_manager.unlockReg(dest_lock);
16841715
1685 // asr/lsr reconstructed, dest, rhs1716 // asr/lsr reconstructed, dest, rhs
1686 const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty);1717 const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null);
16871718
1688 // cmp lhs, reconstructed1719 // cmp lhs, reconstructed
1689 _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty);1720 _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null);
16901721
1691 try self.genSetStack(lhs_ty, stack_offset, dest);1722 try self.genSetStack(lhs_ty, stack_offset, dest);
1692 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });1723 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq });
...@@ -2031,7 +2062,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2031,7 +2062,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2031 },2062 },
2032 else => {2063 else => {
2033 const dest = try self.allocRegOrMem(inst, true);2064 const dest = try self.allocRegOrMem(inst, true);
2034 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);2065 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2035 try self.load(dest, addr, slice_ptr_field_type);2066 try self.load(dest, addr, slice_ptr_field_type);
20362067
2037 break :result dest;2068 break :result dest;
...@@ -2051,7 +2082,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2051,7 +2082,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
20512082
2052 const slice_ty = self.air.typeOf(extra.lhs);2083 const slice_ty = self.air.typeOf(extra.lhs);
20532084
2054 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize);2085 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);
2055 break :result addr;2086 break :result addr;
2056 };2087 };
2057 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2088 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2079,7 +2110,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2079,7 +2110,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
20792110
2080 const ptr_ty = self.air.typeOf(extra.lhs);2111 const ptr_ty = self.air.typeOf(extra.lhs);
20812112
2082 const addr = try self.binOp(.ptr_add, null, ptr_mcv, index_mcv, ptr_ty, Type.usize);2113 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);
2083 break :result addr;2114 break :result addr;
2084 };2115 };
2085 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2116 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2411,11 +2442,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2411,11 +2442,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
24112442
2412 const dest = try self.binOp(2443 const dest = try self.binOp(
2413 .add,2444 .add,
2414 null,
2415 .{ .register = addr_reg },2445 .{ .register = addr_reg },
2416 .{ .register = offset_reg },2446 .{ .register = offset_reg },
2417 Type.usize,2447 Type.usize,
2418 Type.usize,2448 Type.usize,
2449 null,
2419 );2450 );
24202451
2421 break :result dest;2452 break :result dest;
...@@ -2514,11 +2545,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2514,11 +2545,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2514fn binOpRegister(2545fn binOpRegister(
2515 self: *Self,2546 self: *Self,
2516 mir_tag: Mir.Inst.Tag,2547 mir_tag: Mir.Inst.Tag,
2517 maybe_inst: ?Air.Inst.Index,
2518 lhs: MCValue,2548 lhs: MCValue,
2519 rhs: MCValue,2549 rhs: MCValue,
2520 lhs_ty: Type,2550 lhs_ty: Type,
2521 rhs_ty: Type,2551 rhs_ty: Type,
2552 metadata: ?BinOpMetadata,
2522) !MCValue {2553) !MCValue {
2523 const lhs_is_register = lhs == .register;2554 const lhs_is_register = lhs == .register;
2524 const rhs_is_register = rhs == .register;2555 const rhs_is_register = rhs == .register;
...@@ -2532,9 +2563,8 @@ fn binOpRegister(...@@ -2532,9 +2563,8 @@ fn binOpRegister(
2532 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];2563 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
25332564
2534 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2565 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2535 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2566 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2536 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2567 break :inst Air.refToIndex(md.lhs).?;
2537 break :inst Air.refToIndex(bin_op.lhs).?;
2538 } else null;2568 } else null;
25392569
2540 const reg = try self.register_manager.allocReg(track_inst);2570 const reg = try self.register_manager.allocReg(track_inst);
...@@ -2547,9 +2577,8 @@ fn binOpRegister(...@@ -2547,9 +2577,8 @@ fn binOpRegister(
2547 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);2577 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
25482578
2549 const rhs_reg = if (rhs_is_register) rhs.register else blk: {2579 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2550 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2580 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2551 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2581 break :inst Air.refToIndex(md.rhs).?;
2552 break :inst Air.refToIndex(bin_op.rhs).?;
2553 } else null;2582 } else null;
25542583
2555 const reg = try self.register_manager.allocReg(track_inst);2584 const reg = try self.register_manager.allocReg(track_inst);
...@@ -2563,15 +2592,13 @@ fn binOpRegister(...@@ -2563,15 +2592,13 @@ fn binOpRegister(
25632592
2564 const dest_reg = switch (mir_tag) {2593 const dest_reg = switch (mir_tag) {
2565 .cmp => .r0, // cmp has no destination regardless2594 .cmp => .r0, // cmp has no destination regardless
2566 else => if (maybe_inst) |inst| blk: {2595 else => if (metadata) |md| blk: {
2567 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2596 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
2568
2569 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
2570 break :blk lhs_reg;2597 break :blk lhs_reg;
2571 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {2598 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
2572 break :blk rhs_reg;2599 break :blk rhs_reg;
2573 } else {2600 } else {
2574 break :blk try self.register_manager.allocReg(inst);2601 break :blk try self.register_manager.allocReg(md.inst);
2575 }2602 }
2576 } else try self.register_manager.allocReg(null),2603 } else try self.register_manager.allocReg(null),
2577 };2604 };
...@@ -2634,11 +2661,11 @@ fn binOpRegister(...@@ -2634,11 +2661,11 @@ fn binOpRegister(
2634fn binOpImmediate(2661fn binOpImmediate(
2635 self: *Self,2662 self: *Self,
2636 mir_tag: Mir.Inst.Tag,2663 mir_tag: Mir.Inst.Tag,
2637 maybe_inst: ?Air.Inst.Index,
2638 lhs: MCValue,2664 lhs: MCValue,
2639 rhs: MCValue,2665 rhs: MCValue,
2640 lhs_ty: Type,2666 lhs_ty: Type,
2641 lhs_and_rhs_swapped: bool,2667 lhs_and_rhs_swapped: bool,
2668 metadata: ?BinOpMetadata,
2642) !MCValue {2669) !MCValue {
2643 const lhs_is_register = lhs == .register;2670 const lhs_is_register = lhs == .register;
26442671
...@@ -2651,10 +2678,9 @@ fn binOpImmediate(...@@ -2651,10 +2678,9 @@ fn binOpImmediate(
2651 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];2678 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
26522679
2653 const lhs_reg = if (lhs_is_register) lhs.register else blk: {2680 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
2654 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {2681 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2655 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2656 break :inst Air.refToIndex(2682 break :inst Air.refToIndex(
2657 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,2683 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2658 ).?;2684 ).?;
2659 } else null;2685 } else null;
26602686
...@@ -2669,18 +2695,16 @@ fn binOpImmediate(...@@ -2669,18 +2695,16 @@ fn binOpImmediate(
26692695
2670 const dest_reg = switch (mir_tag) {2696 const dest_reg = switch (mir_tag) {
2671 .cmp => .r0, // cmp has no destination reg2697 .cmp => .r0, // cmp has no destination reg
2672 else => if (maybe_inst) |inst| blk: {2698 else => if (metadata) |md| blk: {
2673 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2674
2675 if (lhs_is_register and self.reuseOperand(2699 if (lhs_is_register and self.reuseOperand(
2676 inst,2700 md.inst,
2677 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,2701 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
2678 if (lhs_and_rhs_swapped) 1 else 0,2702 if (lhs_and_rhs_swapped) 1 else 0,
2679 lhs,2703 lhs,
2680 )) {2704 )) {
2681 break :blk lhs_reg;2705 break :blk lhs_reg;
2682 } else {2706 } else {
2683 break :blk try self.register_manager.allocReg(inst);2707 break :blk try self.register_manager.allocReg(md.inst);
2684 }2708 }
2685 } else try self.register_manager.allocReg(null),2709 } else try self.register_manager.allocReg(null),
2686 };2710 };
...@@ -2720,6 +2744,12 @@ fn binOpImmediate(...@@ -2720,6 +2744,12 @@ fn binOpImmediate(
2720 return MCValue{ .register = dest_reg };2744 return MCValue{ .register = dest_reg };
2721}2745}
27222746
2747const BinOpMetadata = struct {
2748 inst: Air.Inst.Index,
2749 lhs: Air.Inst.Ref,
2750 rhs: Air.Inst.Ref,
2751};
2752
2723/// For all your binary operation needs, this function will generate2753/// For all your binary operation needs, this function will generate
2724/// the corresponding Mir instruction(s). Returns the location of the2754/// the corresponding Mir instruction(s). Returns the location of the
2725/// result.2755/// result.
...@@ -2735,11 +2765,11 @@ fn binOpImmediate(...@@ -2735,11 +2765,11 @@ fn binOpImmediate(
2735fn binOp(2765fn binOp(
2736 self: *Self,2766 self: *Self,
2737 tag: Air.Inst.Tag,2767 tag: Air.Inst.Tag,
2738 maybe_inst: ?Air.Inst.Index,
2739 lhs: MCValue,2768 lhs: MCValue,
2740 rhs: MCValue,2769 rhs: MCValue,
2741 lhs_ty: Type,2770 lhs_ty: Type,
2742 rhs_ty: Type,2771 rhs_ty: Type,
2772 metadata: ?BinOpMetadata,
2743) InnerError!MCValue {2773) InnerError!MCValue {
2744 switch (tag) {2774 switch (tag) {
2745 .add,2775 .add,
...@@ -2780,12 +2810,12 @@ fn binOp(...@@ -2780,12 +2810,12 @@ fn binOp(
2780 };2810 };
27812811
2782 if (rhs_immediate_ok) {2812 if (rhs_immediate_ok) {
2783 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2813 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2784 } else if (lhs_immediate_ok) {2814 } else if (lhs_immediate_ok) {
2785 // swap lhs and rhs2815 // swap lhs and rhs
2786 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);2816 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2787 } else {2817 } else {
2788 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2818 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2789 }2819 }
2790 } else {2820 } else {
2791 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2821 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2806,7 +2836,7 @@ fn binOp(...@@ -2806,7 +2836,7 @@ fn binOp(
2806 // TODO add optimisations for multiplication2836 // TODO add optimisations for multiplication
2807 // with immediates, for example a * 2 can be2837 // with immediates, for example a * 2 can be
2808 // lowered to a << 12838 // lowered to a << 1
2809 return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2839 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
2810 } else {2840 } else {
2811 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2841 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2812 }2842 }
...@@ -2826,7 +2856,7 @@ fn binOp(...@@ -2826,7 +2856,7 @@ fn binOp(
2826 };2856 };
28272857
2828 // Generate an add/sub/mul2858 // Generate an add/sub/mul
2829 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2859 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
28302860
2831 // Truncate if necessary2861 // Truncate if necessary
2832 switch (lhs_ty.zigTypeTag()) {2862 switch (lhs_ty.zigTypeTag()) {
...@@ -2869,12 +2899,12 @@ fn binOp(...@@ -2869,12 +2899,12 @@ fn binOp(
2869 };2899 };
28702900
2871 if (rhs_immediate_ok) {2901 if (rhs_immediate_ok) {
2872 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2902 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2873 } else if (lhs_immediate_ok) {2903 } else if (lhs_immediate_ok) {
2874 // swap lhs and rhs2904 // swap lhs and rhs
2875 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);2905 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2876 } else {2906 } else {
2877 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2907 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2878 }2908 }
2879 } else {2909 } else {
2880 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2910 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2903,9 +2933,9 @@ fn binOp(...@@ -2903,9 +2933,9 @@ fn binOp(
2903 };2933 };
29042934
2905 if (rhs_immediate_ok) {2935 if (rhs_immediate_ok) {
2906 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2936 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2907 } else {2937 } else {
2908 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2938 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2909 }2939 }
2910 } else {2940 } else {
2911 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});2941 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
...@@ -2924,7 +2954,7 @@ fn binOp(...@@ -2924,7 +2954,7 @@ fn binOp(
2924 };2954 };
29252955
2926 // Generate a shl_exact/shr_exact2956 // Generate a shl_exact/shr_exact
2927 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);2957 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
29282958
2929 // Truncate if necessary2959 // Truncate if necessary
2930 switch (tag) {2960 switch (tag) {
...@@ -2964,12 +2994,12 @@ fn binOp(...@@ -2964,12 +2994,12 @@ fn binOp(
2964 };2994 };
29652995
2966 if (rhs_immediate_ok) {2996 if (rhs_immediate_ok) {
2967 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);2997 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2968 } else if (lhs_immediate_ok) {2998 } else if (lhs_immediate_ok) {
2969 // swap lhs and rhs2999 // swap lhs and rhs
2970 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);3000 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2971 } else {3001 } else {
2972 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);3002 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2973 }3003 }
2974 },3004 },
2975 else => unreachable,3005 else => unreachable,
...@@ -2994,12 +3024,12 @@ fn binOp(...@@ -2994,12 +3024,12 @@ fn binOp(
2994 else => unreachable,3024 else => unreachable,
2995 };3025 };
29963026
2997 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);3027 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2998 } else {3028 } else {
2999 // convert the offset into a byte offset by3029 // convert the offset into a byte offset by
3000 // multiplying it with elem_size3030 // multiplying it with elem_size
3001 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);3031 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
3002 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);3032 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
3003 return addr;3033 return addr;
3004 }3034 }
3005 },3035 },
...@@ -3575,7 +3605,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3575,7 +3605,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3575 try self.spillCompareFlagsIfOccupied();3605 try self.spillCompareFlagsIfOccupied();
3576 self.compare_flags_inst = inst;3606 self.compare_flags_inst = inst;
35773607
3578 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);3608 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
3609 .lhs = bin_op.lhs,
3610 .rhs = bin_op.rhs,
3611 .inst = inst,
3612 });
35793613
3580 break :result switch (int_info.signedness) {3614 break :result switch (int_info.signedness) {
3581 .signed => MCValue{ .compare_flags_signed = op },3615 .signed => MCValue{ .compare_flags_signed = op },
...@@ -3865,7 +3899,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3865,7 +3899,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3865 }3899 }
38663900
3867 const error_mcv = try self.errUnionErr(operand, ty);3901 const error_mcv = try self.errUnionErr(operand, ty);
3868 _ = try self.binOp(.cmp_eq, null, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type);3902 _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
3869 return MCValue{ .compare_flags_unsigned = .gt };3903 return MCValue{ .compare_flags_unsigned = .gt };
3870}3904}
38713905
src/arch/riscv64/CodeGen.zig+19-4
...@@ -481,10 +481,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -481,10 +481,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
481481
482 switch (air_tags[inst]) {482 switch (air_tags[inst]) {
483 // zig fmt: off483 // zig fmt: off
484 .add, .ptr_add => try self.airBinOp(inst),484 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
485 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
486
487 .add => try self.airBinOp(inst, .add),
488 .sub => try self.airBinOp(inst, .sub),
489
485 .addwrap => try self.airAddWrap(inst),490 .addwrap => try self.airAddWrap(inst),
486 .add_sat => try self.airAddSat(inst),491 .add_sat => try self.airAddSat(inst),
487 .sub, .ptr_sub => try self.airBinOp(inst),
488 .subwrap => try self.airSubWrap(inst),492 .subwrap => try self.airSubWrap(inst),
489 .sub_sat => try self.airSubSat(inst),493 .sub_sat => try self.airSubSat(inst),
490 .mul => try self.airMul(inst),494 .mul => try self.airMul(inst),
...@@ -1091,8 +1095,7 @@ fn binOp(...@@ -1091,8 +1095,7 @@ fn binOp(
1091 }1095 }
1092}1096}
10931097
1094fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1098fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1095 const tag = self.air.instructions.items(.tag)[inst];
1096 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1099 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1097 const lhs = try self.resolveInst(bin_op.lhs);1100 const lhs = try self.resolveInst(bin_op.lhs);
1098 const rhs = try self.resolveInst(bin_op.rhs);1101 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -1103,6 +1106,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1103,6 +1106,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1103 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1106 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1104}1107}
11051108
1109fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1110 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1111 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1112 const lhs = try self.resolveInst(bin_op.lhs);
1113 const rhs = try self.resolveInst(bin_op.rhs);
1114 const lhs_ty = self.air.typeOf(bin_op.lhs);
1115 const rhs_ty = self.air.typeOf(bin_op.rhs);
1116
1117 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1118 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1119}
1120
1106fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {1121fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void {
1107 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1122 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1108 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});1123 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch});
src/arch/sparc64/CodeGen.zig+71-46
...@@ -483,10 +483,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -483,10 +483,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
483483
484 switch (air_tags[inst]) {484 switch (air_tags[inst]) {
485 // zig fmt: off485 // zig fmt: off
486 .add, .ptr_add => try self.airBinOp(inst),486 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
487 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
488
489 .add => try self.airBinOp(inst, .add),
487 .addwrap => @panic("TODO try self.airAddWrap(inst)"),490 .addwrap => @panic("TODO try self.airAddWrap(inst)"),
488 .add_sat => @panic("TODO try self.airAddSat(inst)"),491 .add_sat => @panic("TODO try self.airAddSat(inst)"),
489 .sub, .ptr_sub => @panic("TODO try self.airBinOp(inst)"),492 .sub => @panic("TODO try self.airBinOp(inst)"),
490 .subwrap => @panic("TODO try self.airSubWrap(inst)"),493 .subwrap => @panic("TODO try self.airSubWrap(inst)"),
491 .sub_sat => @panic("TODO try self.airSubSat(inst)"),494 .sub_sat => @panic("TODO try self.airSubSat(inst)"),
492 .mul => @panic("TODO try self.airMul(inst)"),495 .mul => @panic("TODO try self.airMul(inst)"),
...@@ -827,18 +830,38 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -827,18 +830,38 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
827 return self.finishAir(inst, mcv, .{ .none, .none, .none });830 return self.finishAir(inst, mcv, .{ .none, .none, .none });
828}831}
829832
830fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {833fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
831 const tag = self.air.instructions.items(.tag)[inst];
832 const bin_op = self.air.instructions.items(.data)[inst].bin_op;834 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
833 const lhs = try self.resolveInst(bin_op.lhs);835 const lhs = try self.resolveInst(bin_op.lhs);
834 const rhs = try self.resolveInst(bin_op.rhs);836 const rhs = try self.resolveInst(bin_op.rhs);
835 const lhs_ty = self.air.typeOf(bin_op.lhs);837 const lhs_ty = self.air.typeOf(bin_op.lhs);
836 const rhs_ty = self.air.typeOf(bin_op.rhs);838 const rhs_ty = self.air.typeOf(bin_op.rhs);
839 const result: MCValue = if (self.liveness.isUnused(inst))
840 .dead
841 else
842 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
843 .lhs = bin_op.lhs,
844 .rhs = bin_op.rhs,
845 .inst = inst,
846 });
847 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
848}
837849
850fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
851 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
852 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
853 const lhs = try self.resolveInst(bin_op.lhs);
854 const rhs = try self.resolveInst(bin_op.rhs);
855 const lhs_ty = self.air.typeOf(bin_op.lhs);
856 const rhs_ty = self.air.typeOf(bin_op.rhs);
838 const result: MCValue = if (self.liveness.isUnused(inst))857 const result: MCValue = if (self.liveness.isUnused(inst))
839 .dead858 .dead
840 else859 else
841 try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);860 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{
861 .lhs = bin_op.lhs,
862 .rhs = bin_op.rhs,
863 .inst = inst,
864 });
842 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });865 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
843}866}
844867
...@@ -1030,7 +1053,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1030,7 +1053,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
10301053
1031 var int_buffer: Type.Payload.Bits = undefined;1054 var int_buffer: Type.Payload.Bits = undefined;
1032 const int_ty = switch (lhs_ty.zigTypeTag()) {1055 const int_ty = switch (lhs_ty.zigTypeTag()) {
1033 .Vector => unreachable, // Should be handled by cmp_vector?1056 .Vector => unreachable, // Handled by cmp_vector.
1034 .Enum => lhs_ty.intTagType(&int_buffer),1057 .Enum => lhs_ty.intTagType(&int_buffer),
1035 .Int => lhs_ty,1058 .Int => lhs_ty,
1036 .Bool => Type.initTag(.u1),1059 .Bool => Type.initTag(.u1),
...@@ -1053,7 +1076,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1053,7 +1076,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
10531076
1054 const int_info = int_ty.intInfo(self.target.*);1077 const int_info = int_ty.intInfo(self.target.*);
1055 if (int_info.bits <= 64) {1078 if (int_info.bits <= 64) {
1056 _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty);1079 _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{
1080 .lhs = bin_op.lhs,
1081 .rhs = bin_op.rhs,
1082 .inst = inst,
1083 });
10571084
1058 try self.spillCompareFlagsIfOccupied();1085 try self.spillCompareFlagsIfOccupied();
1059 self.compare_flags_inst = inst;1086 self.compare_flags_inst = inst;
...@@ -1426,7 +1453,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1426,7 +1453,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1426 // TODO skip the ptr_add emission entirely and use native addressing modes1453 // TODO skip the ptr_add emission entirely and use native addressing modes
1427 // i.e sllx/mulx then R+R or scale immediate then R+I1454 // i.e sllx/mulx then R+R or scale immediate then R+I
1428 const dest = try self.allocRegOrMem(inst, true);1455 const dest = try self.allocRegOrMem(inst, true);
1429 const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ptr_field_type, Type.usize);1456 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
1430 try self.load(dest, addr, slice_ptr_field_type);1457 try self.load(dest, addr, slice_ptr_field_type);
14311458
1432 break :result dest;1459 break :result dest;
...@@ -1595,6 +1622,12 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1595,6 +1622,12 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1595 return MCValue{ .stack_offset = stack_offset };1622 return MCValue{ .stack_offset = stack_offset };
1596}1623}
15971624
1625const BinOpMetadata = struct {
1626 inst: Air.Inst.Index,
1627 lhs: Air.Inst.Ref,
1628 rhs: Air.Inst.Ref,
1629};
1630
1598/// For all your binary operation needs, this function will generate1631/// For all your binary operation needs, this function will generate
1599/// the corresponding Mir instruction(s). Returns the location of the1632/// the corresponding Mir instruction(s). Returns the location of the
1600/// result.1633/// result.
...@@ -1610,11 +1643,11 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -1610,11 +1643,11 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1610fn binOp(1643fn binOp(
1611 self: *Self,1644 self: *Self,
1612 tag: Air.Inst.Tag,1645 tag: Air.Inst.Tag,
1613 maybe_inst: ?Air.Inst.Index,
1614 lhs: MCValue,1646 lhs: MCValue,
1615 rhs: MCValue,1647 rhs: MCValue,
1616 lhs_ty: Type,1648 lhs_ty: Type,
1617 rhs_ty: Type,1649 rhs_ty: Type,
1650 metadata: ?BinOpMetadata,
1618) InnerError!MCValue {1651) InnerError!MCValue {
1619 const mod = self.bin_file.options.module.?;1652 const mod = self.bin_file.options.module.?;
1620 switch (tag) {1653 switch (tag) {
...@@ -1649,13 +1682,13 @@ fn binOp(...@@ -1649,13 +1682,13 @@ fn binOp(
1649 };1682 };
16501683
1651 if (rhs_immediate_ok) {1684 if (rhs_immediate_ok) {
1652 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);1685 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
1653 } else if (lhs_immediate_ok) {1686 } else if (lhs_immediate_ok) {
1654 // swap lhs and rhs1687 // swap lhs and rhs
1655 return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);1688 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
1656 } else {1689 } else {
1657 // TODO convert large immediates to register before adding1690 // TODO convert large immediates to register before adding
1658 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1691 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1659 }1692 }
1660 } else {1693 } else {
1661 return self.fail("TODO binary operations on int with bits > 64", .{});1694 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1683,10 +1716,10 @@ fn binOp(...@@ -1683,10 +1716,10 @@ fn binOp(
1683 // If it's a power of two immediate then we emit an shl instead1716 // If it's a power of two immediate then we emit an shl instead
1684 // TODO add similar checks for LHS1717 // TODO add similar checks for LHS
1685 if (new_rhs == .immediate and math.isPowerOfTwo(new_rhs.immediate)) {1718 if (new_rhs == .immediate and math.isPowerOfTwo(new_rhs.immediate)) {
1686 return try self.binOp(.shl, maybe_inst, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize);1719 return try self.binOp(.shl, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize, metadata);
1687 }1720 }
16881721
1689 return try self.binOpRegister(.mulx, maybe_inst, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty);1722 return try self.binOpRegister(.mulx, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty, metadata);
1690 } else {1723 } else {
1691 return self.fail("TODO binary operations on int with bits > 64", .{});1724 return self.fail("TODO binary operations on int with bits > 64", .{});
1692 }1725 }
...@@ -1711,13 +1744,13 @@ fn binOp(...@@ -1711,13 +1744,13 @@ fn binOp(
1711 else => unreachable,1744 else => unreachable,
1712 };1745 };
17131746
1714 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1747 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1715 } else {1748 } else {
1716 // convert the offset into a byte offset by1749 // convert the offset into a byte offset by
1717 // multiplying it with elem_size1750 // multiplying it with elem_size
17181751
1719 const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize);1752 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
1720 const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize);1753 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
1721 return addr;1754 return addr;
1722 }1755 }
1723 },1756 },
...@@ -1732,7 +1765,7 @@ fn binOp(...@@ -1732,7 +1765,7 @@ fn binOp(
1732 };1765 };
17331766
1734 // Generate a shl_exact/shr_exact1767 // Generate a shl_exact/shr_exact
1735 const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1768 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
17361769
1737 // Truncate if necessary1770 // Truncate if necessary
1738 switch (tag) {1771 switch (tag) {
...@@ -1768,9 +1801,9 @@ fn binOp(...@@ -1768,9 +1801,9 @@ fn binOp(
1768 };1801 };
17691802
1770 if (rhs_immediate_ok) {1803 if (rhs_immediate_ok) {
1771 return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);1804 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
1772 } else {1805 } else {
1773 return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);1806 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
1774 }1807 }
1775 } else {1808 } else {
1776 return self.fail("TODO binary operations on int with bits > 64", .{});1809 return self.fail("TODO binary operations on int with bits > 64", .{});
...@@ -1792,18 +1825,17 @@ fn binOp(...@@ -1792,18 +1825,17 @@ fn binOp(
1792/// op dest, lhs, #rhs_imm1825/// op dest, lhs, #rhs_imm
1793///1826///
1794/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to1827/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
1795/// rhs and vice versa. This parameter is only used when maybe_inst !=1828/// rhs and vice versa. This parameter is only used when metadata != null.
1796/// null.
1797///1829///
1798/// Asserts that generating an instruction of that form is possible.1830/// Asserts that generating an instruction of that form is possible.
1799fn binOpImmediate(1831fn binOpImmediate(
1800 self: *Self,1832 self: *Self,
1801 mir_tag: Mir.Inst.Tag,1833 mir_tag: Mir.Inst.Tag,
1802 maybe_inst: ?Air.Inst.Index,
1803 lhs: MCValue,1834 lhs: MCValue,
1804 rhs: MCValue,1835 rhs: MCValue,
1805 lhs_ty: Type,1836 lhs_ty: Type,
1806 lhs_and_rhs_swapped: bool,1837 lhs_and_rhs_swapped: bool,
1838 metadata: ?BinOpMetadata,
1807) !MCValue {1839) !MCValue {
1808 const lhs_is_register = lhs == .register;1840 const lhs_is_register = lhs == .register;
18091841
...@@ -1816,10 +1848,9 @@ fn binOpImmediate(...@@ -1816,10 +1848,9 @@ fn binOpImmediate(
1816 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1848 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
18171849
1818 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1850 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1819 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1851 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1820 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1821 break :inst Air.refToIndex(1852 break :inst Air.refToIndex(
1822 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1853 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1823 ).?;1854 ).?;
1824 } else null;1855 } else null;
18251856
...@@ -1833,18 +1864,16 @@ fn binOpImmediate(...@@ -1833,18 +1864,16 @@ fn binOpImmediate(
1833 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1864 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
18341865
1835 const dest_reg = switch (mir_tag) {1866 const dest_reg = switch (mir_tag) {
1836 else => if (maybe_inst) |inst| blk: {1867 else => if (metadata) |md| blk: {
1837 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1838
1839 if (lhs_is_register and self.reuseOperand(1868 if (lhs_is_register and self.reuseOperand(
1840 inst,1869 md.inst,
1841 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,1870 if (lhs_and_rhs_swapped) md.rhs else md.lhs,
1842 if (lhs_and_rhs_swapped) 1 else 0,1871 if (lhs_and_rhs_swapped) 1 else 0,
1843 lhs,1872 lhs,
1844 )) {1873 )) {
1845 break :blk lhs_reg;1874 break :blk lhs_reg;
1846 } else {1875 } else {
1847 break :blk try self.register_manager.allocReg(inst);1876 break :blk try self.register_manager.allocReg(md.inst);
1848 }1877 }
1849 } else blk: {1878 } else blk: {
1850 break :blk try self.register_manager.allocReg(null);1879 break :blk try self.register_manager.allocReg(null);
...@@ -1896,11 +1925,11 @@ fn binOpImmediate(...@@ -1896,11 +1925,11 @@ fn binOpImmediate(
1896fn binOpRegister(1925fn binOpRegister(
1897 self: *Self,1926 self: *Self,
1898 mir_tag: Mir.Inst.Tag,1927 mir_tag: Mir.Inst.Tag,
1899 maybe_inst: ?Air.Inst.Index,
1900 lhs: MCValue,1928 lhs: MCValue,
1901 rhs: MCValue,1929 rhs: MCValue,
1902 lhs_ty: Type,1930 lhs_ty: Type,
1903 rhs_ty: Type,1931 rhs_ty: Type,
1932 metadata: ?BinOpMetadata,
1904) !MCValue {1933) !MCValue {
1905 const lhs_is_register = lhs == .register;1934 const lhs_is_register = lhs == .register;
1906 const rhs_is_register = rhs == .register;1935 const rhs_is_register = rhs == .register;
...@@ -1920,9 +1949,8 @@ fn binOpRegister(...@@ -1920,9 +1949,8 @@ fn binOpRegister(
1920 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1949 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
19211950
1922 const lhs_reg = if (lhs_is_register) lhs.register else blk: {1951 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1923 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1952 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1924 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1953 break :inst Air.refToIndex(md.lhs).?;
1925 break :inst Air.refToIndex(bin_op.lhs).?;
1926 } else null;1954 } else null;
19271955
1928 const reg = try self.register_manager.allocReg(track_inst);1956 const reg = try self.register_manager.allocReg(track_inst);
...@@ -1934,9 +1962,8 @@ fn binOpRegister(...@@ -1934,9 +1962,8 @@ fn binOpRegister(
1934 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1962 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
19351963
1936 const rhs_reg = if (rhs_is_register) rhs.register else blk: {1964 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1937 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {1965 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1938 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1966 break :inst Air.refToIndex(md.rhs).?;
1939 break :inst Air.refToIndex(bin_op.rhs).?;
1940 } else null;1967 } else null;
19411968
1942 const reg = try self.register_manager.allocReg(track_inst);1969 const reg = try self.register_manager.allocReg(track_inst);
...@@ -1948,15 +1975,13 @@ fn binOpRegister(...@@ -1948,15 +1975,13 @@ fn binOpRegister(
1948 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);1975 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
19491976
1950 const dest_reg = switch (mir_tag) {1977 const dest_reg = switch (mir_tag) {
1951 else => if (maybe_inst) |inst| blk: {1978 else => if (metadata) |md| blk: {
1952 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1979 if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) {
1953
1954 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1955 break :blk lhs_reg;1980 break :blk lhs_reg;
1956 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {1981 } else if (rhs_is_register and self.reuseOperand(md.inst, md.rhs, 1, rhs)) {
1957 break :blk rhs_reg;1982 break :blk rhs_reg;
1958 } else {1983 } else {
1959 break :blk try self.register_manager.allocReg(inst);1984 break :blk try self.register_manager.allocReg(md.inst);
1960 }1985 }
1961 } else blk: {1986 } else blk: {
1962 break :blk try self.register_manager.allocReg(null);1987 break :blk try self.register_manager.allocReg(null);
...@@ -3069,11 +3094,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -3069,11 +3094,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
30693094
3070 const dest = try self.binOp(3095 const dest = try self.binOp(
3071 .add,3096 .add,
3072 null,
3073 .{ .register = addr_reg },3097 .{ .register = addr_reg },
3074 .{ .register = offset_reg },3098 .{ .register = offset_reg },
3075 Type.usize,3099 Type.usize,
3076 Type.usize,3100 Type.usize,
3101 null,
3077 );3102 );
30783103
3079 break :result dest;3104 break :result dest;
src/arch/wasm/CodeGen.zig+2-1
...@@ -3397,7 +3397,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3397,7 +3397,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33973397
3398fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {3398fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
3399 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3399 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3400 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3400 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3401 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3401 const ptr = try self.resolveInst(bin_op.lhs);3402 const ptr = try self.resolveInst(bin_op.lhs);
3402 const offset = try self.resolveInst(bin_op.rhs);3403 const offset = try self.resolveInst(bin_op.rhs);
3403 const ptr_ty = self.air.typeOf(bin_op.lhs);3404 const ptr_ty = self.air.typeOf(bin_op.lhs);
src/arch/x86_64/CodeGen.zig+45-37
...@@ -574,23 +574,33 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -574,23 +574,33 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
574574
575 switch (air_tags[inst]) {575 switch (air_tags[inst]) {
576 // zig fmt: off576 // zig fmt: off
577 .add => try self.airBinOp(inst),577 .add => try self.airBinOp(inst, .add),
578 .addwrap => try self.airBinOp(inst),578 .addwrap => try self.airBinOp(inst, .addwrap),
579 .add_sat => try self.airAddSat(inst),579 .sub => try self.airBinOp(inst, .sub),
580 .sub => try self.airBinOp(inst),580 .subwrap => try self.airBinOp(inst, .subwrap),
581 .subwrap => try self.airBinOp(inst),581 .bool_and => try self.airBinOp(inst, .bool_and),
582 .sub_sat => try self.airSubSat(inst),582 .bool_or => try self.airBinOp(inst, .bool_or),
583 .bit_and => try self.airBinOp(inst, .bit_and),
584 .bit_or => try self.airBinOp(inst, .bit_or),
585 .xor => try self.airBinOp(inst, .xor),
586
587 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
588 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
589
590 .shr, .shr_exact => try self.airShlShrBinOp(inst),
591 .shl, .shl_exact => try self.airShlShrBinOp(inst),
592
583 .mul => try self.airMulDivBinOp(inst),593 .mul => try self.airMulDivBinOp(inst),
584 .mulwrap => try self.airMulDivBinOp(inst),594 .mulwrap => try self.airMulDivBinOp(inst),
585 .mul_sat => try self.airMulSat(inst),
586 .rem => try self.airMulDivBinOp(inst),595 .rem => try self.airMulDivBinOp(inst),
587 .mod => try self.airMulDivBinOp(inst),596 .mod => try self.airMulDivBinOp(inst),
588 .shl, .shl_exact => try self.airShlShrBinOp(inst),597
598 .add_sat => try self.airAddSat(inst),
599 .sub_sat => try self.airSubSat(inst),
600 .mul_sat => try self.airMulSat(inst),
589 .shl_sat => try self.airShlSat(inst),601 .shl_sat => try self.airShlSat(inst),
590 .min => try self.airMin(inst),602 .min => try self.airMin(inst),
591 .max => try self.airMax(inst),603 .max => try self.airMax(inst),
592 .ptr_add => try self.airBinOp(inst),
593 .ptr_sub => try self.airBinOp(inst),
594 .slice => try self.airSlice(inst),604 .slice => try self.airSlice(inst),
595605
596 .sqrt,606 .sqrt,
...@@ -626,13 +636,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -626,13 +636,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
626 .cmp_vector => try self.airCmpVector(inst),636 .cmp_vector => try self.airCmpVector(inst),
627 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),637 .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
628638
629 .bool_and => try self.airBinOp(inst),
630 .bool_or => try self.airBinOp(inst),
631 .bit_and => try self.airBinOp(inst),
632 .bit_or => try self.airBinOp(inst),
633 .xor => try self.airBinOp(inst),
634 .shr, .shr_exact => try self.airShlShrBinOp(inst),
635
636 .alloc => try self.airAlloc(inst),639 .alloc => try self.airAlloc(inst),
637 .ret_ptr => try self.airRetPtr(inst),640 .ret_ptr => try self.airRetPtr(inst),
638 .arg => try self.airArg(inst),641 .arg => try self.airArg(inst),
...@@ -1231,21 +1234,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1231,21 +1234,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1231 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1234 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1232}1235}
12331236
1234fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {1237fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1235 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1238 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
12361239
1237 if (self.liveness.isUnused(inst)) {1240 if (self.liveness.isUnused(inst)) {
1238 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1241 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1239 }1242 }
12401243
1241 const tag = self.air.instructions.items(.tag)[inst];1244 const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1242 const lhs = try self.resolveInst(bin_op.lhs);1245 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1243 const rhs = try self.resolveInst(bin_op.rhs);1246}
1244 const lhs_ty = self.air.typeOf(bin_op.lhs);
1245 const rhs_ty = self.air.typeOf(bin_op.rhs);
12461247
1247 const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);1248fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1249 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1250 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1251
1252 if (self.liveness.isUnused(inst)) {
1253 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1254 }
12481255
1256 const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
1249 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1257 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1250}1258}
12511259
...@@ -1316,13 +1324,12 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1316,13 +1324,12 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1316 try self.spillRegisters(1, .{.rcx});1324 try self.spillRegisters(1, .{.rcx});
1317 }1325 }
13181326
1319 const lhs = try self.resolveInst(bin_op.lhs);
1320 const rhs = try self.resolveInst(bin_op.rhs);
1321
1322 const partial: MCValue = switch (tag) {1327 const partial: MCValue = switch (tag) {
1323 .add_with_overflow => try self.genBinOp(.add, null, lhs, rhs, ty, ty),1328 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
1324 .sub_with_overflow => try self.genBinOp(.sub, null, lhs, rhs, ty, ty),1329 .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),
1325 .shl_with_overflow => blk: {1330 .shl_with_overflow => blk: {
1331 const lhs = try self.resolveInst(bin_op.lhs);
1332 const rhs = try self.resolveInst(bin_op.rhs);
1326 const shift_ty = self.air.typeOf(bin_op.rhs);1333 const shift_ty = self.air.typeOf(bin_op.rhs);
1327 break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty);1334 break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty);
1328 },1335 },
...@@ -3310,13 +3317,15 @@ fn genMulDivBinOp(...@@ -3310,13 +3317,15 @@ fn genMulDivBinOp(
3310/// Result is always a register.3317/// Result is always a register.
3311fn genBinOp(3318fn genBinOp(
3312 self: *Self,3319 self: *Self,
3313 tag: Air.Inst.Tag,
3314 maybe_inst: ?Air.Inst.Index,3320 maybe_inst: ?Air.Inst.Index,
3315 lhs: MCValue,3321 tag: Air.Inst.Tag,
3316 rhs: MCValue,3322 lhs_air: Air.Inst.Ref,
3317 lhs_ty: Type,3323 rhs_air: Air.Inst.Ref,
3318 rhs_ty: Type,
3319) !MCValue {3324) !MCValue {
3325 const lhs = try self.resolveInst(lhs_air);
3326 const rhs = try self.resolveInst(rhs_air);
3327 const lhs_ty = self.air.typeOf(lhs_air);
3328 const rhs_ty = self.air.typeOf(rhs_air);
3320 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {3329 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
3321 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});3330 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
3322 }3331 }
...@@ -3352,11 +3361,10 @@ fn genBinOp(...@@ -3352,11 +3361,10 @@ fn genBinOp(
3352 var flipped: bool = false;3361 var flipped: bool = false;
3353 const dst_mcv: MCValue = blk: {3362 const dst_mcv: MCValue = blk: {
3354 if (maybe_inst) |inst| {3363 if (maybe_inst) |inst| {
3355 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3364 if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) {
3356 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
3357 break :blk lhs;3365 break :blk lhs;
3358 }3366 }
3359 if (is_commutative and self.reuseOperand(inst, bin_op.rhs, 1, rhs) and rhs.isRegister()) {3367 if (is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs) and rhs.isRegister()) {
3360 flipped = true;3368 flipped = true;
3361 break :blk rhs;3369 break :blk rhs;
3362 }3370 }
src/codegen/c.zig+16-20
...@@ -1711,21 +1711,18 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1711,21 +1711,18 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1711 .unreach => try airUnreach(f),1711 .unreach => try airUnreach(f),
1712 .fence => try airFence(f, inst),1712 .fence => try airFence(f, inst),
17131713
1714 // TODO use a different strategy for add that communicates to the optimizer1714 .ptr_add => try airPtrAddSub(f, inst, " + "),
1715 // that wrapping is UB.1715 .ptr_sub => try airPtrAddSub(f, inst, " - "),
1716 .add => try airBinOp (f, inst, " + "),1716
1717 .ptr_add => try airPtrAddSub (f, inst, " + "),1717 // TODO use a different strategy for add, sub, mul, div
1718 // TODO use a different strategy for sub that communicates to the optimizer1718 // that communicates to the optimizer that wrapping is UB.
1719 // that wrapping is UB.1719 .add => try airBinOp (f, inst, " + "),
1720 .sub => try airBinOp (f, inst, " - "),1720 .sub => try airBinOp (f, inst, " - "),
1721 .ptr_sub => try airPtrAddSub (f, inst, " - "),1721 .mul => try airBinOp (f, inst, " * "),
1722 // TODO use a different strategy for mul that communicates to the optimizer
1723 // that wrapping is UB.
1724 .mul => try airBinOp (f, inst, " * "),
1725 // TODO use a different strategy for div that communicates to the optimizer
1726 // that wrapping is UB.
1727 .div_float, .div_exact => try airBinOp( f, inst, " / "),1722 .div_float, .div_exact => try airBinOp( f, inst, " / "),
1728 .div_trunc => blk: {1723 .rem => try airBinOp( f, inst, " % "),
1724
1725 .div_trunc => blk: {
1729 const bin_op = f.air.instructions.items(.data)[inst].bin_op;1726 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1730 const lhs_ty = f.air.typeOf(bin_op.lhs);1727 const lhs_ty = f.air.typeOf(bin_op.lhs);
1731 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),1728 // For binary operations @TypeOf(lhs)==@TypeOf(rhs),
...@@ -1735,9 +1732,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1735,9 +1732,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1735 else1732 else
1736 try airBinOpBuiltinCall(f, inst, "div_trunc");1733 try airBinOpBuiltinCall(f, inst, "div_trunc");
1737 },1734 },
1738 .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),1735 .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"),
1739 .rem => try airBinOp( f, inst, " % "),1736 .mod => try airBinOpBuiltinCall(f, inst, "mod"),
1740 .mod => try airBinOpBuiltinCall(f, inst, "mod"),
17411737
1742 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),1738 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
1743 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),1739 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
...@@ -2617,10 +2613,10 @@ fn airEquality(...@@ -2617,10 +2613,10 @@ fn airEquality(
2617}2613}
26182614
2619fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {2615fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
2620 if (f.liveness.isUnused(inst))2616 if (f.liveness.isUnused(inst)) return CValue.none;
2621 return CValue.none;
26222617
2623 const bin_op = f.air.instructions.items(.data)[inst].bin_op;2618 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2619 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
2624 const lhs = try f.resolveInst(bin_op.lhs);2620 const lhs = try f.resolveInst(bin_op.lhs);
2625 const rhs = try f.resolveInst(bin_op.rhs);2621 const rhs = try f.resolveInst(bin_op.rhs);
26262622
src/codegen/llvm.zig+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;
56815681
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;
57005701
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),
235239
236 .call,240 .call,
...@@ -275,12 +279,6 @@ const Writer = struct {...@@ -275,12 +279,6 @@ const Writer = struct {
275 .reduce => try w.writeReduce(s, inst),279 .reduce => try w.writeReduce(s, inst),
276 .cmp_vector => try w.writeCmpVector(s, inst),280 .cmp_vector => try w.writeCmpVector(s, inst),
277281
278 .add_with_overflow,
279 .sub_with_overflow,
280 .mul_with_overflow,
281 .shl_with_overflow,
282 => try w.writeOverflow(s, inst),
283
284 .dbg_block_begin, .dbg_block_end => {},282 .dbg_block_begin, .dbg_block_end => {},
285 }283 }
286 }284 }
...@@ -478,15 +476,6 @@ const Writer = struct {...@@ -478,15 +476,6 @@ const Writer = struct {
478 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });476 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
479 }477 }
480478
481 fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
482 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
483 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
484
485 try w.writeOperand(s, inst, 0, extra.lhs);
486 try s.writeAll(", ");
487 try w.writeOperand(s, inst, 1, extra.rhs);
488 }
489
490 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {479 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
491 const pl_op = w.air.instructions.items(.data)[inst].pl_op;480 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
492 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;481 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
src/value.zig-22
...@@ -1813,27 +1813,6 @@ pub const Value = extern union {...@@ -1813,27 +1813,6 @@ pub const Value = extern union {
1813 };1813 };
1814 }1814 }
18151815
1816 /// Asserts the value is numeric
1817 pub fn isZero(self: Value) bool {
1818 return switch (self.tag()) {
1819 .zero, .the_only_possible_value => true,
1820 .one => false,
1821
1822 .int_u64 => self.castTag(.int_u64).?.data == 0,
1823 .int_i64 => self.castTag(.int_i64).?.data == 0,
1824
1825 .float_16 => self.castTag(.float_16).?.data == 0,
1826 .float_32 => self.castTag(.float_32).?.data == 0,
1827 .float_64 => self.castTag(.float_64).?.data == 0,
1828 .float_80 => self.castTag(.float_80).?.data == 0,
1829 .float_128 => self.castTag(.float_128).?.data == 0,
1830
1831 .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
1832 .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(),
1833 else => unreachable,
1834 };
1835 }
1836
1837 pub fn orderAgainstZero(lhs: Value) std.math.Order {1816 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1838 return orderAgainstZeroAdvanced(lhs, null) catch unreachable;1817 return orderAgainstZeroAdvanced(lhs, null) catch unreachable;
1839 }1818 }
...@@ -3442,7 +3421,6 @@ pub const Value = extern union {...@@ -3442,7 +3421,6 @@ pub const Value = extern union {
3442 const info = ty.intInfo(target);3421 const info = ty.intInfo(target);
34433422
3444 if (info.bits == 0) {3423 if (info.bits == 0) {
3445 assert(val.isZero()); // Sema should guarantee
3446 return val;3424 return val;
3447 }3425 }
34483426
test/behavior/align.zig+16-5
...@@ -16,11 +16,22 @@ test "global variable alignment" {...@@ -16,11 +16,22 @@ test "global variable alignment" {
16 const slice = @as(*align(4) [1]u8, &foo)[0..];16 const slice = @as(*align(4) [1]u8, &foo)[0..];
17 comptime try expect(@TypeOf(slice) == *align(4) [1]u8);17 comptime try expect(@TypeOf(slice) == *align(4) [1]u8);
18 }18 }
19 {19}
20 var runtime_zero: usize = 0;20
21 const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];21test "slicing array of length 1 can assume runtime index is always zero" {
22 comptime try expect(@TypeOf(slice) == []align(4) u8);22 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
23 }23
24 // TODO reevaluate this test case, because notice that you can
25 // change `runtime_zero` to be `1` and the test still passes for stage1.
26 // Reconsider also this code:
27 // var array: [4]u8 = undefined;
28 // var runtime: usize = 4;
29 // var ptr = array[runtime..];
30 // _ = ptr;
31
32 var runtime_zero: usize = 0;
33 const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..];
34 comptime try expect(@TypeOf(slice) == []align(4) u8);
24}35}
2536
26test "default alignment allows unspecified in type syntax" {37test "default alignment allows unspecified in type syntax" {
test/behavior/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}
378378
379test "pointer arithmetic affects the alignment" {379test "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;