| author | |
| committer | |
| log | b6798c26efc4689cf35c5f4ac0436b4510a1f813 |
| tree | 9507321f623264de9c5bef41ff53c19c88f09bd3 |
| parent | 95f5e17e49d32a301d6a9d6f9948719d65469b09 |
This makes it so the result of doing pointer arithmetic creates a new
pointer type that has adjusted alignment.16 files changed, 464 insertions(+), 340 deletions(-)
lib/std/heap.zig+1-1| ... | ... | @@ -345,7 +345,7 @@ const PageAllocator = struct { |
| 345 | 345 | // Unmap extra pages |
| 346 | 346 | const aligned_buffer_len = alloc_len - drop_len; |
| 347 | 347 | if (aligned_buffer_len > aligned_len) { |
| 348 | os.munmap(result_ptr[aligned_len..aligned_buffer_len]); | |
| 348 | os.munmap(@alignCast(mem.page_size, result_ptr[aligned_len..aligned_buffer_len])); | |
| 349 | 349 | } |
| 350 | 350 | |
| 351 | 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 | 113 | /// The offset is in element type units, not bytes. |
| 114 | 114 | /// Wrapping is undefined behavior. |
| 115 | 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 | 117 | ptr_add, |
| 118 | 118 | /// Subtract an offset from a pointer, returning a new pointer. |
| 119 | 119 | /// The offset is in element type units, not bytes. |
| 120 | 120 | /// Wrapping is undefined behavior. |
| 121 | 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 | 123 | ptr_sub, |
| 124 | 124 | /// Given two operands which can be floats, integers, or vectors, returns the |
| 125 | 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 | 916 | .bit_and, |
| 917 | 917 | .bit_or, |
| 918 | 918 | .xor, |
| 919 | .ptr_add, | |
| 920 | .ptr_sub, | |
| 921 | 919 | .shr, |
| 922 | 920 | .shr_exact, |
| 923 | 921 | .shl, |
| ... | ... | @@ -989,6 +987,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 989 | 987 | .sub_with_overflow, |
| 990 | 988 | .mul_with_overflow, |
| 991 | 989 | .shl_with_overflow, |
| 990 | .ptr_add, | |
| 991 | .ptr_sub, | |
| 992 | 992 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 993 | 993 | |
| 994 | 994 | .not, |
src/Liveness.zig+16-15| ... | ... | @@ -312,8 +312,6 @@ fn analyzeInst( |
| 312 | 312 | .div_exact, |
| 313 | 313 | .rem, |
| 314 | 314 | .mod, |
| 315 | .ptr_add, | |
| 316 | .ptr_sub, | |
| 317 | 315 | .bit_and, |
| 318 | 316 | .bit_or, |
| 319 | 317 | .xor, |
| ... | ... | @@ -441,6 +439,21 @@ fn analyzeInst( |
| 441 | 439 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
| 442 | 440 | }, |
| 443 | 441 | |
| 442 | .add_with_overflow, | |
| 443 | .sub_with_overflow, | |
| 444 | .mul_with_overflow, | |
| 445 | .shl_with_overflow, | |
| 446 | .ptr_add, | |
| 447 | .ptr_sub, | |
| 448 | .ptr_elem_ptr, | |
| 449 | .slice_elem_ptr, | |
| 450 | .slice, | |
| 451 | => { | |
| 452 | const ty_pl = inst_datas[inst].ty_pl; | |
| 453 | const extra = a.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 454 | return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none }); | |
| 455 | }, | |
| 456 | ||
| 444 | 457 | .dbg_var_ptr, |
| 445 | 458 | .dbg_var_val, |
| 446 | 459 | => { |
| ... | ... | @@ -529,10 +542,6 @@ fn analyzeInst( |
| 529 | 542 | const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data; |
| 530 | 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 | 545 | .cmpxchg_strong, .cmpxchg_weak => { |
| 537 | 546 | const extra = a.air.extraData(Air.Cmpxchg, inst_datas[inst].ty_pl.payload).data; |
| 538 | 547 | return trackOperands(a, new_set, inst, main_tomb, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| ... | ... | @@ -558,15 +567,7 @@ fn analyzeInst( |
| 558 | 567 | const extra = a.air.extraData(Air.Bin, pl_op.payload).data; |
| 559 | 568 | return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 560 | 569 | }, |
| 561 | .add_with_overflow, | |
| 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 | ||
| 570 | 571 | .br => { |
| 571 | 572 | const br = inst_datas[inst].br; |
| 572 | 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 | 10610 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| 10611 | 10611 | // coerce to isize instead of usize. |
| 10612 | 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 | 10613 | const target = sema.mod.getTarget(); |
| 10615 | const runtime_src = rs: { | |
| 10616 | if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { | |
| 10617 | if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| { | |
| 10618 | const ptr_ty = sema.typeOf(ptr); | |
| 10619 | const new_ptr_ty = ptr_ty; // TODO modify alignment | |
| 10614 | const opt_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, ptr); | |
| 10615 | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); | |
| 10616 | const ptr_ty = sema.typeOf(ptr); | |
| 10617 | const ptr_info = ptr_ty.ptrInfo().data; | |
| 10618 | const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array) | |
| 10619 | ptr_info.pointee_type.childType() | |
| 10620 | else | |
| 10621 | ptr_info.pointee_type; | |
| 10622 | ||
| 10623 | const new_ptr_ty = t: { | |
| 10624 | // Calculate the new pointer alignment. | |
| 10625 | if (ptr_info.@"align" == 0) { | |
| 10626 | // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness. | |
| 10627 | break :t ptr_ty; | |
| 10628 | } | |
| 10629 | // If the addend is not a comptime-known value we can still count on | |
| 10630 | // it being a multiple of the type size. | |
| 10631 | const elem_size = elem_ty.abiSize(target); | |
| 10632 | const addend = if (opt_off_val) |off_val| a: { | |
| 10633 | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target)); | |
| 10634 | break :a elem_size * off_int; | |
| 10635 | } else elem_size; | |
| 10636 | ||
| 10637 | // The resulting pointer is aligned to the lcd between the offset (an | |
| 10638 | // arbitrary number) and the alignment factor (always a power of two, | |
| 10639 | // non zero). | |
| 10640 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, addend | ptr_info.@"align")); | |
| 10641 | ||
| 10642 | break :t try Type.ptr(sema.arena, sema.mod, .{ | |
| 10643 | .pointee_type = ptr_info.pointee_type, | |
| 10644 | .sentinel = ptr_info.sentinel, | |
| 10645 | .@"align" = new_align, | |
| 10646 | .@"addrspace" = ptr_info.@"addrspace", | |
| 10647 | .mutable = ptr_info.mutable, | |
| 10648 | .@"allowzero" = ptr_info.@"allowzero", | |
| 10649 | .@"volatile" = ptr_info.@"volatile", | |
| 10650 | .size = ptr_info.size, | |
| 10651 | }); | |
| 10652 | }; | |
| 10620 | 10653 | |
| 10621 | if (ptr_val.isUndef() or offset_val.isUndef()) { | |
| 10622 | return sema.addConstUndef(new_ptr_ty); | |
| 10623 | } | |
| 10654 | const runtime_src = rs: { | |
| 10655 | if (opt_ptr_val) |ptr_val| { | |
| 10656 | if (opt_off_val) |offset_val| { | |
| 10657 | if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty); | |
| 10624 | 10658 | |
| 10625 | 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 | 10660 | if (offset_int == 0) return ptr; |
| 10628 | 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 | 10662 | const elem_size = elem_ty.abiSize(target); |
| 10636 | 10663 | const new_addr = switch (air_tag) { |
| 10637 | 10664 | .ptr_add => addr + elem_size * offset_int, |
| ... | ... | @@ -10651,7 +10678,16 @@ fn analyzePtrArithmetic( |
| 10651 | 10678 | }; |
| 10652 | 10679 | |
| 10653 | 10680 | try sema.requireRuntimeBlock(block, runtime_src); |
| 10654 | return block.addBinOp(air_tag, ptr, offset); | |
| 10681 | return block.addInst(.{ | |
| 10682 | .tag = air_tag, | |
| 10683 | .data = .{ .ty_pl = .{ | |
| 10684 | .ty = try sema.addType(new_ptr_ty), | |
| 10685 | .payload = try sema.addExtra(Air.Bin{ | |
| 10686 | .lhs = ptr, | |
| 10687 | .rhs = offset, | |
| 10688 | }), | |
| 10689 | } }, | |
| 10690 | }); | |
| 10655 | 10691 | } |
| 10656 | 10692 | |
| 10657 | 10693 | fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
src/arch/aarch64/CodeGen.zig+98-68| ... | ... | @@ -545,18 +545,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 545 | 545 | |
| 546 | 546 | switch (air_tags[inst]) { |
| 547 | 547 | // zig fmt: off |
| 548 | .add, .ptr_add => try self.airBinOp(inst), | |
| 549 | .addwrap => try self.airBinOp(inst), | |
| 548 | .add => try self.airBinOp(inst, .add), | |
| 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 | 567 | .add_sat => try self.airAddSat(inst), |
| 551 | .sub, .ptr_sub => try self.airBinOp(inst), | |
| 552 | .subwrap => try self.airBinOp(inst), | |
| 553 | 568 | .sub_sat => try self.airSubSat(inst), |
| 554 | .mul => try self.airBinOp(inst), | |
| 555 | .mulwrap => try self.airBinOp(inst), | |
| 556 | 569 | .mul_sat => try self.airMulSat(inst), |
| 557 | 570 | .rem => try self.airRem(inst), |
| 558 | 571 | .mod => try self.airMod(inst), |
| 559 | .shl, .shl_exact => try self.airBinOp(inst), | |
| 560 | 572 | .shl_sat => try self.airShlSat(inst), |
| 561 | 573 | .min => try self.airMin(inst), |
| 562 | 574 | .max => try self.airMax(inst), |
| ... | ... | @@ -595,13 +607,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 595 | 607 | .cmp_vector => try self.airCmpVector(inst), |
| 596 | 608 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 597 | 609 | |
| 598 | .bool_and => try self.airBinOp(inst), | |
| 599 | .bool_or => try self.airBinOp(inst), | |
| 600 | .bit_and => try self.airBinOp(inst), | |
| 601 | .bit_or => try self.airBinOp(inst), | |
| 602 | .xor => try self.airBinOp(inst), | |
| 603 | .shr, .shr_exact => try self.airBinOp(inst), | |
| 604 | ||
| 605 | 610 | .alloc => try self.airAlloc(inst), |
| 606 | 611 | .ret_ptr => try self.airRetPtr(inst), |
| 607 | 612 | .arg => try self.airArg(inst), |
| ... | ... | @@ -1260,11 +1265,11 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1260 | 1265 | fn binOpRegister( |
| 1261 | 1266 | self: *Self, |
| 1262 | 1267 | mir_tag: Mir.Inst.Tag, |
| 1263 | maybe_inst: ?Air.Inst.Index, | |
| 1264 | 1268 | lhs: MCValue, |
| 1265 | 1269 | rhs: MCValue, |
| 1266 | 1270 | lhs_ty: Type, |
| 1267 | 1271 | rhs_ty: Type, |
| 1272 | metadata: ?BinOpMetadata, | |
| 1268 | 1273 | ) !MCValue { |
| 1269 | 1274 | const lhs_is_register = lhs == .register; |
| 1270 | 1275 | const rhs_is_register = rhs == .register; |
| ... | ... | @@ -1284,9 +1289,8 @@ fn binOpRegister( |
| 1284 | 1289 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1285 | 1290 | |
| 1286 | 1291 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| 1287 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 1288 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1289 | break :inst Air.refToIndex(bin_op.lhs).?; | |
| 1292 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1293 | break :inst Air.refToIndex(md.lhs).?; | |
| 1290 | 1294 | } else null; |
| 1291 | 1295 | |
| 1292 | 1296 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -1300,9 +1304,8 @@ fn binOpRegister( |
| 1300 | 1304 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1301 | 1305 | |
| 1302 | 1306 | const rhs_reg = if (rhs_is_register) rhs.register else blk: { |
| 1303 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 1304 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1305 | break :inst Air.refToIndex(bin_op.rhs).?; | |
| 1307 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1308 | break :inst Air.refToIndex(md.rhs).?; | |
| 1306 | 1309 | } else null; |
| 1307 | 1310 | |
| 1308 | 1311 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -1317,15 +1320,13 @@ fn binOpRegister( |
| 1317 | 1320 | |
| 1318 | 1321 | const dest_reg = switch (mir_tag) { |
| 1319 | 1322 | .cmp_shifted_register => undefined, // cmp has no destination register |
| 1320 | else => if (maybe_inst) |inst| blk: { | |
| 1321 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1322 | ||
| 1323 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | |
| 1323 | else => if (metadata) |md| blk: { | |
| 1324 | if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) { | |
| 1324 | 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 | 1327 | break :blk rhs_reg; |
| 1327 | 1328 | } else { |
| 1328 | const raw_reg = try self.register_manager.allocReg(inst); | |
| 1329 | const raw_reg = try self.register_manager.allocReg(md.inst); | |
| 1329 | 1330 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1330 | 1331 | } |
| 1331 | 1332 | } else blk: { |
| ... | ... | @@ -1407,11 +1408,11 @@ fn binOpRegister( |
| 1407 | 1408 | fn binOpImmediate( |
| 1408 | 1409 | self: *Self, |
| 1409 | 1410 | mir_tag: Mir.Inst.Tag, |
| 1410 | maybe_inst: ?Air.Inst.Index, | |
| 1411 | 1411 | lhs: MCValue, |
| 1412 | 1412 | rhs: MCValue, |
| 1413 | 1413 | lhs_ty: Type, |
| 1414 | 1414 | lhs_and_rhs_swapped: bool, |
| 1415 | metadata: ?BinOpMetadata, | |
| 1415 | 1416 | ) !MCValue { |
| 1416 | 1417 | const lhs_is_register = lhs == .register; |
| 1417 | 1418 | |
| ... | ... | @@ -1424,10 +1425,9 @@ fn binOpImmediate( |
| 1424 | 1425 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1425 | 1426 | |
| 1426 | 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 bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1428 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1429 | 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 | 1432 | } else null; |
| 1433 | 1433 | |
| ... | ... | @@ -1443,18 +1443,16 @@ fn binOpImmediate( |
| 1443 | 1443 | |
| 1444 | 1444 | const dest_reg = switch (mir_tag) { |
| 1445 | 1445 | .cmp_immediate => undefined, // cmp has no destination register |
| 1446 | else => if (maybe_inst) |inst| blk: { | |
| 1447 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1448 | ||
| 1446 | else => if (metadata) |md| blk: { | |
| 1449 | 1447 | if (lhs_is_register and self.reuseOperand( |
| 1450 | inst, | |
| 1451 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, | |
| 1448 | md.inst, | |
| 1449 | if (lhs_and_rhs_swapped) md.rhs else md.lhs, | |
| 1452 | 1450 | if (lhs_and_rhs_swapped) 1 else 0, |
| 1453 | 1451 | lhs, |
| 1454 | 1452 | )) { |
| 1455 | 1453 | break :blk lhs_reg; |
| 1456 | 1454 | } else { |
| 1457 | const raw_reg = try self.register_manager.allocReg(inst); | |
| 1455 | const raw_reg = try self.register_manager.allocReg(md.inst); | |
| 1458 | 1456 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1459 | 1457 | } |
| 1460 | 1458 | } else blk: { |
| ... | ... | @@ -1498,6 +1496,12 @@ fn binOpImmediate( |
| 1498 | 1496 | return MCValue{ .register = dest_reg }; |
| 1499 | 1497 | } |
| 1500 | 1498 | |
| 1499 | const BinOpMetadata = struct { | |
| 1500 | inst: Air.Inst.Index, | |
| 1501 | lhs: Air.Inst.Ref, | |
| 1502 | rhs: Air.Inst.Ref, | |
| 1503 | }; | |
| 1504 | ||
| 1501 | 1505 | /// For all your binary operation needs, this function will generate |
| 1502 | 1506 | /// the corresponding Mir instruction(s). Returns the location of the |
| 1503 | 1507 | /// result. |
| ... | ... | @@ -1513,11 +1517,11 @@ fn binOpImmediate( |
| 1513 | 1517 | fn binOp( |
| 1514 | 1518 | self: *Self, |
| 1515 | 1519 | tag: Air.Inst.Tag, |
| 1516 | maybe_inst: ?Air.Inst.Index, | |
| 1517 | 1520 | lhs: MCValue, |
| 1518 | 1521 | rhs: MCValue, |
| 1519 | 1522 | lhs_ty: Type, |
| 1520 | 1523 | rhs_ty: Type, |
| 1524 | metadata: ?BinOpMetadata, | |
| 1521 | 1525 | ) InnerError!MCValue { |
| 1522 | 1526 | const mod = self.bin_file.options.module.?; |
| 1523 | 1527 | switch (tag) { |
| ... | ... | @@ -1562,12 +1566,12 @@ fn binOp( |
| 1562 | 1566 | }; |
| 1563 | 1567 | |
| 1564 | 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 | 1570 | } else if (lhs_immediate_ok) { |
| 1567 | 1571 | // swap lhs and rhs |
| 1568 | return try self.binOpImmediate(mir_tag_immediate, maybe_inst, rhs, lhs, rhs_ty, true); | |
| 1572 | return try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, metadata); | |
| 1569 | 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 | 1576 | } else { |
| 1573 | 1577 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1586,7 +1590,7 @@ fn binOp( |
| 1586 | 1590 | // TODO add optimisations for multiplication |
| 1587 | 1591 | // with immediates, for example a * 2 can be |
| 1588 | 1592 | // lowered to a << 1 |
| 1589 | return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1593 | return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1590 | 1594 | } else { |
| 1591 | 1595 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1592 | 1596 | } |
| ... | ... | @@ -1606,7 +1610,7 @@ fn binOp( |
| 1606 | 1610 | }; |
| 1607 | 1611 | |
| 1608 | 1612 | // Generate an add/sub/mul |
| 1609 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1613 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1610 | 1614 | |
| 1611 | 1615 | // Truncate if necessary |
| 1612 | 1616 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -1642,7 +1646,7 @@ fn binOp( |
| 1642 | 1646 | else => unreachable, |
| 1643 | 1647 | }; |
| 1644 | 1648 | |
| 1645 | return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1649 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1646 | 1650 | } else { |
| 1647 | 1651 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1648 | 1652 | } |
| ... | ... | @@ -1678,9 +1682,9 @@ fn binOp( |
| 1678 | 1682 | }; |
| 1679 | 1683 | |
| 1680 | 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 | 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 | 1689 | } else { |
| 1686 | 1690 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1699,7 +1703,7 @@ fn binOp( |
| 1699 | 1703 | }; |
| 1700 | 1704 | |
| 1701 | 1705 | // Generate a shl_exact/shr_exact |
| 1702 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1706 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1703 | 1707 | |
| 1704 | 1708 | // Truncate if necessary |
| 1705 | 1709 | switch (tag) { |
| ... | ... | @@ -1735,7 +1739,7 @@ fn binOp( |
| 1735 | 1739 | else => unreachable, |
| 1736 | 1740 | }; |
| 1737 | 1741 | |
| 1738 | return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1742 | return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1739 | 1743 | }, |
| 1740 | 1744 | else => unreachable, |
| 1741 | 1745 | } |
| ... | ... | @@ -1759,12 +1763,12 @@ fn binOp( |
| 1759 | 1763 | else => unreachable, |
| 1760 | 1764 | }; |
| 1761 | 1765 | |
| 1762 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1766 | return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1763 | 1767 | } else { |
| 1764 | 1768 | // convert the offset into a byte offset by |
| 1765 | 1769 | // multiplying it with elem_size |
| 1766 | const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize); | |
| 1767 | const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize); | |
| 1770 | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); | |
| 1771 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); | |
| 1768 | 1772 | return addr; |
| 1769 | 1773 | } |
| 1770 | 1774 | }, |
| ... | ... | @@ -1775,8 +1779,7 @@ fn binOp( |
| 1775 | 1779 | } |
| 1776 | 1780 | } |
| 1777 | 1781 | |
| 1778 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 1779 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 1782 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1780 | 1783 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1781 | 1784 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1782 | 1785 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1786,7 +1789,30 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1786 | 1789 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1787 | 1790 | .dead |
| 1788 | 1791 | else |
| 1789 | try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1792 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 1793 | .inst = inst, | |
| 1794 | .lhs = bin_op.lhs, | |
| 1795 | .rhs = bin_op.rhs, | |
| 1796 | }); | |
| 1797 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1798 | } | |
| 1799 | ||
| 1800 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1801 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1802 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 1803 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1804 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1805 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1806 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1807 | ||
| 1808 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1809 | .dead | |
| 1810 | else | |
| 1811 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 1812 | .inst = inst, | |
| 1813 | .lhs = bin_op.lhs, | |
| 1814 | .rhs = bin_op.rhs, | |
| 1815 | }); | |
| 1790 | 1816 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1791 | 1817 | } |
| 1792 | 1818 | |
| ... | ... | @@ -1841,7 +1867,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1841 | 1867 | .sub_with_overflow => .sub, |
| 1842 | 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 | 1871 | const dest_reg = dest.register; |
| 1846 | 1872 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1847 | 1873 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -1855,7 +1881,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1855 | 1881 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 1856 | 1882 | |
| 1857 | 1883 | // cmp dest, truncated |
| 1858 | _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize); | |
| 1884 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | |
| 1859 | 1885 | |
| 1860 | 1886 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1861 | 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 | 1920 | |
| 1895 | 1921 | const dest = blk: { |
| 1896 | 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 | 1924 | } else if (lhs_immediate_ok) { |
| 1899 | 1925 | // swap lhs and rhs |
| 1900 | break :blk try self.binOpImmediate(mir_tag_immediate, null, rhs, lhs, rhs_ty, true); | |
| 1926 | break :blk try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, null); | |
| 1901 | 1927 | } else { |
| 1902 | break :blk try self.binOpRegister(mir_tag_register, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 1928 | break :blk try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 1903 | 1929 | } |
| 1904 | 1930 | }; |
| 1905 | 1931 | |
| ... | ... | @@ -1952,7 +1978,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1952 | 1978 | .unsigned => .umull, |
| 1953 | 1979 | }; |
| 1954 | 1980 | |
| 1955 | const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 1981 | const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 1956 | 1982 | const dest_reg = dest.register; |
| 1957 | 1983 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1958 | 1984 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -2136,11 +2162,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2136 | 2162 | |
| 2137 | 2163 | _ = try self.binOp( |
| 2138 | 2164 | .cmp_eq, |
| 2139 | null, | |
| 2140 | 2165 | .{ .register = dest_high_reg }, |
| 2141 | 2166 | .{ .immediate = 0 }, |
| 2142 | 2167 | Type.usize, |
| 2143 | 2168 | Type.usize, |
| 2169 | null, | |
| 2144 | 2170 | ); |
| 2145 | 2171 | |
| 2146 | 2172 | if (int_info.bits < 64) { |
| ... | ... | @@ -2156,11 +2182,11 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2156 | 2182 | |
| 2157 | 2183 | _ = try self.binOp( |
| 2158 | 2184 | .cmp_eq, |
| 2159 | null, | |
| 2160 | 2185 | .{ .register = dest_high_reg }, |
| 2161 | 2186 | .{ .immediate = 0 }, |
| 2162 | 2187 | Type.usize, |
| 2163 | 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 | 2244 | self.compare_flags_inst = null; |
| 2219 | 2245 | |
| 2220 | 2246 | // lsl dest, lhs, rhs |
| 2221 | const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 2247 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 2222 | 2248 | const dest_reg = dest.register; |
| 2223 | 2249 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 2224 | 2250 | defer self.register_manager.unlockReg(dest_reg_lock); |
| 2225 | 2251 | |
| 2226 | 2252 | // asr/lsr reconstructed, dest, rhs |
| 2227 | const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty); | |
| 2253 | const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null); | |
| 2228 | 2254 | |
| 2229 | 2255 | // cmp lhs, reconstructed |
| 2230 | _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty); | |
| 2256 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); | |
| 2231 | 2257 | |
| 2232 | 2258 | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 2233 | 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 | 2515 | switch (elem_size) { |
| 2490 | 2516 | else => { |
| 2491 | 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 | 2519 | try self.load(dest, addr, slice_ptr_field_type); |
| 2494 | 2520 | |
| 2495 | 2521 | break :result dest; |
| ... | ... | @@ -2933,11 +2959,11 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2933 | 2959 | |
| 2934 | 2960 | const dest = try self.binOp( |
| 2935 | 2961 | .add, |
| 2936 | null, | |
| 2937 | 2962 | .{ .register = addr_reg }, |
| 2938 | 2963 | .{ .register = offset_reg }, |
| 2939 | 2964 | Type.usize, |
| 2940 | 2965 | Type.usize, |
| 2966 | null, | |
| 2941 | 2967 | ); |
| 2942 | 2968 | |
| 2943 | 2969 | break :result dest; |
| ... | ... | @@ -3302,7 +3328,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3302 | 3328 | |
| 3303 | 3329 | const int_info = int_ty.intInfo(self.target.*); |
| 3304 | 3330 | if (int_info.bits <= 64) { |
| 3305 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); | |
| 3331 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ | |
| 3332 | .inst = inst, | |
| 3333 | .lhs = bin_op.lhs, | |
| 3334 | .rhs = bin_op.rhs, | |
| 3335 | }); | |
| 3306 | 3336 | |
| 3307 | 3337 | try self.spillCompareFlagsIfOccupied(); |
| 3308 | 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 | 552 | |
| 553 | 553 | switch (air_tags[inst]) { |
| 554 | 554 | // zig fmt: off |
| 555 | .add, .ptr_add => try self.airBinOp(inst), | |
| 556 | .addwrap => try self.airBinOp(inst), | |
| 555 | .add, => try self.airBinOp(inst, .add), | |
| 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 | 577 | .add_sat => try self.airAddSat(inst), |
| 558 | .sub, .ptr_sub => try self.airBinOp(inst), | |
| 559 | .subwrap => try self.airBinOp(inst), | |
| 560 | 578 | .sub_sat => try self.airSubSat(inst), |
| 561 | .mul => try self.airBinOp(inst), | |
| 562 | .mulwrap => try self.airBinOp(inst), | |
| 563 | 579 | .mul_sat => try self.airMulSat(inst), |
| 564 | 580 | .rem => try self.airRem(inst), |
| 565 | 581 | .mod => try self.airMod(inst), |
| 566 | .shl, .shl_exact => try self.airBinOp(inst), | |
| 567 | 582 | .shl_sat => try self.airShlSat(inst), |
| 568 | .min => try self.airMinMax(inst), | |
| 569 | .max => try self.airMinMax(inst), | |
| 570 | 583 | .slice => try self.airSlice(inst), |
| 571 | 584 | |
| 572 | 585 | .sqrt, |
| ... | ... | @@ -602,13 +615,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 602 | 615 | .cmp_vector => try self.airCmpVector(inst), |
| 603 | 616 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 604 | 617 | |
| 605 | .bool_and => try self.airBinOp(inst), | |
| 606 | .bool_or => try self.airBinOp(inst), | |
| 607 | .bit_and => try self.airBinOp(inst), | |
| 608 | .bit_or => try self.airBinOp(inst), | |
| 609 | .xor => try self.airBinOp(inst), | |
| 610 | .shr, .shr_exact => try self.airBinOp(inst), | |
| 611 | ||
| 612 | 618 | .alloc => try self.airAlloc(inst), |
| 613 | 619 | .ret_ptr => try self.airRetPtr(inst), |
| 614 | 620 | .arg => try self.airArg(inst), |
| ... | ... | @@ -1260,7 +1266,7 @@ fn minMax( |
| 1260 | 1266 | // register. |
| 1261 | 1267 | assert(lhs_reg != rhs_reg); // see note above |
| 1262 | 1268 | |
| 1263 | _ = try self.binOpRegister(.cmp, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty); | |
| 1269 | _ = try self.binOpRegister(.cmp, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty, null); | |
| 1264 | 1270 | |
| 1265 | 1271 | const cond_choose_lhs: Condition = switch (tag) { |
| 1266 | 1272 | .max => switch (int_info.signedness) { |
| ... | ... | @@ -1340,15 +1346,40 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1340 | 1346 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1341 | 1347 | } |
| 1342 | 1348 | |
| 1343 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 1344 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 1349 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1345 | 1350 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1346 | 1351 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1347 | 1352 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1348 | 1353 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1349 | 1354 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1350 | 1355 | |
| 1351 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1356 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1357 | .dead | |
| 1358 | else | |
| 1359 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 1360 | .lhs = bin_op.lhs, | |
| 1361 | .rhs = bin_op.rhs, | |
| 1362 | .inst = inst, | |
| 1363 | }); | |
| 1364 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1365 | } | |
| 1366 | ||
| 1367 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1368 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1369 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 1370 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1371 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1372 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1373 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1374 | ||
| 1375 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 1376 | .dead | |
| 1377 | else | |
| 1378 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 1379 | .lhs = bin_op.lhs, | |
| 1380 | .rhs = bin_op.rhs, | |
| 1381 | .inst = inst, | |
| 1382 | }); | |
| 1352 | 1383 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1353 | 1384 | } |
| 1354 | 1385 | |
| ... | ... | @@ -1402,7 +1433,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1402 | 1433 | .sub_with_overflow => .sub, |
| 1403 | 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 | 1437 | const dest_reg = dest.register; |
| 1407 | 1438 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1408 | 1439 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -1415,7 +1446,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1415 | 1446 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 1416 | 1447 | |
| 1417 | 1448 | // cmp dest, truncated |
| 1418 | _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize); | |
| 1449 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | |
| 1419 | 1450 | |
| 1420 | 1451 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1421 | 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 | 1479 | |
| 1449 | 1480 | const dest = blk: { |
| 1450 | 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 | 1483 | } else if (lhs_immediate_ok) { |
| 1453 | 1484 | // swap lhs and rhs |
| 1454 | break :blk try self.binOpImmediate(mir_tag, null, rhs, lhs, rhs_ty, true); | |
| 1485 | break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null); | |
| 1455 | 1486 | } else { |
| 1456 | break :blk try self.binOpRegister(mir_tag, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 1487 | break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 1457 | 1488 | } |
| 1458 | 1489 | }; |
| 1459 | 1490 | |
| ... | ... | @@ -1507,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1507 | 1538 | .unsigned => .mul, |
| 1508 | 1539 | }; |
| 1509 | 1540 | |
| 1510 | const dest = try self.binOpRegister(base_tag, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 1541 | const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 1511 | 1542 | const dest_reg = dest.register; |
| 1512 | 1543 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1513 | 1544 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -1520,7 +1551,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1520 | 1551 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 1521 | 1552 | |
| 1522 | 1553 | // cmp dest, truncated |
| 1523 | _ = try self.binOp(.cmp_eq, null, dest, .{ .register = truncated_reg }, Type.usize, Type.usize); | |
| 1554 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | |
| 1524 | 1555 | |
| 1525 | 1556 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1526 | 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 | 1625 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1595 | 1626 | |
| 1596 | 1627 | // cmp truncated, rdlo |
| 1597 | _ = try self.binOp(.cmp_eq, null, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize); | |
| 1628 | _ = try self.binOp(.cmp_eq, .{ .register = truncated_reg }, .{ .register = rdlo }, Type.usize, Type.usize, null); | |
| 1598 | 1629 | |
| 1599 | 1630 | // mov rdlo, #0 |
| 1600 | 1631 | _ = try self.addInst(.{ |
| ... | ... | @@ -1618,7 +1649,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1618 | 1649 | }); |
| 1619 | 1650 | |
| 1620 | 1651 | // cmp rdhi, #0 |
| 1621 | _ = try self.binOp(.cmp_eq, null, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize); | |
| 1652 | _ = try self.binOp(.cmp_eq, .{ .register = rdhi }, .{ .immediate = 0 }, Type.usize, Type.usize, null); | |
| 1622 | 1653 | |
| 1623 | 1654 | // movne rdlo, #1 |
| 1624 | 1655 | _ = try self.addInst(.{ |
| ... | ... | @@ -1677,16 +1708,16 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1677 | 1708 | self.compare_flags_inst = null; |
| 1678 | 1709 | |
| 1679 | 1710 | // lsl dest, lhs, rhs |
| 1680 | const dest = try self.binOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); | |
| 1711 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); | |
| 1681 | 1712 | const dest_reg = dest.register; |
| 1682 | 1713 | const dest_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1683 | 1714 | defer self.register_manager.unlockReg(dest_lock); |
| 1684 | 1715 | |
| 1685 | 1716 | // asr/lsr reconstructed, dest, rhs |
| 1686 | const reconstructed = try self.binOp(.shr, null, dest, rhs, lhs_ty, rhs_ty); | |
| 1717 | const reconstructed = try self.binOp(.shr, dest, rhs, lhs_ty, rhs_ty, null); | |
| 1687 | 1718 | |
| 1688 | 1719 | // cmp lhs, reconstructed |
| 1689 | _ = try self.binOp(.cmp_eq, null, lhs, reconstructed, lhs_ty, lhs_ty); | |
| 1720 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); | |
| 1690 | 1721 | |
| 1691 | 1722 | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 1692 | 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 | 2062 | }, |
| 2032 | 2063 | else => { |
| 2033 | 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 | 2066 | try self.load(dest, addr, slice_ptr_field_type); |
| 2036 | 2067 | |
| 2037 | 2068 | break :result dest; |
| ... | ... | @@ -2051,7 +2082,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2051 | 2082 | |
| 2052 | 2083 | const slice_ty = self.air.typeOf(extra.lhs); |
| 2053 | 2084 | |
| 2054 | const addr = try self.binOp(.ptr_add, null, base_mcv, index_mcv, slice_ty, Type.usize); | |
| 2085 | const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null); | |
| 2055 | 2086 | break :result addr; |
| 2056 | 2087 | }; |
| 2057 | 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 | 2110 | |
| 2080 | 2111 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2081 | 2112 | |
| 2082 | const addr = try self.binOp(.ptr_add, null, ptr_mcv, index_mcv, ptr_ty, Type.usize); | |
| 2113 | const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null); | |
| 2083 | 2114 | break :result addr; |
| 2084 | 2115 | }; |
| 2085 | 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 | 2442 | |
| 2412 | 2443 | const dest = try self.binOp( |
| 2413 | 2444 | .add, |
| 2414 | null, | |
| 2415 | 2445 | .{ .register = addr_reg }, |
| 2416 | 2446 | .{ .register = offset_reg }, |
| 2417 | 2447 | Type.usize, |
| 2418 | 2448 | Type.usize, |
| 2449 | null, | |
| 2419 | 2450 | ); |
| 2420 | 2451 | |
| 2421 | 2452 | break :result dest; |
| ... | ... | @@ -2514,11 +2545,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2514 | 2545 | fn binOpRegister( |
| 2515 | 2546 | self: *Self, |
| 2516 | 2547 | mir_tag: Mir.Inst.Tag, |
| 2517 | maybe_inst: ?Air.Inst.Index, | |
| 2518 | 2548 | lhs: MCValue, |
| 2519 | 2549 | rhs: MCValue, |
| 2520 | 2550 | lhs_ty: Type, |
| 2521 | 2551 | rhs_ty: Type, |
| 2552 | metadata: ?BinOpMetadata, | |
| 2522 | 2553 | ) !MCValue { |
| 2523 | 2554 | const lhs_is_register = lhs == .register; |
| 2524 | 2555 | const rhs_is_register = rhs == .register; |
| ... | ... | @@ -2532,9 +2563,8 @@ fn binOpRegister( |
| 2532 | 2563 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 2533 | 2564 | |
| 2534 | 2565 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| 2535 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 2536 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 2537 | break :inst Air.refToIndex(bin_op.lhs).?; | |
| 2566 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 2567 | break :inst Air.refToIndex(md.lhs).?; | |
| 2538 | 2568 | } else null; |
| 2539 | 2569 | |
| 2540 | 2570 | const reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -2547,9 +2577,8 @@ fn binOpRegister( |
| 2547 | 2577 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 2548 | 2578 | |
| 2549 | 2579 | const rhs_reg = if (rhs_is_register) rhs.register else blk: { |
| 2550 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 2551 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 2552 | break :inst Air.refToIndex(bin_op.rhs).?; | |
| 2580 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 2581 | break :inst Air.refToIndex(md.rhs).?; | |
| 2553 | 2582 | } else null; |
| 2554 | 2583 | |
| 2555 | 2584 | const reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -2563,15 +2592,13 @@ fn binOpRegister( |
| 2563 | 2592 | |
| 2564 | 2593 | const dest_reg = switch (mir_tag) { |
| 2565 | 2594 | .cmp => .r0, // cmp has no destination regardless |
| 2566 | else => if (maybe_inst) |inst| blk: { | |
| 2567 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 2568 | ||
| 2569 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | |
| 2595 | else => if (metadata) |md| blk: { | |
| 2596 | if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) { | |
| 2570 | 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 | 2599 | break :blk rhs_reg; |
| 2573 | 2600 | } else { |
| 2574 | break :blk try self.register_manager.allocReg(inst); | |
| 2601 | break :blk try self.register_manager.allocReg(md.inst); | |
| 2575 | 2602 | } |
| 2576 | 2603 | } else try self.register_manager.allocReg(null), |
| 2577 | 2604 | }; |
| ... | ... | @@ -2634,11 +2661,11 @@ fn binOpRegister( |
| 2634 | 2661 | fn binOpImmediate( |
| 2635 | 2662 | self: *Self, |
| 2636 | 2663 | mir_tag: Mir.Inst.Tag, |
| 2637 | maybe_inst: ?Air.Inst.Index, | |
| 2638 | 2664 | lhs: MCValue, |
| 2639 | 2665 | rhs: MCValue, |
| 2640 | 2666 | lhs_ty: Type, |
| 2641 | 2667 | lhs_and_rhs_swapped: bool, |
| 2668 | metadata: ?BinOpMetadata, | |
| 2642 | 2669 | ) !MCValue { |
| 2643 | 2670 | const lhs_is_register = lhs == .register; |
| 2644 | 2671 | |
| ... | ... | @@ -2651,10 +2678,9 @@ fn binOpImmediate( |
| 2651 | 2678 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 2652 | 2679 | |
| 2653 | 2680 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| 2654 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 2655 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 2681 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 2656 | 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 | 2685 | } else null; |
| 2660 | 2686 | |
| ... | ... | @@ -2669,18 +2695,16 @@ fn binOpImmediate( |
| 2669 | 2695 | |
| 2670 | 2696 | const dest_reg = switch (mir_tag) { |
| 2671 | 2697 | .cmp => .r0, // cmp has no destination reg |
| 2672 | else => if (maybe_inst) |inst| blk: { | |
| 2673 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 2674 | ||
| 2698 | else => if (metadata) |md| blk: { | |
| 2675 | 2699 | if (lhs_is_register and self.reuseOperand( |
| 2676 | inst, | |
| 2677 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, | |
| 2700 | md.inst, | |
| 2701 | if (lhs_and_rhs_swapped) md.rhs else md.lhs, | |
| 2678 | 2702 | if (lhs_and_rhs_swapped) 1 else 0, |
| 2679 | 2703 | lhs, |
| 2680 | 2704 | )) { |
| 2681 | 2705 | break :blk lhs_reg; |
| 2682 | 2706 | } else { |
| 2683 | break :blk try self.register_manager.allocReg(inst); | |
| 2707 | break :blk try self.register_manager.allocReg(md.inst); | |
| 2684 | 2708 | } |
| 2685 | 2709 | } else try self.register_manager.allocReg(null), |
| 2686 | 2710 | }; |
| ... | ... | @@ -2720,6 +2744,12 @@ fn binOpImmediate( |
| 2720 | 2744 | return MCValue{ .register = dest_reg }; |
| 2721 | 2745 | } |
| 2722 | 2746 | |
| 2747 | const BinOpMetadata = struct { | |
| 2748 | inst: Air.Inst.Index, | |
| 2749 | lhs: Air.Inst.Ref, | |
| 2750 | rhs: Air.Inst.Ref, | |
| 2751 | }; | |
| 2752 | ||
| 2723 | 2753 | /// For all your binary operation needs, this function will generate |
| 2724 | 2754 | /// the corresponding Mir instruction(s). Returns the location of the |
| 2725 | 2755 | /// result. |
| ... | ... | @@ -2735,11 +2765,11 @@ fn binOpImmediate( |
| 2735 | 2765 | fn binOp( |
| 2736 | 2766 | self: *Self, |
| 2737 | 2767 | tag: Air.Inst.Tag, |
| 2738 | maybe_inst: ?Air.Inst.Index, | |
| 2739 | 2768 | lhs: MCValue, |
| 2740 | 2769 | rhs: MCValue, |
| 2741 | 2770 | lhs_ty: Type, |
| 2742 | 2771 | rhs_ty: Type, |
| 2772 | metadata: ?BinOpMetadata, | |
| 2743 | 2773 | ) InnerError!MCValue { |
| 2744 | 2774 | switch (tag) { |
| 2745 | 2775 | .add, |
| ... | ... | @@ -2780,12 +2810,12 @@ fn binOp( |
| 2780 | 2810 | }; |
| 2781 | 2811 | |
| 2782 | 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 | 2814 | } else if (lhs_immediate_ok) { |
| 2785 | 2815 | // swap lhs and rhs |
| 2786 | return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true); | |
| 2816 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | |
| 2787 | 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 | 2820 | } else { |
| 2791 | 2821 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -2806,7 +2836,7 @@ fn binOp( |
| 2806 | 2836 | // TODO add optimisations for multiplication |
| 2807 | 2837 | // with immediates, for example a * 2 can be |
| 2808 | 2838 | // lowered to a << 1 |
| 2809 | return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 2839 | return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 2810 | 2840 | } else { |
| 2811 | 2841 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 2812 | 2842 | } |
| ... | ... | @@ -2826,7 +2856,7 @@ fn binOp( |
| 2826 | 2856 | }; |
| 2827 | 2857 | |
| 2828 | 2858 | // Generate an add/sub/mul |
| 2829 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 2859 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 2830 | 2860 | |
| 2831 | 2861 | // Truncate if necessary |
| 2832 | 2862 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -2869,12 +2899,12 @@ fn binOp( |
| 2869 | 2899 | }; |
| 2870 | 2900 | |
| 2871 | 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 | 2903 | } else if (lhs_immediate_ok) { |
| 2874 | 2904 | // swap lhs and rhs |
| 2875 | return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true); | |
| 2905 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | |
| 2876 | 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 | 2909 | } else { |
| 2880 | 2910 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -2903,9 +2933,9 @@ fn binOp( |
| 2903 | 2933 | }; |
| 2904 | 2934 | |
| 2905 | 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 | 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 | 2940 | } else { |
| 2911 | 2941 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| ... | ... | @@ -2924,7 +2954,7 @@ fn binOp( |
| 2924 | 2954 | }; |
| 2925 | 2955 | |
| 2926 | 2956 | // Generate a shl_exact/shr_exact |
| 2927 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 2957 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 2928 | 2958 | |
| 2929 | 2959 | // Truncate if necessary |
| 2930 | 2960 | switch (tag) { |
| ... | ... | @@ -2964,12 +2994,12 @@ fn binOp( |
| 2964 | 2994 | }; |
| 2965 | 2995 | |
| 2966 | 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 | 2998 | } else if (lhs_immediate_ok) { |
| 2969 | 2999 | // swap lhs and rhs |
| 2970 | return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true); | |
| 3000 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | |
| 2971 | 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 | 3005 | else => unreachable, |
| ... | ... | @@ -2994,12 +3024,12 @@ fn binOp( |
| 2994 | 3024 | else => unreachable, |
| 2995 | 3025 | }; |
| 2996 | 3026 | |
| 2997 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 3027 | return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 2998 | 3028 | } else { |
| 2999 | 3029 | // convert the offset into a byte offset by |
| 3000 | 3030 | // multiplying it with elem_size |
| 3001 | const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize); | |
| 3002 | const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize); | |
| 3031 | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); | |
| 3032 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); | |
| 3003 | 3033 | return addr; |
| 3004 | 3034 | } |
| 3005 | 3035 | }, |
| ... | ... | @@ -3575,7 +3605,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3575 | 3605 | try self.spillCompareFlagsIfOccupied(); |
| 3576 | 3606 | self.compare_flags_inst = inst; |
| 3577 | 3607 | |
| 3578 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); | |
| 3608 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ | |
| 3609 | .lhs = bin_op.lhs, | |
| 3610 | .rhs = bin_op.rhs, | |
| 3611 | .inst = inst, | |
| 3612 | }); | |
| 3579 | 3613 | |
| 3580 | 3614 | break :result switch (int_info.signedness) { |
| 3581 | 3615 | .signed => MCValue{ .compare_flags_signed = op }, |
| ... | ... | @@ -3865,7 +3899,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3865 | 3899 | } |
| 3866 | 3900 | |
| 3867 | 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 | 3903 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 3870 | 3904 | } |
| 3871 | 3905 |
src/arch/riscv64/CodeGen.zig+19-4| ... | ... | @@ -481,10 +481,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 481 | 481 | |
| 482 | 482 | switch (air_tags[inst]) { |
| 483 | 483 | // zig fmt: off |
| 484 | .add, .ptr_add => try self.airBinOp(inst), | |
| 484 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), | |
| 485 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | |
| 486 | ||
| 487 | .add => try self.airBinOp(inst, .add), | |
| 488 | .sub => try self.airBinOp(inst, .sub), | |
| 489 | ||
| 485 | 490 | .addwrap => try self.airAddWrap(inst), |
| 486 | 491 | .add_sat => try self.airAddSat(inst), |
| 487 | .sub, .ptr_sub => try self.airBinOp(inst), | |
| 488 | 492 | .subwrap => try self.airSubWrap(inst), |
| 489 | 493 | .sub_sat => try self.airSubSat(inst), |
| 490 | 494 | .mul => try self.airMul(inst), |
| ... | ... | @@ -1091,8 +1095,7 @@ fn binOp( |
| 1091 | 1095 | } |
| 1092 | 1096 | } |
| 1093 | 1097 | |
| 1094 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 1095 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 1098 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1096 | 1099 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1097 | 1100 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1098 | 1101 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1103,6 +1106,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1103 | 1106 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1104 | 1107 | } |
| 1105 | 1108 | |
| 1109 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1110 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1111 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 1112 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1113 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1114 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1115 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1116 | ||
| 1117 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1118 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1119 | } | |
| 1120 | ||
| 1106 | 1121 | fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 1107 | 1122 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1108 | 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 | 483 | |
| 484 | 484 | switch (air_tags[inst]) { |
| 485 | 485 | // zig fmt: off |
| 486 | .add, .ptr_add => try self.airBinOp(inst), | |
| 486 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), | |
| 487 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | |
| 488 | ||
| 489 | .add => try self.airBinOp(inst, .add), | |
| 487 | 490 | .addwrap => @panic("TODO try self.airAddWrap(inst)"), |
| 488 | 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 | 493 | .subwrap => @panic("TODO try self.airSubWrap(inst)"), |
| 491 | 494 | .sub_sat => @panic("TODO try self.airSubSat(inst)"), |
| 492 | 495 | .mul => @panic("TODO try self.airMul(inst)"), |
| ... | ... | @@ -827,18 +830,38 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 827 | 830 | return self.finishAir(inst, mcv, .{ .none, .none, .none }); |
| 828 | 831 | } |
| 829 | 832 | |
| 830 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 831 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 833 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 832 | 834 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 833 | 835 | const lhs = try self.resolveInst(bin_op.lhs); |
| 834 | 836 | const rhs = try self.resolveInst(bin_op.rhs); |
| 835 | 837 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 836 | 838 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 839 | const result: MCValue = if (self.liveness.isUnused(inst)) | |
| 840 | .dead | |
| 841 | else | |
| 842 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 843 | .lhs = bin_op.lhs, | |
| 844 | .rhs = bin_op.rhs, | |
| 845 | .inst = inst, | |
| 846 | }); | |
| 847 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 848 | } | |
| 837 | 849 | |
| 850 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 851 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 852 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 853 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 854 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 855 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 856 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 838 | 857 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 839 | 858 | .dead |
| 840 | 859 | else |
| 841 | try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 860 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | |
| 861 | .lhs = bin_op.lhs, | |
| 862 | .rhs = bin_op.rhs, | |
| 863 | .inst = inst, | |
| 864 | }); | |
| 842 | 865 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 843 | 866 | } |
| 844 | 867 | |
| ... | ... | @@ -1030,7 +1053,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1030 | 1053 | |
| 1031 | 1054 | var int_buffer: Type.Payload.Bits = undefined; |
| 1032 | 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 | 1057 | .Enum => lhs_ty.intTagType(&int_buffer), |
| 1035 | 1058 | .Int => lhs_ty, |
| 1036 | 1059 | .Bool => Type.initTag(.u1), |
| ... | ... | @@ -1053,7 +1076,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1053 | 1076 | |
| 1054 | 1077 | const int_info = int_ty.intInfo(self.target.*); |
| 1055 | 1078 | if (int_info.bits <= 64) { |
| 1056 | _ = try self.binOp(.cmp_eq, inst, lhs, rhs, int_ty, int_ty); | |
| 1079 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ | |
| 1080 | .lhs = bin_op.lhs, | |
| 1081 | .rhs = bin_op.rhs, | |
| 1082 | .inst = inst, | |
| 1083 | }); | |
| 1057 | 1084 | |
| 1058 | 1085 | try self.spillCompareFlagsIfOccupied(); |
| 1059 | 1086 | self.compare_flags_inst = inst; |
| ... | ... | @@ -1426,7 +1453,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1426 | 1453 | // TODO skip the ptr_add emission entirely and use native addressing modes |
| 1427 | 1454 | // i.e sllx/mulx then R+R or scale immediate then R+I |
| 1428 | 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 | 1457 | try self.load(dest, addr, slice_ptr_field_type); |
| 1431 | 1458 | |
| 1432 | 1459 | break :result dest; |
| ... | ... | @@ -1595,6 +1622,12 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1595 | 1622 | return MCValue{ .stack_offset = stack_offset }; |
| 1596 | 1623 | } |
| 1597 | 1624 | |
| 1625 | const BinOpMetadata = struct { | |
| 1626 | inst: Air.Inst.Index, | |
| 1627 | lhs: Air.Inst.Ref, | |
| 1628 | rhs: Air.Inst.Ref, | |
| 1629 | }; | |
| 1630 | ||
| 1598 | 1631 | /// For all your binary operation needs, this function will generate |
| 1599 | 1632 | /// the corresponding Mir instruction(s). Returns the location of the |
| 1600 | 1633 | /// result. |
| ... | ... | @@ -1610,11 +1643,11 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1610 | 1643 | fn binOp( |
| 1611 | 1644 | self: *Self, |
| 1612 | 1645 | tag: Air.Inst.Tag, |
| 1613 | maybe_inst: ?Air.Inst.Index, | |
| 1614 | 1646 | lhs: MCValue, |
| 1615 | 1647 | rhs: MCValue, |
| 1616 | 1648 | lhs_ty: Type, |
| 1617 | 1649 | rhs_ty: Type, |
| 1650 | metadata: ?BinOpMetadata, | |
| 1618 | 1651 | ) InnerError!MCValue { |
| 1619 | 1652 | const mod = self.bin_file.options.module.?; |
| 1620 | 1653 | switch (tag) { |
| ... | ... | @@ -1649,13 +1682,13 @@ fn binOp( |
| 1649 | 1682 | }; |
| 1650 | 1683 | |
| 1651 | 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 | 1686 | } else if (lhs_immediate_ok) { |
| 1654 | 1687 | // swap lhs and rhs |
| 1655 | return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true); | |
| 1688 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | |
| 1656 | 1689 | } else { |
| 1657 | 1690 | // TODO convert large immediates to register before adding |
| 1658 | return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1691 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1659 | 1692 | } |
| 1660 | 1693 | } else { |
| 1661 | 1694 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1683,10 +1716,10 @@ fn binOp( |
| 1683 | 1716 | // If it's a power of two immediate then we emit an shl instead |
| 1684 | 1717 | // TODO add similar checks for LHS |
| 1685 | 1718 | if (new_rhs == .immediate and math.isPowerOfTwo(new_rhs.immediate)) { |
| 1686 | return try self.binOp(.shl, maybe_inst, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize); | |
| 1719 | return try self.binOp(.shl, new_lhs, .{ .immediate = math.log2(new_rhs.immediate) }, new_lhs_ty, Type.usize, metadata); | |
| 1687 | 1720 | } |
| 1688 | 1721 | |
| 1689 | return try self.binOpRegister(.mulx, maybe_inst, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty); | |
| 1722 | return try self.binOpRegister(.mulx, new_lhs, new_rhs, new_lhs_ty, new_rhs_ty, metadata); | |
| 1690 | 1723 | } else { |
| 1691 | 1724 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1692 | 1725 | } |
| ... | ... | @@ -1711,13 +1744,13 @@ fn binOp( |
| 1711 | 1744 | else => unreachable, |
| 1712 | 1745 | }; |
| 1713 | 1746 | |
| 1714 | return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1747 | return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1715 | 1748 | } else { |
| 1716 | 1749 | // convert the offset into a byte offset by |
| 1717 | 1750 | // multiplying it with elem_size |
| 1718 | 1751 | |
| 1719 | const offset = try self.binOp(.mul, null, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize); | |
| 1720 | const addr = try self.binOp(tag, null, lhs, offset, Type.initTag(.manyptr_u8), Type.usize); | |
| 1752 | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); | |
| 1753 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); | |
| 1721 | 1754 | return addr; |
| 1722 | 1755 | } |
| 1723 | 1756 | }, |
| ... | ... | @@ -1732,7 +1765,7 @@ fn binOp( |
| 1732 | 1765 | }; |
| 1733 | 1766 | |
| 1734 | 1767 | // Generate a shl_exact/shr_exact |
| 1735 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1768 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | |
| 1736 | 1769 | |
| 1737 | 1770 | // Truncate if necessary |
| 1738 | 1771 | switch (tag) { |
| ... | ... | @@ -1768,9 +1801,9 @@ fn binOp( |
| 1768 | 1801 | }; |
| 1769 | 1802 | |
| 1770 | 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 | 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 | 1808 | } else { |
| 1776 | 1809 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1792,18 +1825,17 @@ fn binOp( |
| 1792 | 1825 | /// op dest, lhs, #rhs_imm |
| 1793 | 1826 | /// |
| 1794 | 1827 | /// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to |
| 1795 | /// rhs and vice versa. This parameter is only used when maybe_inst != | |
| 1796 | /// null. | |
| 1828 | /// rhs and vice versa. This parameter is only used when metadata != null. | |
| 1797 | 1829 | /// |
| 1798 | 1830 | /// Asserts that generating an instruction of that form is possible. |
| 1799 | 1831 | fn binOpImmediate( |
| 1800 | 1832 | self: *Self, |
| 1801 | 1833 | mir_tag: Mir.Inst.Tag, |
| 1802 | maybe_inst: ?Air.Inst.Index, | |
| 1803 | 1834 | lhs: MCValue, |
| 1804 | 1835 | rhs: MCValue, |
| 1805 | 1836 | lhs_ty: Type, |
| 1806 | 1837 | lhs_and_rhs_swapped: bool, |
| 1838 | metadata: ?BinOpMetadata, | |
| 1807 | 1839 | ) !MCValue { |
| 1808 | 1840 | const lhs_is_register = lhs == .register; |
| 1809 | 1841 | |
| ... | ... | @@ -1816,10 +1848,9 @@ fn binOpImmediate( |
| 1816 | 1848 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1817 | 1849 | |
| 1818 | 1850 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| 1819 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 1820 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1851 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1821 | 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 | 1855 | } else null; |
| 1825 | 1856 | |
| ... | ... | @@ -1833,18 +1864,16 @@ fn binOpImmediate( |
| 1833 | 1864 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1834 | 1865 | |
| 1835 | 1866 | const dest_reg = switch (mir_tag) { |
| 1836 | else => if (maybe_inst) |inst| blk: { | |
| 1837 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1838 | ||
| 1867 | else => if (metadata) |md| blk: { | |
| 1839 | 1868 | if (lhs_is_register and self.reuseOperand( |
| 1840 | inst, | |
| 1841 | if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs, | |
| 1869 | md.inst, | |
| 1870 | if (lhs_and_rhs_swapped) md.rhs else md.lhs, | |
| 1842 | 1871 | if (lhs_and_rhs_swapped) 1 else 0, |
| 1843 | 1872 | lhs, |
| 1844 | 1873 | )) { |
| 1845 | 1874 | break :blk lhs_reg; |
| 1846 | 1875 | } else { |
| 1847 | break :blk try self.register_manager.allocReg(inst); | |
| 1876 | break :blk try self.register_manager.allocReg(md.inst); | |
| 1848 | 1877 | } |
| 1849 | 1878 | } else blk: { |
| 1850 | 1879 | break :blk try self.register_manager.allocReg(null); |
| ... | ... | @@ -1896,11 +1925,11 @@ fn binOpImmediate( |
| 1896 | 1925 | fn binOpRegister( |
| 1897 | 1926 | self: *Self, |
| 1898 | 1927 | mir_tag: Mir.Inst.Tag, |
| 1899 | maybe_inst: ?Air.Inst.Index, | |
| 1900 | 1928 | lhs: MCValue, |
| 1901 | 1929 | rhs: MCValue, |
| 1902 | 1930 | lhs_ty: Type, |
| 1903 | 1931 | rhs_ty: Type, |
| 1932 | metadata: ?BinOpMetadata, | |
| 1904 | 1933 | ) !MCValue { |
| 1905 | 1934 | const lhs_is_register = lhs == .register; |
| 1906 | 1935 | const rhs_is_register = rhs == .register; |
| ... | ... | @@ -1920,9 +1949,8 @@ fn binOpRegister( |
| 1920 | 1949 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1921 | 1950 | |
| 1922 | 1951 | const lhs_reg = if (lhs_is_register) lhs.register else blk: { |
| 1923 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 1924 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1925 | break :inst Air.refToIndex(bin_op.lhs).?; | |
| 1952 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1953 | break :inst Air.refToIndex(md.lhs).?; | |
| 1926 | 1954 | } else null; |
| 1927 | 1955 | |
| 1928 | 1956 | const reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -1934,9 +1962,8 @@ fn binOpRegister( |
| 1934 | 1962 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1935 | 1963 | |
| 1936 | 1964 | const rhs_reg = if (rhs_is_register) rhs.register else blk: { |
| 1937 | const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: { | |
| 1938 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1939 | break :inst Air.refToIndex(bin_op.rhs).?; | |
| 1965 | const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: { | |
| 1966 | break :inst Air.refToIndex(md.rhs).?; | |
| 1940 | 1967 | } else null; |
| 1941 | 1968 | |
| 1942 | 1969 | const reg = try self.register_manager.allocReg(track_inst); |
| ... | ... | @@ -1948,15 +1975,13 @@ fn binOpRegister( |
| 1948 | 1975 | defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 1949 | 1976 | |
| 1950 | 1977 | const dest_reg = switch (mir_tag) { |
| 1951 | else => if (maybe_inst) |inst| blk: { | |
| 1952 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 1953 | ||
| 1954 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | |
| 1978 | else => if (metadata) |md| blk: { | |
| 1979 | if (lhs_is_register and self.reuseOperand(md.inst, md.lhs, 0, lhs)) { | |
| 1955 | 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 | 1982 | break :blk rhs_reg; |
| 1958 | 1983 | } else { |
| 1959 | break :blk try self.register_manager.allocReg(inst); | |
| 1984 | break :blk try self.register_manager.allocReg(md.inst); | |
| 1960 | 1985 | } |
| 1961 | 1986 | } else blk: { |
| 1962 | 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 | 3094 | |
| 3070 | 3095 | const dest = try self.binOp( |
| 3071 | 3096 | .add, |
| 3072 | null, | |
| 3073 | 3097 | .{ .register = addr_reg }, |
| 3074 | 3098 | .{ .register = offset_reg }, |
| 3075 | 3099 | Type.usize, |
| 3076 | 3100 | Type.usize, |
| 3101 | null, | |
| 3077 | 3102 | ); |
| 3078 | 3103 | |
| 3079 | 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 | 3397 | |
| 3398 | 3398 | fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 3399 | 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 | 3402 | const ptr = try self.resolveInst(bin_op.lhs); |
| 3402 | 3403 | const offset = try self.resolveInst(bin_op.rhs); |
| 3403 | 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 | 574 | |
| 575 | 575 | switch (air_tags[inst]) { |
| 576 | 576 | // zig fmt: off |
| 577 | .add => try self.airBinOp(inst), | |
| 578 | .addwrap => try self.airBinOp(inst), | |
| 579 | .add_sat => try self.airAddSat(inst), | |
| 580 | .sub => try self.airBinOp(inst), | |
| 581 | .subwrap => try self.airBinOp(inst), | |
| 582 | .sub_sat => try self.airSubSat(inst), | |
| 577 | .add => try self.airBinOp(inst, .add), | |
| 578 | .addwrap => try self.airBinOp(inst, .addwrap), | |
| 579 | .sub => try self.airBinOp(inst, .sub), | |
| 580 | .subwrap => try self.airBinOp(inst, .subwrap), | |
| 581 | .bool_and => try self.airBinOp(inst, .bool_and), | |
| 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 | 593 | .mul => try self.airMulDivBinOp(inst), |
| 584 | 594 | .mulwrap => try self.airMulDivBinOp(inst), |
| 585 | .mul_sat => try self.airMulSat(inst), | |
| 586 | 595 | .rem => try self.airMulDivBinOp(inst), |
| 587 | 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 | 601 | .shl_sat => try self.airShlSat(inst), |
| 590 | 602 | .min => try self.airMin(inst), |
| 591 | 603 | .max => try self.airMax(inst), |
| 592 | .ptr_add => try self.airBinOp(inst), | |
| 593 | .ptr_sub => try self.airBinOp(inst), | |
| 594 | 604 | .slice => try self.airSlice(inst), |
| 595 | 605 | |
| 596 | 606 | .sqrt, |
| ... | ... | @@ -626,13 +636,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 626 | 636 | .cmp_vector => try self.airCmpVector(inst), |
| 627 | 637 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 628 | 638 | |
| 629 | .bool_and => try self.airBinOp(inst), | |
| 630 | .bool_or => try self.airBinOp(inst), | |
| 631 | .bit_and => try self.airBinOp(inst), | |
| 632 | .bit_or => try self.airBinOp(inst), | |
| 633 | .xor => try self.airBinOp(inst), | |
| 634 | .shr, .shr_exact => try self.airShlShrBinOp(inst), | |
| 635 | ||
| 636 | 639 | .alloc => try self.airAlloc(inst), |
| 637 | 640 | .ret_ptr => try self.airRetPtr(inst), |
| 638 | 641 | .arg => try self.airArg(inst), |
| ... | ... | @@ -1231,21 +1234,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1231 | 1234 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1232 | 1235 | } |
| 1233 | 1236 | |
| 1234 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 1237 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1235 | 1238 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1236 | 1239 | |
| 1237 | 1240 | if (self.liveness.isUnused(inst)) { |
| 1238 | 1241 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1239 | 1242 | } |
| 1240 | 1243 | |
| 1241 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 1242 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1243 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1244 | const lhs_ty = self.air.typeOf(bin_op.lhs); | |
| 1245 | const rhs_ty = self.air.typeOf(bin_op.rhs); | |
| 1244 | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | |
| 1245 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1246 | } | |
| 1246 | 1247 | |
| 1247 | const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | |
| 1248 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | |
| 1249 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1250 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 1251 | ||
| 1252 | if (self.liveness.isUnused(inst)) { | |
| 1253 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | |
| 1254 | } | |
| 1248 | 1255 | |
| 1256 | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | |
| 1249 | 1257 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1250 | 1258 | } |
| 1251 | 1259 | |
| ... | ... | @@ -1316,13 +1324,12 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1316 | 1324 | try self.spillRegisters(1, .{.rcx}); |
| 1317 | 1325 | } |
| 1318 | 1326 | |
| 1319 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1320 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1321 | ||
| 1322 | 1327 | const partial: MCValue = switch (tag) { |
| 1323 | .add_with_overflow => try self.genBinOp(.add, null, lhs, rhs, ty, ty), | |
| 1324 | .sub_with_overflow => try self.genBinOp(.sub, null, lhs, rhs, ty, ty), | |
| 1328 | .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs), | |
| 1329 | .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs), | |
| 1325 | 1330 | .shl_with_overflow => blk: { |
| 1331 | const lhs = try self.resolveInst(bin_op.lhs); | |
| 1332 | const rhs = try self.resolveInst(bin_op.rhs); | |
| 1326 | 1333 | const shift_ty = self.air.typeOf(bin_op.rhs); |
| 1327 | 1334 | break :blk try self.genShiftBinOp(.shl, null, lhs, rhs, ty, shift_ty); |
| 1328 | 1335 | }, |
| ... | ... | @@ -3310,13 +3317,15 @@ fn genMulDivBinOp( |
| 3310 | 3317 | /// Result is always a register. |
| 3311 | 3318 | fn genBinOp( |
| 3312 | 3319 | self: *Self, |
| 3313 | tag: Air.Inst.Tag, | |
| 3314 | 3320 | maybe_inst: ?Air.Inst.Index, |
| 3315 | lhs: MCValue, | |
| 3316 | rhs: MCValue, | |
| 3317 | lhs_ty: Type, | |
| 3318 | rhs_ty: Type, | |
| 3321 | tag: Air.Inst.Tag, | |
| 3322 | lhs_air: Air.Inst.Ref, | |
| 3323 | rhs_air: Air.Inst.Ref, | |
| 3319 | 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 | 3329 | if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) { |
| 3321 | 3330 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 3322 | 3331 | } |
| ... | ... | @@ -3352,11 +3361,10 @@ fn genBinOp( |
| 3352 | 3361 | var flipped: bool = false; |
| 3353 | 3362 | const dst_mcv: MCValue = blk: { |
| 3354 | 3363 | if (maybe_inst) |inst| { |
| 3355 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 3356 | if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) { | |
| 3364 | if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) { | |
| 3357 | 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 | 3368 | flipped = true; |
| 3361 | 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 | 1711 | .unreach => try airUnreach(f), |
| 1712 | 1712 | .fence => try airFence(f, inst), |
| 1713 | 1713 | |
| 1714 | // TODO use a different strategy for add that communicates to the optimizer | |
| 1715 | // that wrapping is UB. | |
| 1716 | .add => try airBinOp (f, inst, " + "), | |
| 1717 | .ptr_add => try airPtrAddSub (f, inst, " + "), | |
| 1718 | // TODO use a different strategy for sub that communicates to the optimizer | |
| 1719 | // that wrapping is UB. | |
| 1720 | .sub => try airBinOp (f, inst, " - "), | |
| 1721 | .ptr_sub => try airPtrAddSub (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. | |
| 1714 | .ptr_add => try airPtrAddSub(f, inst, " + "), | |
| 1715 | .ptr_sub => try airPtrAddSub(f, inst, " - "), | |
| 1716 | ||
| 1717 | // TODO use a different strategy for add, sub, mul, div | |
| 1718 | // that communicates to the optimizer that wrapping is UB. | |
| 1719 | .add => try airBinOp (f, inst, " + "), | |
| 1720 | .sub => try airBinOp (f, inst, " - "), | |
| 1721 | .mul => try airBinOp (f, inst, " * "), | |
| 1727 | 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 | 1726 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 1730 | 1727 | const lhs_ty = f.air.typeOf(bin_op.lhs); |
| 1731 | 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 | 1732 | else |
| 1736 | 1733 | try airBinOpBuiltinCall(f, inst, "div_trunc"); |
| 1737 | 1734 | }, |
| 1738 | .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"), | |
| 1739 | .rem => try airBinOp( f, inst, " % "), | |
| 1740 | .mod => try airBinOpBuiltinCall(f, inst, "mod"), | |
| 1735 | .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"), | |
| 1736 | .mod => try airBinOpBuiltinCall(f, inst, "mod"), | |
| 1741 | 1737 | |
| 1742 | 1738 | .addwrap => try airWrapOp(f, inst, " + ", "addw_"), |
| 1743 | 1739 | .subwrap => try airWrapOp(f, inst, " - ", "subw_"), |
| ... | ... | @@ -2617,10 +2613,10 @@ fn airEquality( |
| 2617 | 2613 | } |
| 2618 | 2614 | |
| 2619 | 2615 | fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { |
| 2620 | if (f.liveness.isUnused(inst)) | |
| 2621 | return CValue.none; | |
| 2616 | if (f.liveness.isUnused(inst)) return CValue.none; | |
| 2622 | 2617 | |
| 2623 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | |
| 2618 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | |
| 2619 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 2624 | 2620 | const lhs = try f.resolveInst(bin_op.lhs); |
| 2625 | 2621 | const rhs = try f.resolveInst(bin_op.rhs); |
| 2626 | 2622 |
src/codegen/llvm.zig+4-2| ... | ... | @@ -5679,7 +5679,8 @@ pub const FuncGen = struct { |
| 5679 | 5679 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 5680 | 5680 | if (self.liveness.isUnused(inst)) return null; |
| 5681 | 5681 | |
| 5682 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 5682 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 5683 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 5683 | 5684 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5684 | 5685 | const offset = try self.resolveInst(bin_op.rhs); |
| 5685 | 5686 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| ... | ... | @@ -5698,7 +5699,8 @@ pub const FuncGen = struct { |
| 5698 | 5699 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 5699 | 5700 | if (self.liveness.isUnused(inst)) return null; |
| 5700 | 5701 | |
| 5701 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | |
| 5702 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 5703 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 5702 | 5704 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5703 | 5705 | const offset = try self.resolveInst(bin_op.rhs); |
| 5704 | 5706 | const negative_offset = self.builder.buildNeg(offset, ""); |
src/print_air.zig+6-17| ... | ... | @@ -114,8 +114,6 @@ const Writer = struct { |
| 114 | 114 | .div_exact, |
| 115 | 115 | .rem, |
| 116 | 116 | .mod, |
| 117 | .ptr_add, | |
| 118 | .ptr_sub, | |
| 119 | 117 | .bit_and, |
| 120 | 118 | .bit_or, |
| 121 | 119 | .xor, |
| ... | ... | @@ -231,6 +229,12 @@ const Writer = struct { |
| 231 | 229 | .slice, |
| 232 | 230 | .slice_elem_ptr, |
| 233 | 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 | 238 | => try w.writeTyPlBin(s, inst), |
| 235 | 239 | |
| 236 | 240 | .call, |
| ... | ... | @@ -275,12 +279,6 @@ const Writer = struct { |
| 275 | 279 | .reduce => try w.writeReduce(s, inst), |
| 276 | 280 | .cmp_vector => try w.writeCmpVector(s, inst), |
| 277 | 281 | |
| 278 | .add_with_overflow, | |
| 279 | .sub_with_overflow, | |
| 280 | .mul_with_overflow, | |
| 281 | .shl_with_overflow, | |
| 282 | => try w.writeOverflow(s, inst), | |
| 283 | ||
| 284 | 282 | .dbg_block_begin, .dbg_block_end => {}, |
| 285 | 283 | } |
| 286 | 284 | } |
| ... | ... | @@ -478,15 +476,6 @@ const Writer = struct { |
| 478 | 476 | try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) }); |
| 479 | 477 | } |
| 480 | 478 | |
| 481 | fn writeOverflow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 482 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | |
| 483 | const extra = w.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 484 | ||
| 485 | try w.writeOperand(s, inst, 0, extra.lhs); | |
| 486 | try s.writeAll(", "); | |
| 487 | try w.writeOperand(s, inst, 1, extra.rhs); | |
| 488 | } | |
| 489 | ||
| 490 | 479 | fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 491 | 480 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 492 | 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 | 1813 | }; |
| 1814 | 1814 | } |
| 1815 | 1815 | |
| 1816 | /// Asserts the value is numeric | |
| 1817 | pub fn isZero(self: Value) bool { | |
| 1818 | return switch (self.tag()) { | |
| 1819 | .zero, .the_only_possible_value => true, | |
| 1820 | .one => false, | |
| 1821 | ||
| 1822 | .int_u64 => self.castTag(.int_u64).?.data == 0, | |
| 1823 | .int_i64 => self.castTag(.int_i64).?.data == 0, | |
| 1824 | ||
| 1825 | .float_16 => self.castTag(.float_16).?.data == 0, | |
| 1826 | .float_32 => self.castTag(.float_32).?.data == 0, | |
| 1827 | .float_64 => self.castTag(.float_64).?.data == 0, | |
| 1828 | .float_80 => self.castTag(.float_80).?.data == 0, | |
| 1829 | .float_128 => self.castTag(.float_128).?.data == 0, | |
| 1830 | ||
| 1831 | .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(), | |
| 1832 | .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(), | |
| 1833 | else => unreachable, | |
| 1834 | }; | |
| 1835 | } | |
| 1836 | ||
| 1837 | 1816 | pub fn orderAgainstZero(lhs: Value) std.math.Order { |
| 1838 | 1817 | return orderAgainstZeroAdvanced(lhs, null) catch unreachable; |
| 1839 | 1818 | } |
| ... | ... | @@ -3442,7 +3421,6 @@ pub const Value = extern union { |
| 3442 | 3421 | const info = ty.intInfo(target); |
| 3443 | 3422 | |
| 3444 | 3423 | if (info.bits == 0) { |
| 3445 | assert(val.isZero()); // Sema should guarantee | |
| 3446 | 3424 | return val; |
| 3447 | 3425 | } |
| 3448 | 3426 |
test/behavior/align.zig+16-5| ... | ... | @@ -16,11 +16,22 @@ test "global variable alignment" { |
| 16 | 16 | const slice = @as(*align(4) [1]u8, &foo)[0..]; |
| 17 | 17 | comptime try expect(@TypeOf(slice) == *align(4) [1]u8); |
| 18 | 18 | } |
| 19 | { | |
| 20 | var runtime_zero: usize = 0; | |
| 21 | const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..]; | |
| 22 | comptime try expect(@TypeOf(slice) == []align(4) u8); | |
| 23 | } | |
| 19 | } | |
| 20 | ||
| 21 | test "slicing array of length 1 can assume runtime index is always zero" { | |
| 22 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 23 | ||
| 24 | // TODO reevaluate this test case, because notice that you can | |
| 25 | // change `runtime_zero` to be `1` and the test still passes for stage1. | |
| 26 | // Reconsider also this code: | |
| 27 | // var array: [4]u8 = undefined; | |
| 28 | // var runtime: usize = 4; | |
| 29 | // var ptr = array[runtime..]; | |
| 30 | // _ = ptr; | |
| 31 | ||
| 32 | var runtime_zero: usize = 0; | |
| 33 | const slice = @as(*align(4) [1]u8, &foo)[runtime_zero..]; | |
| 34 | comptime try expect(@TypeOf(slice) == []align(4) u8); | |
| 24 | 35 | } |
| 25 | 36 | |
| 26 | 37 | test "default alignment allows unspecified in type syntax" { |
test/behavior/pointers.zig-2| ... | ... | @@ -377,8 +377,6 @@ test "pointer to array at fixed address" { |
| 377 | 377 | } |
| 378 | 378 | |
| 379 | 379 | test "pointer arithmetic affects the alignment" { |
| 380 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 381 | ||
| 382 | 380 | { |
| 383 | 381 | var ptr: [*]align(8) u32 = undefined; |
| 384 | 382 | var x: usize = 1; |