@@ -1086,29 +1086,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1086
1086
// have to be removed. this only happens if the dst if not a power-of-two size.
1087
1087
const dst_bit_size = dst_ty .bitSize (self .target .* );
1088
1088
if (! math .isPowerOfTwo (dst_bit_size ) or dst_bit_size < 8 ) {
1089
- const max_reg_bit_width = Register .rax .size ();
1090
- const shift = @intCast (u6 , max_reg_bit_width - dst_ty .bitSize (self .target .* ));
1091
- const mask = (~ @as (u64 , 0 )) >> shift ;
1092
- try self .genBinMathOpMir (.@"and" , Type .usize , .{ .register = reg }, .{ .immediate = mask });
1093
-
1094
- if (src_ty .intInfo (self .target .* ).signedness == .signed ) {
1095
- _ = try self .addInst (.{
1096
- .tag = .sal ,
1097
- .ops = (Mir.Ops {
1098
- .reg1 = reg ,
1099
- .flags = 0b10 ,
1100
- }).encode (),
1101
- .data = .{ .imm = shift },
1102
- });
1103
- _ = try self .addInst (.{
1104
- .tag = .sar ,
1105
- .ops = (Mir.Ops {
1106
- .reg1 = reg ,
1107
- .flags = 0b10 ,
1108
- }).encode (),
1109
- .data = .{ .imm = shift },
1110
- });
1111
- }
1089
+ try self .truncateRegister (dst_ty , reg );
1112
1090
}
1113
1091
1114
1092
return self .finishAir (inst , .{ .register = reg }, .{ ty_op .operand , .none , .none });
@@ -1478,31 +1456,119 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1478
1456
switch (ty .zigTypeTag ()) {
1479
1457
.Vector = > return self .fail ("TODO implement mul_with_overflow for Vector type" , .{}),
1480
1458
.Int = > {
1459
+ try self .spillCompareFlagsIfOccupied ();
1460
+ self .compare_flags_inst = null ;
1461
+
1481
1462
const int_info = ty .intInfo (self .target .* );
1482
1463
1483
1464
if (int_info .bits > 64 ) {
1484
1465
return self .fail ("TODO implement mul_with_overflow for Ints larger than 64bits" , .{});
1485
1466
}
1486
1467
1487
- // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1488
- try self .register_manager .getReg (.rax , inst );
1489
- try self .register_manager .getReg (.rdx , null );
1490
- self .register_manager .freezeRegs (&.{ .rax , .rdx });
1491
- defer self .register_manager .unfreezeRegs (&.{ .rax , .rdx });
1468
+ if (math .isPowerOfTwo (int_info .bits )) {
1469
+ // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1470
+ try self .register_manager .getReg (.rax , inst );
1471
+ try self .register_manager .getReg (.rdx , null );
1472
+ self .register_manager .freezeRegs (&.{ .rax , .rdx });
1473
+ defer self .register_manager .unfreezeRegs (&.{ .rax , .rdx });
1474
+
1475
+ const lhs = try self .resolveInst (bin_op .lhs );
1476
+ const rhs = try self .resolveInst (bin_op .rhs );
1477
+
1478
+ try self .genIntMulDivOpMir (switch (int_info .signedness ) {
1479
+ .signed = > .imul ,
1480
+ .unsigned = > .mul ,
1481
+ }, ty , int_info .signedness , lhs , rhs );
1482
+
1483
+ const result : MCValue = switch (int_info .signedness ) {
1484
+ .signed = > .{ .register_overflow_signed = .rax },
1485
+ .unsigned = > .{ .register_overflow_unsigned = .rax },
1486
+ };
1487
+ break :result result ;
1488
+ }
1492
1489
1493
1490
const lhs = try self .resolveInst (bin_op .lhs );
1494
1491
const rhs = try self .resolveInst (bin_op .rhs );
1495
1492
1496
- try self .genIntMulDivOpMir (switch (int_info .signedness ) {
1497
- .signed = > .imul ,
1498
- .unsigned = > .mul ,
1499
- }, ty , int_info .signedness , lhs , rhs );
1493
+ rhs .freezeIfRegister (& self .register_manager );
1494
+ defer rhs .unfreezeIfRegister (& self .register_manager );
1500
1495
1501
- const result : MCValue = switch (int_info .signedness ) {
1502
- .signed = > .{ .register_overflow_signed = .rax },
1503
- .unsigned = > .{ .register_overflow_unsigned = .rax },
1496
+ // TODO check if we could reuse rhs instead, and swap the values out.
1497
+ const dst_mcv = blk : {
1498
+ if (self .reuseOperand (inst , bin_op .lhs , 0 , lhs )) {
1499
+ if (lhs .isRegister ()) break :blk lhs ;
1500
+ }
1501
+ break :blk MCValue { .register = try self .copyToTmpRegister (ty , lhs ) };
1504
1502
};
1505
- break :result result ;
1503
+ dst_mcv .freezeIfRegister (& self .register_manager );
1504
+ defer dst_mcv .unfreezeIfRegister (& self .register_manager );
1505
+
1506
+ const rhs_mcv = blk : {
1507
+ if (rhs .isRegister () or rhs .isMemory ()) break :blk rhs ;
1508
+ break :blk MCValue { .register = try self .copyToTmpRegister (ty , rhs ) };
1509
+ };
1510
+ rhs_mcv .freezeIfRegister (& self .register_manager );
1511
+ defer rhs_mcv .unfreezeIfRegister (& self .register_manager );
1512
+
1513
+ const tuple_ty = self .air .typeOfIndex (inst );
1514
+ const tuple_size = @intCast (u32 , tuple_ty .abiSize (self .target .* ));
1515
+ const tuple_align = tuple_ty .abiAlignment (self .target .* );
1516
+ const overflow_bit_offset = @intCast (i32 , tuple_ty .structFieldOffset (1 , self .target .* ));
1517
+
1518
+ const stack_offset = @intCast (i32 , try self .allocMem (inst , tuple_size , tuple_align ));
1519
+ const extended_ty = switch (int_info .signedness ) {
1520
+ .signed = > Type .isize ,
1521
+ .unsigned = > ty ,
1522
+ };
1523
+
1524
+ try self .genIntMulComplexOpMir (extended_ty , dst_mcv , rhs_mcv );
1525
+
1526
+ const temp_regs = try self .register_manager .allocRegs (3 , .{ null , null , null });
1527
+ self .register_manager .freezeRegs (& temp_regs );
1528
+ defer self .register_manager .unfreezeRegs (& temp_regs );
1529
+
1530
+ const overflow_reg = temp_regs [0 ];
1531
+ const flags : u2 = switch (int_info .signedness ) {
1532
+ .signed = > 0b00 ,
1533
+ .unsigned = > 0b10 ,
1534
+ };
1535
+ _ = try self .addInst (.{
1536
+ .tag = .cond_set_byte_overflow ,
1537
+ .ops = (Mir.Ops {
1538
+ .reg1 = overflow_reg .to8 (),
1539
+ .flags = flags ,
1540
+ }).encode (),
1541
+ .data = undefined ,
1542
+ });
1543
+
1544
+ const scratch_reg = temp_regs [1 ];
1545
+ try self .genSetReg (extended_ty , scratch_reg , dst_mcv );
1546
+ try self .truncateRegister (ty , scratch_reg );
1547
+ try self .genBinMathOpMir (.cmp , extended_ty , dst_mcv , .{ .register = scratch_reg });
1548
+
1549
+ const eq_reg = temp_regs [2 ];
1550
+ _ = try self .addInst (.{
1551
+ .tag = .cond_set_byte_eq_ne ,
1552
+ .ops = (Mir.Ops {
1553
+ .reg1 = eq_reg .to8 (),
1554
+ .flags = 0b00 ,
1555
+ }).encode (),
1556
+ .data = undefined ,
1557
+ });
1558
+
1559
+ try self .genBinMathOpMir (
1560
+ .@"or" ,
1561
+ Type .u8 ,
1562
+ .{ .register = overflow_reg },
1563
+ .{ .register = eq_reg },
1564
+ );
1565
+
1566
+ try self .genSetStack (ty , stack_offset , .{ .register = scratch_reg }, .{});
1567
+ try self .genSetStack (Type .initTag (.u1 ), stack_offset - overflow_bit_offset , .{
1568
+ .register = overflow_reg .to8 (),
1569
+ }, .{});
1570
+
1571
+ break :result MCValue { .stack_offset = stack_offset };
1506
1572
},
1507
1573
else = > unreachable ,
1508
1574
}
@@ -1648,7 +1714,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
1648
1714
}).encode (),
1649
1715
.data = undefined ,
1650
1716
});
1651
- try self .genBinMathOpMir (.add , Type .isize , .{ .register = divisor . to64 () }, .{ .register = .rax });
1717
+ try self .genBinMathOpMir (.add , Type .isize , .{ .register = divisor }, .{ .register = .rax });
1652
1718
return MCValue { .register = divisor };
1653
1719
}
1654
1720
@@ -2222,8 +2288,8 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2222
2288
}
2223
2289
// TODO we could allocate register here, but need to expect addr register and potentially
2224
2290
// offset register.
2225
- try self .genBinMathOpMir (.add , slice_ptr_field_type , .{ .register = addr_reg . to64 () }, .{
2226
- .register = offset_reg . to64 () ,
2291
+ try self .genBinMathOpMir (.add , slice_ptr_field_type , .{ .register = addr_reg }, .{
2292
+ .register = offset_reg ,
2227
2293
});
2228
2294
return MCValue { .register = addr_reg .to64 () };
2229
2295
}
@@ -2315,7 +2381,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2315
2381
// TODO we could allocate register here, but need to expect addr register and potentially
2316
2382
// offset register.
2317
2383
const dst_mcv = try self .allocRegOrMem (inst , false );
2318
- try self .genBinMathOpMir (.add , array_ty , .{ .register = addr_reg . to64 () }, .{ .register = offset_reg . to64 () });
2384
+ try self .genBinMathOpMir (.add , Type . usize , .{ .register = addr_reg }, .{ .register = offset_reg });
2319
2385
try self .load (dst_mcv , .{ .register = addr_reg .to64 () }, array_ty );
2320
2386
break :result dst_mcv ;
2321
2387
};
@@ -3178,8 +3244,8 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
3178
3244
_ = try self .addInst (.{
3179
3245
.tag = mir_tag ,
3180
3246
.ops = (Mir.Ops {
3181
- .reg1 = registerAlias (dst_reg , @divExact ( src_reg . size (), 8 ) ),
3182
- .reg2 = src_reg ,
3247
+ .reg1 = registerAlias (dst_reg , abi_size ),
3248
+ .reg2 = registerAlias ( src_reg , abi_size ) ,
3183
3249
}).encode (),
3184
3250
.data = undefined ,
3185
3251
});
@@ -6531,3 +6597,36 @@ fn shiftRegister(self: *Self, reg: Register, shift: u8) !void {
6531
6597
});
6532
6598
}
6533
6599
}
6600
+
6601
+ /// Truncates the value in the register in place.
6602
+ /// Clobbers any remaining bits.
6603
+ fn truncateRegister (self : * Self , ty : Type , reg : Register ) ! void {
6604
+ const int_info = ty .intInfo (self .target .* );
6605
+ const max_reg_bit_width = Register .rax .size ();
6606
+ switch (int_info .signedness ) {
6607
+ .signed = > {
6608
+ const shift = @intCast (u6 , max_reg_bit_width - int_info .bits );
6609
+ _ = try self .addInst (.{
6610
+ .tag = .sal ,
6611
+ .ops = (Mir.Ops {
6612
+ .reg1 = reg .to64 (),
6613
+ .flags = 0b10 ,
6614
+ }).encode (),
6615
+ .data = .{ .imm = shift },
6616
+ });
6617
+ _ = try self .addInst (.{
6618
+ .tag = .sar ,
6619
+ .ops = (Mir.Ops {
6620
+ .reg1 = reg .to64 (),
6621
+ .flags = 0b10 ,
6622
+ }).encode (),
6623
+ .data = .{ .imm = shift },
6624
+ });
6625
+ },
6626
+ .unsigned = > {
6627
+ const shift = @intCast (u6 , max_reg_bit_width - int_info .bits );
6628
+ const mask = (~ @as (u64 , 0 )) >> shift ;
6629
+ try self .genBinMathOpMir (.@"and" , Type .usize , .{ .register = reg }, .{ .immediate = mask });
6630
+ },
6631
+ }
6632
+ }
0 commit comments