| ... | @@ -81,6 +81,19 @@ pub const Feature = enum { | ... | @@ -81,6 +81,19 @@ pub const Feature = enum { |
| 81 | /// Legalize reduce of a one element vector to a bitcast | 81 | /// Legalize reduce of a one element vector to a bitcast |
| 82 | reduce_one_elem_to_bitcast, | 82 | reduce_one_elem_to_bitcast, |
| 83 | | 83 | |
| | 84 | /// Replace `intcast_safe` with an explicit safety check which `call`s the panic function on failure. |
| | 85 | /// Not compatible with `scalarize_intcast_safe`. |
| | 86 | expand_intcast_safe, |
| | 87 | /// Replace `add_safe` with an explicit safety check which `call`s the panic function on failure. |
| | 88 | /// Not compatible with `scalarize_add_safe`. |
| | 89 | expand_add_safe, |
| | 90 | /// Replace `sub_safe` with an explicit safety check which `call`s the panic function on failure. |
| | 91 | /// Not compatible with `scalarize_sub_safe`. |
| | 92 | expand_sub_safe, |
| | 93 | /// Replace `mul_safe` with an explicit safety check which `call`s the panic function on failure. |
| | 94 | /// Not compatible with `scalarize_mul_safe`. |
| | 95 | expand_mul_safe, |
| | 96 | |
| 84 | fn scalarize(tag: Air.Inst.Tag) Feature { | 97 | fn scalarize(tag: Air.Inst.Tag) Feature { |
| 85 | return switch (tag) { | 98 | return switch (tag) { |
| 86 | else => unreachable, | 99 | else => unreachable, |
| ... | @@ -205,17 +218,14 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -205,17 +218,14 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 205 | .arg, | 218 | .arg, |
| 206 | => {}, | 219 | => {}, |
| 207 | inline .add, | 220 | inline .add, |
| 208 | .add_safe, | | |
| 209 | .add_optimized, | 221 | .add_optimized, |
| 210 | .add_wrap, | 222 | .add_wrap, |
| 211 | .add_sat, | 223 | .add_sat, |
| 212 | .sub, | 224 | .sub, |
| 213 | .sub_safe, | | |
| 214 | .sub_optimized, | 225 | .sub_optimized, |
| 215 | .sub_wrap, | 226 | .sub_wrap, |
| 216 | .sub_sat, | 227 | .sub_sat, |
| 217 | .mul, | 228 | .mul, |
| 218 | .mul_safe, | | |
| 219 | .mul_optimized, | 229 | .mul_optimized, |
| 220 | .mul_wrap, | 230 | .mul_wrap, |
| 221 | .mul_sat, | 231 | .mul_sat, |
| ... | @@ -240,6 +250,27 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -240,6 +250,27 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 240 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; | 250 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 241 | if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op); | 251 | if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op); |
| 242 | }, | 252 | }, |
| | 253 | .add_safe => if (l.features.contains(.expand_add_safe)) { |
| | 254 | assert(!l.features.contains(.scalarize_add_safe)); // it doesn't make sense to do both |
| | 255 | continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .add_with_overflow)); |
| | 256 | } else if (l.features.contains(.scalarize_add_safe)) { |
| | 257 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 258 | if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op); |
| | 259 | }, |
| | 260 | .sub_safe => if (l.features.contains(.expand_sub_safe)) { |
| | 261 | assert(!l.features.contains(.scalarize_sub_safe)); // it doesn't make sense to do both |
| | 262 | continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .sub_with_overflow)); |
| | 263 | } else if (l.features.contains(.scalarize_sub_safe)) { |
| | 264 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 265 | if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op); |
| | 266 | }, |
| | 267 | .mul_safe => if (l.features.contains(.expand_mul_safe)) { |
| | 268 | assert(!l.features.contains(.scalarize_mul_safe)); // it doesn't make sense to do both |
| | 269 | continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .mul_with_overflow)); |
| | 270 | } else if (l.features.contains(.scalarize_mul_safe)) { |
| | 271 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| | 272 | if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op); |
| | 273 | }, |
| 243 | .ptr_add, | 274 | .ptr_add, |
| 244 | .ptr_sub, | 275 | .ptr_sub, |
| 245 | .add_with_overflow, | 276 | .add_with_overflow, |
| ... | @@ -295,7 +326,6 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -295,7 +326,6 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 295 | .fptrunc, | 326 | .fptrunc, |
| 296 | .fpext, | 327 | .fpext, |
| 297 | .intcast, | 328 | .intcast, |
| 298 | .intcast_safe, | | |
| 299 | .trunc, | 329 | .trunc, |
| 300 | .int_from_float, | 330 | .int_from_float, |
| 301 | .int_from_float_optimized, | 331 | .int_from_float_optimized, |
| ... | @@ -312,6 +342,13 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -312,6 +342,13 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 312 | if (to_ty.isVector(zcu) and from_ty.isVector(zcu) and to_ty.vectorLen(zcu) == from_ty.vectorLen(zcu)) | 342 | if (to_ty.isVector(zcu) and from_ty.isVector(zcu) and to_ty.vectorLen(zcu) == from_ty.vectorLen(zcu)) |
| 313 | continue :inst try l.scalarize(inst, .ty_op); | 343 | continue :inst try l.scalarize(inst, .ty_op); |
| 314 | }, | 344 | }, |
| | 345 | .intcast_safe => if (l.features.contains(.expand_intcast_safe)) { |
| | 346 | assert(!l.features.contains(.scalarize_intcast_safe)); // it doesn't make sense to do both |
| | 347 | continue :inst l.replaceInst(inst, .block, try l.safeIntcastBlockPayload(inst)); |
| | 348 | } else if (l.features.contains(.scalarize_intcast_safe)) { |
| | 349 | const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| | 350 | if (ty_op.ty.toType().isVector(zcu)) continue :inst try l.scalarize(inst, .ty_op); |
| | 351 | }, |
| 315 | .block, | 352 | .block, |
| 316 | .loop, | 353 | .loop, |
| 317 | => { | 354 | => { |
| ... | @@ -550,81 +587,83 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ | ... | @@ -550,81 +587,83 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ |
| 550 | const expected_instructions_len = l.air_instructions.len + (6 + arity + 8); | 587 | const expected_instructions_len = l.air_instructions.len + (6 + arity + 8); |
| 551 | try l.air_instructions.ensureTotalCapacity(gpa, expected_instructions_len); | 588 | try l.air_instructions.ensureTotalCapacity(gpa, expected_instructions_len); |
| 552 | | 589 | |
| 553 | var res_block: Block(4) = .empty; | 590 | var res_block_buf: [4]Air.Inst.Index = undefined; |
| | 591 | var res_block: Block = .init(&res_block_buf); |
| 554 | { | 592 | { |
| 555 | const res_alloc_inst = res_block.add(l.addInstAssumeCapacity(.{ | 593 | const res_alloc_inst = res_block.add(l, .{ |
| 556 | .tag = .alloc, | 594 | .tag = .alloc, |
| 557 | .data = .{ .ty = try pt.singleMutPtrType(res_ty) }, | 595 | .data = .{ .ty = try pt.singleMutPtrType(res_ty) }, |
| 558 | })); | 596 | }); |
| 559 | const index_alloc_inst = res_block.add(l.addInstAssumeCapacity(.{ | 597 | const index_alloc_inst = res_block.add(l, .{ |
| 560 | .tag = .alloc, | 598 | .tag = .alloc, |
| 561 | .data = .{ .ty = .ptr_usize }, | 599 | .data = .{ .ty = .ptr_usize }, |
| 562 | })); | 600 | }); |
| 563 | _ = res_block.add(l.addInstAssumeCapacity(.{ | 601 | _ = res_block.add(l, .{ |
| 564 | .tag = .store, | 602 | .tag = .store, |
| 565 | .data = .{ .bin_op = .{ | 603 | .data = .{ .bin_op = .{ |
| 566 | .lhs = index_alloc_inst.toRef(), | 604 | .lhs = index_alloc_inst.toRef(), |
| 567 | .rhs = .zero_usize, | 605 | .rhs = .zero_usize, |
| 568 | } }, | 606 | } }, |
| 569 | })); | 607 | }); |
| 570 | | 608 | |
| 571 | const loop_inst: Air.Inst.Index = @enumFromInt(l.air_instructions.len + (3 + arity + 7)); | 609 | const loop_inst: Air.Inst.Index = @enumFromInt(l.air_instructions.len + (3 + arity + 7)); |
| 572 | var loop_block: Block(3 + arity + 2) = .empty; | 610 | var loop_block_buf: [3 + arity + 2]Air.Inst.Index = undefined; |
| | 611 | var loop_block: Block = .init(&loop_block_buf); |
| 573 | { | 612 | { |
| 574 | const cur_index_inst = loop_block.add(l.addInstAssumeCapacity(.{ | 613 | const cur_index_inst = loop_block.add(l, .{ |
| 575 | .tag = .load, | 614 | .tag = .load, |
| 576 | .data = .{ .ty_op = .{ | 615 | .data = .{ .ty_op = .{ |
| 577 | .ty = .usize_type, | 616 | .ty = .usize_type, |
| 578 | .operand = index_alloc_inst.toRef(), | 617 | .operand = index_alloc_inst.toRef(), |
| 579 | } }, | 618 | } }, |
| 580 | })); | 619 | }); |
| 581 | _ = loop_block.add(l.addInstAssumeCapacity(.{ | 620 | _ = loop_block.add(l, .{ |
| 582 | .tag = .vector_store_elem, | 621 | .tag = .vector_store_elem, |
| 583 | .data = .{ .vector_store_elem = .{ | 622 | .data = .{ .vector_store_elem = .{ |
| 584 | .vector_ptr = res_alloc_inst.toRef(), | 623 | .vector_ptr = res_alloc_inst.toRef(), |
| 585 | .payload = try l.addExtra(Air.Bin, .{ | 624 | .payload = try l.addExtra(Air.Bin, .{ |
| 586 | .lhs = cur_index_inst.toRef(), | 625 | .lhs = cur_index_inst.toRef(), |
| 587 | .rhs = loop_block.add(l.addInstAssumeCapacity(res_elem: switch (data_tag) { | 626 | .rhs = loop_block.add(l, res_elem: switch (data_tag) { |
| 588 | .un_op => .{ | 627 | .un_op => .{ |
| 589 | .tag = orig.tag, | 628 | .tag = orig.tag, |
| 590 | .data = .{ .un_op = loop_block.add(l.addInstAssumeCapacity(.{ | 629 | .data = .{ .un_op = loop_block.add(l, .{ |
| 591 | .tag = .array_elem_val, | 630 | .tag = .array_elem_val, |
| 592 | .data = .{ .bin_op = .{ | 631 | .data = .{ .bin_op = .{ |
| 593 | .lhs = orig.data.un_op, | 632 | .lhs = orig.data.un_op, |
| 594 | .rhs = cur_index_inst.toRef(), | 633 | .rhs = cur_index_inst.toRef(), |
| 595 | } }, | 634 | } }, |
| 596 | })).toRef() }, | 635 | }).toRef() }, |
| 597 | }, | 636 | }, |
| 598 | .ty_op => .{ | 637 | .ty_op => .{ |
| 599 | .tag = orig.tag, | 638 | .tag = orig.tag, |
| 600 | .data = .{ .ty_op = .{ | 639 | .data = .{ .ty_op = .{ |
| 601 | .ty = Air.internedToRef(orig.data.ty_op.ty.toType().scalarType(zcu).toIntern()), | 640 | .ty = Air.internedToRef(orig.data.ty_op.ty.toType().scalarType(zcu).toIntern()), |
| 602 | .operand = loop_block.add(l.addInstAssumeCapacity(.{ | 641 | .operand = loop_block.add(l, .{ |
| 603 | .tag = .array_elem_val, | 642 | .tag = .array_elem_val, |
| 604 | .data = .{ .bin_op = .{ | 643 | .data = .{ .bin_op = .{ |
| 605 | .lhs = orig.data.ty_op.operand, | 644 | .lhs = orig.data.ty_op.operand, |
| 606 | .rhs = cur_index_inst.toRef(), | 645 | .rhs = cur_index_inst.toRef(), |
| 607 | } }, | 646 | } }, |
| 608 | })).toRef(), | 647 | }).toRef(), |
| 609 | } }, | 648 | } }, |
| 610 | }, | 649 | }, |
| 611 | .bin_op => .{ | 650 | .bin_op => .{ |
| 612 | .tag = orig.tag, | 651 | .tag = orig.tag, |
| 613 | .data = .{ .bin_op = .{ | 652 | .data = .{ .bin_op = .{ |
| 614 | .lhs = loop_block.add(l.addInstAssumeCapacity(.{ | 653 | .lhs = loop_block.add(l, .{ |
| 615 | .tag = .array_elem_val, | 654 | .tag = .array_elem_val, |
| 616 | .data = .{ .bin_op = .{ | 655 | .data = .{ .bin_op = .{ |
| 617 | .lhs = orig.data.bin_op.lhs, | 656 | .lhs = orig.data.bin_op.lhs, |
| 618 | .rhs = cur_index_inst.toRef(), | 657 | .rhs = cur_index_inst.toRef(), |
| 619 | } }, | 658 | } }, |
| 620 | })).toRef(), | 659 | }).toRef(), |
| 621 | .rhs = loop_block.add(l.addInstAssumeCapacity(.{ | 660 | .rhs = loop_block.add(l, .{ |
| 622 | .tag = .array_elem_val, | 661 | .tag = .array_elem_val, |
| 623 | .data = .{ .bin_op = .{ | 662 | .data = .{ .bin_op = .{ |
| 624 | .lhs = orig.data.bin_op.rhs, | 663 | .lhs = orig.data.bin_op.rhs, |
| 625 | .rhs = cur_index_inst.toRef(), | 664 | .rhs = cur_index_inst.toRef(), |
| 626 | } }, | 665 | } }, |
| 627 | })).toRef(), | 666 | }).toRef(), |
| 628 | } }, | 667 | } }, |
| 629 | }, | 668 | }, |
| 630 | .ty_pl_vector_cmp => { | 669 | .ty_pl_vector_cmp => { |
| ... | @@ -650,20 +689,20 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ | ... | @@ -650,20 +689,20 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ |
| 650 | }, | 689 | }, |
| 651 | }, | 690 | }, |
| 652 | .data = .{ .bin_op = .{ | 691 | .data = .{ .bin_op = .{ |
| 653 | .lhs = loop_block.add(l.addInstAssumeCapacity(.{ | 692 | .lhs = loop_block.add(l, .{ |
| 654 | .tag = .array_elem_val, | 693 | .tag = .array_elem_val, |
| 655 | .data = .{ .bin_op = .{ | 694 | .data = .{ .bin_op = .{ |
| 656 | .lhs = extra.lhs, | 695 | .lhs = extra.lhs, |
| 657 | .rhs = cur_index_inst.toRef(), | 696 | .rhs = cur_index_inst.toRef(), |
| 658 | } }, | 697 | } }, |
| 659 | })).toRef(), | 698 | }).toRef(), |
| 660 | .rhs = loop_block.add(l.addInstAssumeCapacity(.{ | 699 | .rhs = loop_block.add(l, .{ |
| 661 | .tag = .array_elem_val, | 700 | .tag = .array_elem_val, |
| 662 | .data = .{ .bin_op = .{ | 701 | .data = .{ .bin_op = .{ |
| 663 | .lhs = extra.rhs, | 702 | .lhs = extra.rhs, |
| 664 | .rhs = cur_index_inst.toRef(), | 703 | .rhs = cur_index_inst.toRef(), |
| 665 | } }, | 704 | } }, |
| 666 | })).toRef(), | 705 | }).toRef(), |
| 667 | } }, | 706 | } }, |
| 668 | }; | 707 | }; |
| 669 | }, | 708 | }, |
| ... | @@ -673,94 +712,96 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ | ... | @@ -673,94 +712,96 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ |
| 673 | .tag = orig.tag, | 712 | .tag = orig.tag, |
| 674 | .data = .{ .pl_op = .{ | 713 | .data = .{ .pl_op = .{ |
| 675 | .payload = try l.addExtra(Air.Bin, .{ | 714 | .payload = try l.addExtra(Air.Bin, .{ |
| 676 | .lhs = loop_block.add(l.addInstAssumeCapacity(.{ | 715 | .lhs = loop_block.add(l, .{ |
| 677 | .tag = .array_elem_val, | 716 | .tag = .array_elem_val, |
| 678 | .data = .{ .bin_op = .{ | 717 | .data = .{ .bin_op = .{ |
| 679 | .lhs = extra.lhs, | 718 | .lhs = extra.lhs, |
| 680 | .rhs = cur_index_inst.toRef(), | 719 | .rhs = cur_index_inst.toRef(), |
| 681 | } }, | 720 | } }, |
| 682 | })).toRef(), | 721 | }).toRef(), |
| 683 | .rhs = loop_block.add(l.addInstAssumeCapacity(.{ | 722 | .rhs = loop_block.add(l, .{ |
| 684 | .tag = .array_elem_val, | 723 | .tag = .array_elem_val, |
| 685 | .data = .{ .bin_op = .{ | 724 | .data = .{ .bin_op = .{ |
| 686 | .lhs = extra.rhs, | 725 | .lhs = extra.rhs, |
| 687 | .rhs = cur_index_inst.toRef(), | 726 | .rhs = cur_index_inst.toRef(), |
| 688 | } }, | 727 | } }, |
| 689 | })).toRef(), | 728 | }).toRef(), |
| 690 | }), | 729 | }), |
| 691 | .operand = loop_block.add(l.addInstAssumeCapacity(.{ | 730 | .operand = loop_block.add(l, .{ |
| 692 | .tag = .array_elem_val, | 731 | .tag = .array_elem_val, |
| 693 | .data = .{ .bin_op = .{ | 732 | .data = .{ .bin_op = .{ |
| 694 | .lhs = orig.data.pl_op.operand, | 733 | .lhs = orig.data.pl_op.operand, |
| 695 | .rhs = cur_index_inst.toRef(), | 734 | .rhs = cur_index_inst.toRef(), |
| 696 | } }, | 735 | } }, |
| 697 | })).toRef(), | 736 | }).toRef(), |
| 698 | } }, | 737 | } }, |
| 699 | }; | 738 | }; |
| 700 | }, | 739 | }, |
| 701 | })).toRef(), | 740 | }).toRef(), |
| 702 | }), | 741 | }), |
| 703 | } }, | 742 | } }, |
| 704 | })); | 743 | }); |
| 705 | const not_done_inst = loop_block.add(l.addInstAssumeCapacity(.{ | 744 | const not_done_inst = loop_block.add(l, .{ |
| 706 | .tag = .cmp_lt, | 745 | .tag = .cmp_lt, |
| 707 | .data = .{ .bin_op = .{ | 746 | .data = .{ .bin_op = .{ |
| 708 | .lhs = cur_index_inst.toRef(), | 747 | .lhs = cur_index_inst.toRef(), |
| 709 | .rhs = try pt.intRef(.usize, res_ty.vectorLen(zcu) - 1), | 748 | .rhs = try pt.intRef(.usize, res_ty.vectorLen(zcu) - 1), |
| 710 | } }, | 749 | } }, |
| 711 | })); | 750 | }); |
| 712 | | 751 | |
| 713 | var not_done_block: Block(3) = .empty; | 752 | var not_done_block_buf: [3]Air.Inst.Index = undefined; |
| | 753 | var not_done_block: Block = .init(&not_done_block_buf); |
| 714 | { | 754 | { |
| 715 | _ = not_done_block.add(l.addInstAssumeCapacity(.{ | 755 | _ = not_done_block.add(l, .{ |
| 716 | .tag = .store, | 756 | .tag = .store, |
| 717 | .data = .{ .bin_op = .{ | 757 | .data = .{ .bin_op = .{ |
| 718 | .lhs = index_alloc_inst.toRef(), | 758 | .lhs = index_alloc_inst.toRef(), |
| 719 | .rhs = not_done_block.add(l.addInstAssumeCapacity(.{ | 759 | .rhs = not_done_block.add(l, .{ |
| 720 | .tag = .add, | 760 | .tag = .add, |
| 721 | .data = .{ .bin_op = .{ | 761 | .data = .{ .bin_op = .{ |
| 722 | .lhs = cur_index_inst.toRef(), | 762 | .lhs = cur_index_inst.toRef(), |
| 723 | .rhs = .one_usize, | 763 | .rhs = .one_usize, |
| 724 | } }, | 764 | } }, |
| 725 | })).toRef(), | 765 | }).toRef(), |
| 726 | } }, | 766 | } }, |
| 727 | })); | 767 | }); |
| 728 | _ = not_done_block.add(l.addInstAssumeCapacity(.{ | 768 | _ = not_done_block.add(l, .{ |
| 729 | .tag = .repeat, | 769 | .tag = .repeat, |
| 730 | .data = .{ .repeat = .{ .loop_inst = loop_inst } }, | 770 | .data = .{ .repeat = .{ .loop_inst = loop_inst } }, |
| 731 | })); | 771 | }); |
| 732 | } | 772 | } |
| 733 | var done_block: Block(2) = .empty; | 773 | var done_block_buf: [2]Air.Inst.Index = undefined; |
| | 774 | var done_block: Block = .init(&done_block_buf); |
| 734 | { | 775 | { |
| 735 | _ = done_block.add(l.addInstAssumeCapacity(.{ | 776 | _ = done_block.add(l, .{ |
| 736 | .tag = .br, | 777 | .tag = .br, |
| 737 | .data = .{ .br = .{ | 778 | .data = .{ .br = .{ |
| 738 | .block_inst = orig_inst, | 779 | .block_inst = orig_inst, |
| 739 | .operand = done_block.add(l.addInstAssumeCapacity(.{ | 780 | .operand = done_block.add(l, .{ |
| 740 | .tag = .load, | 781 | .tag = .load, |
| 741 | .data = .{ .ty_op = .{ | 782 | .data = .{ .ty_op = .{ |
| 742 | .ty = Air.internedToRef(res_ty.toIntern()), | 783 | .ty = Air.internedToRef(res_ty.toIntern()), |
| 743 | .operand = res_alloc_inst.toRef(), | 784 | .operand = res_alloc_inst.toRef(), |
| 744 | } }, | 785 | } }, |
| 745 | })).toRef(), | 786 | }).toRef(), |
| 746 | } }, | 787 | } }, |
| 747 | })); | 788 | }); |
| 748 | } | 789 | } |
| 749 | _ = loop_block.add(l.addInstAssumeCapacity(.{ | 790 | _ = loop_block.add(l, .{ |
| 750 | .tag = .cond_br, | 791 | .tag = .cond_br, |
| 751 | .data = .{ .pl_op = .{ | 792 | .data = .{ .pl_op = .{ |
| 752 | .operand = not_done_inst.toRef(), | 793 | .operand = not_done_inst.toRef(), |
| 753 | .payload = try l.addCondBrBodies(not_done_block.body(), done_block.body()), | 794 | .payload = try l.addCondBrBodies(not_done_block.body(), done_block.body()), |
| 754 | } }, | 795 | } }, |
| 755 | })); | 796 | }); |
| 756 | } | 797 | } |
| 757 | assert(loop_inst == res_block.add(l.addInstAssumeCapacity(.{ | 798 | assert(loop_inst == res_block.add(l, .{ |
| 758 | .tag = .loop, | 799 | .tag = .loop, |
| 759 | .data = .{ .ty_pl = .{ | 800 | .data = .{ .ty_pl = .{ |
| 760 | .ty = .noreturn_type, | 801 | .ty = .noreturn_type, |
| 761 | .payload = try l.addBlockBody(loop_block.body()), | 802 | .payload = try l.addBlockBody(loop_block.body()), |
| 762 | } }, | 803 | } }, |
| 763 | }))); | 804 | })); |
| 764 | } | 805 | } |
| 765 | assert(l.air_instructions.len == expected_instructions_len); | 806 | assert(l.air_instructions.len == expected_instructions_len); |
| 766 | return .{ .ty_pl = .{ | 807 | return .{ .ty_pl = .{ |
| ... | @@ -768,29 +809,423 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ | ... | @@ -768,29 +809,423 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, comptime data_ |
| 768 | .payload = try l.addBlockBody(res_block.body()), | 809 | .payload = try l.addBlockBody(res_block.body()), |
| 769 | } }; | 810 | } }; |
| 770 | } | 811 | } |
| | 812 | fn safeIntcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.Inst.Data { |
| | 813 | const pt = l.pt; |
| | 814 | const zcu = pt.zcu; |
| | 815 | const gpa = zcu.gpa; |
| | 816 | const ty_op = l.air_instructions.items(.data)[@intFromEnum(orig_inst)].ty_op; |
| | 817 | |
| | 818 | const operand_ref = ty_op.operand; |
| | 819 | const operand_ty = l.typeOf(operand_ref); |
| | 820 | const dest_ty = ty_op.ty.toType(); |
| | 821 | |
| | 822 | const is_vector = operand_ty.zigTypeTag(zcu) == .vector; |
| | 823 | const operand_scalar_ty = operand_ty.scalarType(zcu); |
| | 824 | const dest_scalar_ty = dest_ty.scalarType(zcu); |
| | 825 | |
| | 826 | assert(operand_scalar_ty.zigTypeTag(zcu) == .int); |
| | 827 | const dest_is_enum = switch (dest_scalar_ty.zigTypeTag(zcu)) { |
| | 828 | .int => false, |
| | 829 | .@"enum" => true, |
| | 830 | else => unreachable, |
| | 831 | }; |
| | 832 | |
| | 833 | const operand_info = operand_scalar_ty.intInfo(zcu); |
| | 834 | const dest_info = dest_scalar_ty.intInfo(zcu); |
| | 835 | |
| | 836 | const have_min_check, const have_max_check = c: { |
| | 837 | const dest_pos_bits = dest_info.bits - @intFromBool(dest_info.signedness == .signed); |
| | 838 | const operand_pos_bits = operand_info.bits - @intFromBool(operand_info.signedness == .signed); |
| | 839 | const dest_allows_neg = dest_info.signedness == .signed and dest_info.bits > 0; |
| | 840 | const operand_allows_neg = operand_info.signedness == .signed and operand_info.bits > 0; |
| | 841 | break :c .{ |
| | 842 | operand_allows_neg and (!dest_allows_neg or dest_info.bits < operand_info.bits), |
| | 843 | dest_pos_bits < operand_pos_bits, |
| | 844 | }; |
| | 845 | }; |
| | 846 | |
| | 847 | // The worst-case scenario in terms of total instructions and total condbrs is the case where |
| | 848 | // the result type is an exhaustive enum whose tag type is smaller than the operand type: |
| | 849 | // |
| | 850 | // %x = block({ |
| | 851 | // %1 = cmp_lt(%y, @min_allowed_int) |
| | 852 | // %2 = cmp_gt(%y, @max_allowed_int) |
| | 853 | // %3 = bool_or(%1, %2) |
| | 854 | // %4 = cond_br(%3, { |
| | 855 | // %5 = call(@panic.invalidEnumValue, []) |
| | 856 | // %6 = unreach() |
| | 857 | // }, { |
| | 858 | // %7 = intcast(@res_ty, %y) |
| | 859 | // %8 = is_named_enum_value(%7) |
| | 860 | // %9 = cond_br(%8, { |
| | 861 | // %10 = br(%x, %7) |
| | 862 | // }, { |
| | 863 | // %11 = call(@panic.invalidEnumValue, []) |
| | 864 | // %12 = unreach() |
| | 865 | // }) |
| | 866 | // }) |
| | 867 | // }) |
| | 868 | // |
| | 869 | // Note that vectors of enums don't exist -- the worst case for vectors is this: |
| | 870 | // |
| | 871 | // %x = block({ |
| | 872 | // %1 = cmp_lt(%y, @min_allowed_int) |
| | 873 | // %2 = cmp_gt(%y, @max_allowed_int) |
| | 874 | // %3 = bool_or(%1, %2) |
| | 875 | // %4 = reduce(%3, .@"or") |
| | 876 | // %5 = cond_br(%4, { |
| | 877 | // %6 = call(@panic.invalidEnumValue, []) |
| | 878 | // %7 = unreach() |
| | 879 | // }, { |
| | 880 | // %8 = intcast(@res_ty, %y) |
| | 881 | // %9 = br(%x, %8) |
| | 882 | // }) |
| | 883 | // }) |
| | 884 | |
| | 885 | try l.air_instructions.ensureUnusedCapacity(gpa, 12); |
| | 886 | var body_inst_buf: [12]Air.Inst.Index = undefined; |
| | 887 | var condbr_buf: [2]CondBr = undefined; |
| | 888 | var condbr_idx: usize = 0; |
| | 889 | |
| | 890 | var main_block: Block = .init(&body_inst_buf); |
| | 891 | var cur_block: *Block = &main_block; |
| | 892 | |
| | 893 | const panic_id: Zcu.SimplePanicId = if (dest_is_enum) .invalid_enum_value else .cast_truncated_data; |
| | 894 | |
| | 895 | if (have_min_check or have_max_check) { |
| | 896 | const dest_int_ty = if (dest_is_enum) dest_ty.intTagType(zcu) else dest_ty; |
| | 897 | const condbr = &condbr_buf[condbr_idx]; |
| | 898 | condbr_idx += 1; |
| | 899 | const below_min_inst: Air.Inst.Index = if (have_min_check) inst: { |
| | 900 | const min_val_ref = Air.internedToRef((try dest_int_ty.minInt(pt, operand_ty)).toIntern()); |
| | 901 | break :inst try cur_block.addCmp(l, is_vector, .lt, operand_ref, min_val_ref); |
| | 902 | } else undefined; |
| | 903 | const above_max_inst: Air.Inst.Index = if (have_max_check) inst: { |
| | 904 | const max_val_ref = Air.internedToRef((try dest_int_ty.maxInt(pt, operand_ty)).toIntern()); |
| | 905 | break :inst try cur_block.addCmp(l, is_vector, .gt, operand_ref, max_val_ref); |
| | 906 | } else undefined; |
| | 907 | const out_of_range_inst: Air.Inst.Index = inst: { |
| | 908 | if (have_min_check and have_max_check) break :inst cur_block.add(l, .{ |
| | 909 | .tag = .bool_or, |
| | 910 | .data = .{ .bin_op = .{ |
| | 911 | .lhs = below_min_inst.toRef(), |
| | 912 | .rhs = above_max_inst.toRef(), |
| | 913 | } }, |
| | 914 | }); |
| | 915 | if (have_min_check) break :inst below_min_inst; |
| | 916 | if (have_max_check) break :inst above_max_inst; |
| | 917 | unreachable; |
| | 918 | }; |
| | 919 | const scalar_out_of_range_inst: Air.Inst.Index = if (is_vector) cur_block.add(l, .{ |
| | 920 | .tag = .reduce, |
| | 921 | .data = .{ .reduce = .{ |
| | 922 | .operand = out_of_range_inst.toRef(), |
| | 923 | .operation = .Or, |
| | 924 | } }, |
| | 925 | }) else out_of_range_inst; |
| | 926 | condbr.* = .init(l, scalar_out_of_range_inst.toRef(), cur_block, .{ |
| | 927 | .true = .cold, |
| | 928 | .false = .none, |
| | 929 | }); |
| | 930 | condbr.then_block = .init(cur_block.stealRemainingCapacity()); |
| | 931 | try condbr.then_block.addPanic(l, panic_id); |
| | 932 | condbr.else_block = .init(condbr.then_block.stealRemainingCapacity()); |
| | 933 | cur_block = &condbr.else_block; |
| | 934 | } |
| | 935 | |
| | 936 | // Now we know we're in-range, we can intcast: |
| | 937 | const cast_inst = cur_block.add(l, .{ |
| | 938 | .tag = .intcast, |
| | 939 | .data = .{ .ty_op = .{ |
| | 940 | .ty = Air.internedToRef(dest_ty.toIntern()), |
| | 941 | .operand = operand_ref, |
| | 942 | } }, |
| | 943 | }); |
| | 944 | // For ints we're already done, but for exhaustive enums we must check this is a valid tag. |
| | 945 | if (dest_is_enum and !dest_ty.isNonexhaustiveEnum(zcu) and zcu.backendSupportsFeature(.is_named_enum_value)) { |
| | 946 | assert(!is_vector); // vectors of enums don't exist |
| | 947 | // We are building this: |
| | 948 | // %1 = is_named_enum_value(%cast_inst) |
| | 949 | // %2 = cond_br(%1, { |
| | 950 | // <new cursor> |
| | 951 | // }, { |
| | 952 | // <panic> |
| | 953 | // }) |
| | 954 | const is_named_inst = cur_block.add(l, .{ |
| | 955 | .tag = .is_named_enum_value, |
| | 956 | .data = .{ .un_op = cast_inst.toRef() }, |
| | 957 | }); |
| | 958 | const condbr = &condbr_buf[condbr_idx]; |
| | 959 | condbr_idx += 1; |
| | 960 | condbr.* = .init(l, is_named_inst.toRef(), cur_block, .{ |
| | 961 | .true = .none, |
| | 962 | .false = .cold, |
| | 963 | }); |
| | 964 | condbr.else_block = .init(cur_block.stealRemainingCapacity()); |
| | 965 | try condbr.else_block.addPanic(l, panic_id); |
| | 966 | condbr.then_block = .init(condbr.else_block.stealRemainingCapacity()); |
| | 967 | cur_block = &condbr.then_block; |
| | 968 | } |
| | 969 | // Finally, just `br` to our outer `block`. |
| | 970 | _ = cur_block.add(l, .{ |
| | 971 | .tag = .br, |
| | 972 | .data = .{ .br = .{ |
| | 973 | .block_inst = orig_inst, |
| | 974 | .operand = cast_inst.toRef(), |
| | 975 | } }, |
| | 976 | }); |
| | 977 | // We might not have used all of the instructions; that's intentional. |
| | 978 | _ = cur_block.stealRemainingCapacity(); |
| | 979 | |
| | 980 | for (condbr_buf[0..condbr_idx]) |*condbr| try condbr.finish(l); |
| | 981 | return .{ .ty_pl = .{ |
| | 982 | .ty = Air.internedToRef(dest_ty.toIntern()), |
| | 983 | .payload = try l.addBlockBody(main_block.body()), |
| | 984 | } }; |
| | 985 | } |
| | 986 | fn safeArithmeticBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, overflow_op_tag: Air.Inst.Tag) Error!Air.Inst.Data { |
| | 987 | const pt = l.pt; |
| | 988 | const zcu = pt.zcu; |
| | 989 | const gpa = zcu.gpa; |
| | 990 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(orig_inst)].bin_op; |
| | 991 | |
| | 992 | const operand_ty = l.typeOf(bin_op.lhs); |
| | 993 | assert(l.typeOf(bin_op.rhs).toIntern() == operand_ty.toIntern()); |
| | 994 | const is_vector = operand_ty.zigTypeTag(zcu) == .vector; |
| | 995 | |
| | 996 | const overflow_tuple_ty = try pt.overflowArithmeticTupleType(operand_ty); |
| | 997 | const overflow_bits_ty = overflow_tuple_ty.fieldType(1, zcu); |
| | 998 | |
| | 999 | // The worst-case scenario is a vector operand: |
| | 1000 | // |
| | 1001 | // %1 = add_with_overflow(%x, %y) |
| | 1002 | // %2 = struct_field_val(%1, .@"1") |
| | 1003 | // %3 = reduce(%2, .@"or") |
| | 1004 | // %4 = bitcast(%3, @bool_type) |
| | 1005 | // %5 = cond_br(%4, { |
| | 1006 | // %6 = call(@panic.integerOverflow, []) |
| | 1007 | // %7 = unreach() |
| | 1008 | // }, { |
| | 1009 | // %8 = struct_field_val(%1, .@"0") |
| | 1010 | // %9 = br(%z, %8) |
| | 1011 | // }) |
| | 1012 | try l.air_instructions.ensureUnusedCapacity(gpa, 9); |
| | 1013 | var body_inst_buf: [9]Air.Inst.Index = undefined; |
| | 1014 | |
| | 1015 | var main_block: Block = .init(&body_inst_buf); |
| | 1016 | |
| | 1017 | const overflow_op_inst = main_block.add(l, .{ |
| | 1018 | .tag = overflow_op_tag, |
| | 1019 | .data = .{ .ty_pl = .{ |
| | 1020 | .ty = Air.internedToRef(overflow_tuple_ty.toIntern()), |
| | 1021 | .payload = try l.addExtra(Air.Bin, .{ |
| | 1022 | .lhs = bin_op.lhs, |
| | 1023 | .rhs = bin_op.rhs, |
| | 1024 | }), |
| | 1025 | } }, |
| | 1026 | }); |
| | 1027 | const overflow_bits_inst = main_block.add(l, .{ |
| | 1028 | .tag = .struct_field_val, |
| | 1029 | .data = .{ .ty_pl = .{ |
| | 1030 | .ty = Air.internedToRef(overflow_bits_ty.toIntern()), |
| | 1031 | .payload = try l.addExtra(Air.StructField, .{ |
| | 1032 | .struct_operand = overflow_op_inst.toRef(), |
| | 1033 | .field_index = 1, |
| | 1034 | }), |
| | 1035 | } }, |
| | 1036 | }); |
| | 1037 | const any_overflow_bit_inst = if (is_vector) main_block.add(l, .{ |
| | 1038 | .tag = .reduce, |
| | 1039 | .data = .{ .reduce = .{ |
| | 1040 | .operand = overflow_bits_inst.toRef(), |
| | 1041 | .operation = .Or, |
| | 1042 | } }, |
| | 1043 | }) else overflow_bits_inst; |
| | 1044 | const any_overflow_inst = try main_block.addCmp(l, false, .eq, any_overflow_bit_inst.toRef(), .one_u1); |
| | 1045 | |
| | 1046 | var condbr: CondBr = .init(l, any_overflow_inst.toRef(), &main_block, .{ |
| | 1047 | .true = .cold, |
| | 1048 | .false = .none, |
| | 1049 | }); |
| | 1050 | condbr.then_block = .init(main_block.stealRemainingCapacity()); |
| | 1051 | try condbr.then_block.addPanic(l, .integer_overflow); |
| | 1052 | condbr.else_block = .init(condbr.then_block.stealRemainingCapacity()); |
| | 1053 | |
| | 1054 | const result_inst = condbr.else_block.add(l, .{ |
| | 1055 | .tag = .struct_field_val, |
| | 1056 | .data = .{ .ty_pl = .{ |
| | 1057 | .ty = Air.internedToRef(operand_ty.toIntern()), |
| | 1058 | .payload = try l.addExtra(Air.StructField, .{ |
| | 1059 | .struct_operand = overflow_op_inst.toRef(), |
| | 1060 | .field_index = 0, |
| | 1061 | }), |
| | 1062 | } }, |
| | 1063 | }); |
| | 1064 | _ = condbr.else_block.add(l, .{ |
| | 1065 | .tag = .br, |
| | 1066 | .data = .{ .br = .{ |
| | 1067 | .block_inst = orig_inst, |
| | 1068 | .operand = result_inst.toRef(), |
| | 1069 | } }, |
| | 1070 | }); |
| | 1071 | // We might not have used all of the instructions; that's intentional. |
| | 1072 | _ = condbr.else_block.stealRemainingCapacity(); |
| | 1073 | |
| | 1074 | try condbr.finish(l); |
| | 1075 | return .{ .ty_pl = .{ |
| | 1076 | .ty = Air.internedToRef(operand_ty.toIntern()), |
| | 1077 | .payload = try l.addBlockBody(main_block.body()), |
| | 1078 | } }; |
| | 1079 | } |
| 771 | | 1080 | |
| 772 | fn Block(comptime capacity: usize) type { | 1081 | const Block = struct { |
| 773 | return struct { | 1082 | instructions: []Air.Inst.Index, |
| 774 | instructions: [capacity]Air.Inst.Index, | 1083 | len: usize, |
| 775 | len: usize, | | |
| 776 | | 1084 | |
| 777 | const empty: @This() = .{ | 1085 | /// There are two common usages of the API: |
| 778 | .instructions = undefined, | 1086 | /// * `buf.len` is exactly the number of instructions which will be in this block |
| | 1087 | /// * `buf.len` is no smaller than necessary, and `b.stealRemainingCapacity` will be used |
| | 1088 | fn init(buf: []Air.Inst.Index) Block { |
| | 1089 | return .{ |
| | 1090 | .instructions = buf, |
| 779 | .len = 0, | 1091 | .len = 0, |
| 780 | }; | 1092 | }; |
| | 1093 | } |
| 781 | | 1094 | |
| 782 | fn add(b: *@This(), inst: Air.Inst.Index) Air.Inst.Index { | 1095 | /// Like `Legalize.addInstAssumeCapacity`, but also appends the instruction to `b`. |
| 783 | b.instructions[b.len] = inst; | 1096 | fn add(b: *Block, l: *Legalize, inst_data: Air.Inst) Air.Inst.Index { |
| 784 | b.len += 1; | 1097 | const inst = l.addInstAssumeCapacity(inst_data); |
| 785 | return inst; | 1098 | b.instructions[b.len] = inst; |
| | 1099 | b.len += 1; |
| | 1100 | return inst; |
| | 1101 | } |
| | 1102 | |
| | 1103 | /// Adds the code to call the panic handler `panic_id`. This is usually `.call` then `.unreach`, |
| | 1104 | /// but if `Zcu.Feature.panic_fn` is unsupported, we lower to `.trap` instead. |
| | 1105 | fn addPanic(b: *Block, l: *Legalize, panic_id: Zcu.SimplePanicId) Error!void { |
| | 1106 | const zcu = l.pt.zcu; |
| | 1107 | if (!zcu.backendSupportsFeature(.panic_fn)) { |
| | 1108 | _ = b.add(l, .{ |
| | 1109 | .tag = .trap, |
| | 1110 | .data = .{ .no_op = {} }, |
| | 1111 | }); |
| | 1112 | return; |
| 786 | } | 1113 | } |
| | 1114 | const panic_fn_val = zcu.builtin_decl_values.get(panic_id.toBuiltin()); |
| | 1115 | _ = b.add(l, .{ |
| | 1116 | .tag = .call, |
| | 1117 | .data = .{ .pl_op = .{ |
| | 1118 | .operand = Air.internedToRef(panic_fn_val), |
| | 1119 | .payload = try l.addExtra(Air.Call, .{ .args_len = 0 }), |
| | 1120 | } }, |
| | 1121 | }); |
| | 1122 | _ = b.add(l, .{ |
| | 1123 | .tag = .unreach, |
| | 1124 | .data = .{ .no_op = {} }, |
| | 1125 | }); |
| | 1126 | } |
| 787 | | 1127 | |
| 788 | fn body(b: *const @This()) []const Air.Inst.Index { | 1128 | /// Adds a `cmp_*` instruction (including maybe `cmp_vector`) to `b`. This is a fairly thin wrapper |
| 789 | assert(b.len == b.instructions.len); | 1129 | /// around `add`, although it does compute the result type if `is_vector` (`@Vector(n, bool)`). |
| 790 | return &b.instructions; | 1130 | fn addCmp( |
| | 1131 | b: *Block, |
| | 1132 | l: *Legalize, |
| | 1133 | is_vector: bool, |
| | 1134 | op: std.math.CompareOperator, |
| | 1135 | lhs: Air.Inst.Ref, |
| | 1136 | rhs: Air.Inst.Ref, |
| | 1137 | ) Error!Air.Inst.Index { |
| | 1138 | const pt = l.pt; |
| | 1139 | if (is_vector) { |
| | 1140 | const bool_vec_ty = try pt.vectorType(.{ |
| | 1141 | .child = .bool_type, |
| | 1142 | .len = l.typeOf(lhs).vectorLen(pt.zcu), |
| | 1143 | }); |
| | 1144 | return b.add(l, .{ |
| | 1145 | .tag = .cmp_vector, |
| | 1146 | .data = .{ .ty_pl = .{ |
| | 1147 | .ty = Air.internedToRef(bool_vec_ty.toIntern()), |
| | 1148 | .payload = try l.addExtra(Air.VectorCmp, .{ |
| | 1149 | .lhs = lhs, |
| | 1150 | .rhs = rhs, |
| | 1151 | .op = Air.VectorCmp.encodeOp(op), |
| | 1152 | }), |
| | 1153 | } }, |
| | 1154 | }); |
| 791 | } | 1155 | } |
| | 1156 | return b.add(l, .{ |
| | 1157 | .tag = switch (op) { |
| | 1158 | .lt => .cmp_lt, |
| | 1159 | .lte => .cmp_lte, |
| | 1160 | .eq => .cmp_eq, |
| | 1161 | .gte => .cmp_gte, |
| | 1162 | .gt => .cmp_gt, |
| | 1163 | .neq => .cmp_neq, |
| | 1164 | }, |
| | 1165 | .data = .{ .bin_op = .{ |
| | 1166 | .lhs = lhs, |
| | 1167 | .rhs = rhs, |
| | 1168 | } }, |
| | 1169 | }); |
| | 1170 | } |
| | 1171 | |
| | 1172 | /// Returns the unused capacity of `b.instructions`, and shrinks `b.instructions` down to `b.len`. |
| | 1173 | /// This is useful when you've provided a buffer big enough for all your instructions, but you are |
| | 1174 | /// now starting a new block and some of them need to live there instead. |
| | 1175 | fn stealRemainingCapacity(b: *Block) []Air.Inst.Index { |
| | 1176 | const remaining = b.instructions[b.len..]; |
| | 1177 | b.instructions = b.instructions[0..b.len]; |
| | 1178 | return remaining; |
| | 1179 | } |
| | 1180 | |
| | 1181 | fn body(b: *const Block) []const Air.Inst.Index { |
| | 1182 | assert(b.len == b.instructions.len); |
| | 1183 | return b.instructions; |
| | 1184 | } |
| | 1185 | }; |
| | 1186 | |
| | 1187 | const CondBr = struct { |
| | 1188 | inst: Air.Inst.Index, |
| | 1189 | hints: BranchHints, |
| | 1190 | then_block: Block, |
| | 1191 | else_block: Block, |
| | 1192 | |
| | 1193 | const BranchHints = struct { |
| | 1194 | true: std.builtin.BranchHint, |
| | 1195 | false: std.builtin.BranchHint, |
| 792 | }; | 1196 | }; |
| 793 | } | 1197 | |
| | 1198 | /// The return value has `then_block` and `else_block` initialized to `undefined`; it is the |
| | 1199 | /// caller's reponsibility to initialize them. |
| | 1200 | fn init(l: *Legalize, operand: Air.Inst.Ref, parent_block: *Block, hints: BranchHints) CondBr { |
| | 1201 | return .{ |
| | 1202 | .inst = parent_block.add(l, .{ |
| | 1203 | .tag = .cond_br, |
| | 1204 | .data = .{ .pl_op = .{ |
| | 1205 | .operand = operand, |
| | 1206 | .payload = undefined, |
| | 1207 | } }, |
| | 1208 | }), |
| | 1209 | .hints = hints, |
| | 1210 | .then_block = undefined, |
| | 1211 | .else_block = undefined, |
| | 1212 | }; |
| | 1213 | } |
| | 1214 | |
| | 1215 | fn finish(cond_br: CondBr, l: *Legalize) Error!void { |
| | 1216 | const data = &l.air_instructions.items(.data)[@intFromEnum(cond_br.inst)]; |
| | 1217 | data.pl_op.payload = try l.addCondBrBodiesHints( |
| | 1218 | cond_br.then_block.body(), |
| | 1219 | cond_br.else_block.body(), |
| | 1220 | .{ |
| | 1221 | .true = cond_br.hints.true, |
| | 1222 | .false = cond_br.hints.false, |
| | 1223 | .then_cov = .none, |
| | 1224 | .else_cov = .none, |
| | 1225 | }, |
| | 1226 | ); |
| | 1227 | } |
| | 1228 | }; |
| 794 | | 1229 | |
| 795 | fn addInstAssumeCapacity(l: *Legalize, inst: Air.Inst) Air.Inst.Index { | 1230 | fn addInstAssumeCapacity(l: *Legalize, inst: Air.Inst) Air.Inst.Index { |
| 796 | defer l.air_instructions.appendAssumeCapacity(inst); | 1231 | defer l.air_instructions.appendAssumeCapacity(inst); |
| ... | @@ -818,17 +1253,20 @@ fn addBlockBody(l: *Legalize, body: []const Air.Inst.Index) Error!u32 { | ... | @@ -818,17 +1253,20 @@ fn addBlockBody(l: *Legalize, body: []const Air.Inst.Index) Error!u32 { |
| 818 | } | 1253 | } |
| 819 | | 1254 | |
| 820 | fn addCondBrBodies(l: *Legalize, then_body: []const Air.Inst.Index, else_body: []const Air.Inst.Index) Error!u32 { | 1255 | fn addCondBrBodies(l: *Legalize, then_body: []const Air.Inst.Index, else_body: []const Air.Inst.Index) Error!u32 { |
| | 1256 | return l.addCondBrBodiesHints(then_body, else_body, .{ |
| | 1257 | .true = .none, |
| | 1258 | .false = .none, |
| | 1259 | .then_cov = .none, |
| | 1260 | .else_cov = .none, |
| | 1261 | }); |
| | 1262 | } |
| | 1263 | fn addCondBrBodiesHints(l: *Legalize, then_body: []const Air.Inst.Index, else_body: []const Air.Inst.Index, hints: Air.CondBr.BranchHints) Error!u32 { |
| 821 | try l.air_extra.ensureUnusedCapacity(l.pt.zcu.gpa, 3 + then_body.len + else_body.len); | 1264 | try l.air_extra.ensureUnusedCapacity(l.pt.zcu.gpa, 3 + then_body.len + else_body.len); |
| 822 | defer { | 1265 | defer { |
| 823 | l.air_extra.appendSliceAssumeCapacity(&.{ | 1266 | l.air_extra.appendSliceAssumeCapacity(&.{ |
| 824 | @intCast(then_body.len), | 1267 | @intCast(then_body.len), |
| 825 | @intCast(else_body.len), | 1268 | @intCast(else_body.len), |
| 826 | @bitCast(Air.CondBr.BranchHints{ | 1269 | @bitCast(hints), |
| 827 | .true = .none, | | |
| 828 | .false = .none, | | |
| 829 | .then_cov = .none, | | |
| 830 | .else_cov = .none, | | |
| 831 | }), | | |
| 832 | }); | 1270 | }); |
| 833 | l.air_extra.appendSliceAssumeCapacity(@ptrCast(then_body)); | 1271 | l.air_extra.appendSliceAssumeCapacity(@ptrCast(then_body)); |
| 834 | l.air_extra.appendSliceAssumeCapacity(@ptrCast(else_body)); | 1272 | l.air_extra.appendSliceAssumeCapacity(@ptrCast(else_body)); |