| ... | @@ -499,20 +499,29 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -499,20 +499,29 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 499 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | 499 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), |
| 500 | | 500 | |
| 501 | .add => try self.airBinOp(inst, .add), | 501 | .add => try self.airBinOp(inst, .add), |
| 502 | .addwrap => @panic("TODO try self.airAddWrap(inst)"), | 502 | .addwrap => try self.airBinOp(inst, .addwrap), |
| 503 | .add_sat => @panic("TODO try self.airAddSat(inst)"), | 503 | .sub => try self.airBinOp(inst, .sub), |
| 504 | .sub => @panic("TODO try self.airBinOp(inst)"), | 504 | .subwrap => try self.airBinOp(inst, .subwrap), |
| 505 | .subwrap => @panic("TODO try self.airSubWrap(inst)"), | 505 | .mul => try self.airBinOp(inst, .mul), |
| 506 | .sub_sat => @panic("TODO try self.airSubSat(inst)"), | 506 | .mulwrap => try self.airBinOp(inst, .mulwrap), |
| 507 | .mul => @panic("TODO try self.airMul(inst)"), | 507 | .shl => try self.airBinOp(inst, .shl), |
| 508 | .mulwrap => @panic("TODO try self.airMulWrap(inst)"), | 508 | .shl_exact => try self.airBinOp(inst, .shl_exact), |
| 509 | .mul_sat => @panic("TODO try self.airMulSat(inst)"), | 509 | .shr => try self.airBinOp(inst, .shr), |
| 510 | .rem => try self.airRem(inst), | 510 | .shr_exact => try self.airBinOp(inst, .shr_exact), |
| 511 | .mod => try self.airMod(inst), | 511 | .bool_and => try self.airBinOp(inst, .bool_and), |
| 512 | .shl, .shl_exact => @panic("TODO try self.airShl(inst)"), | 512 | .bool_or => try self.airBinOp(inst, .bool_or), |
| 513 | .shl_sat => @panic("TODO try self.airShlSat(inst)"), | 513 | .bit_and => try self.airBinOp(inst, .bit_and), |
| | 514 | .bit_or => try self.airBinOp(inst, .bit_or), |
| | 515 | .xor => try self.airBinOp(inst, .xor), |
| | 516 | |
| | 517 | .add_sat => try self.airAddSat(inst), |
| | 518 | .sub_sat => try self.airSubSat(inst), |
| | 519 | .mul_sat => try self.airMulSat(inst), |
| | 520 | .shl_sat => try self.airShlSat(inst), |
| 514 | .min => @panic("TODO try self.airMin(inst)"), | 521 | .min => @panic("TODO try self.airMin(inst)"), |
| 515 | .max => @panic("TODO try self.airMax(inst)"), | 522 | .max => @panic("TODO try self.airMax(inst)"), |
| | 523 | .rem => try self.airRem(inst), |
| | 524 | .mod => try self.airMod(inst), |
| 516 | .slice => try self.airSlice(inst), | 525 | .slice => try self.airSlice(inst), |
| 517 | | 526 | |
| 518 | .sqrt, | 527 | .sqrt, |
| ... | @@ -530,12 +539,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -530,12 +539,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 530 | .round, | 539 | .round, |
| 531 | .trunc_float, | 540 | .trunc_float, |
| 532 | .neg, | 541 | .neg, |
| 533 | => @panic("TODO try self.airUnaryMath(inst)"), | 542 | => try self.airUnaryMath(inst), |
| 534 | | 543 | |
| 535 | .add_with_overflow => try self.airAddSubWithOverflow(inst), | 544 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 536 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), | 545 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 537 | .mul_with_overflow => @panic("TODO try self.airMulWithOverflow(inst)"), | 546 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 538 | .shl_with_overflow => @panic("TODO try self.airShlWithOverflow(inst)"), | 547 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 539 | | 548 | |
| 540 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), | 549 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), |
| 541 | | 550 | |
| ... | @@ -546,14 +555,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -546,14 +555,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 546 | .cmp_gt => try self.airCmp(inst, .gt), | 555 | .cmp_gt => try self.airCmp(inst, .gt), |
| 547 | .cmp_neq => try self.airCmp(inst, .neq), | 556 | .cmp_neq => try self.airCmp(inst, .neq), |
| 548 | .cmp_vector => @panic("TODO try self.airCmpVector(inst)"), | 557 | .cmp_vector => @panic("TODO try self.airCmpVector(inst)"), |
| 549 | .cmp_lt_errors_len => @panic("TODO try self.airCmpLtErrorsLen(inst)"), | 558 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 550 | | | |
| 551 | .bool_and => @panic("TODO try self.airBoolOp(inst)"), | | |
| 552 | .bool_or => @panic("TODO try self.airBoolOp(inst)"), | | |
| 553 | .bit_and => try self.airBinOp(inst, .bit_and), | | |
| 554 | .bit_or => try self.airBinOp(inst, .bit_or), | | |
| 555 | .xor => try self.airBinOp(inst, .xor), | | |
| 556 | .shr, .shr_exact => @panic("TODO try self.airShr(inst)"), | | |
| 557 | | 559 | |
| 558 | .alloc => try self.airAlloc(inst), | 560 | .alloc => try self.airAlloc(inst), |
| 559 | .ret_ptr => try self.airRetPtr(inst), | 561 | .ret_ptr => try self.airRetPtr(inst), |
| ... | @@ -584,15 +586,15 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -584,15 +586,15 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 584 | .load => try self.airLoad(inst), | 586 | .load => try self.airLoad(inst), |
| 585 | .loop => try self.airLoop(inst), | 587 | .loop => try self.airLoop(inst), |
| 586 | .not => try self.airNot(inst), | 588 | .not => try self.airNot(inst), |
| 587 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), | 589 | .ptrtoint => try self.airPtrToInt(inst), |
| 588 | .ret => try self.airRet(inst), | 590 | .ret => try self.airRet(inst), |
| 589 | .ret_load => try self.airRetLoad(inst), | 591 | .ret_load => try self.airRetLoad(inst), |
| 590 | .store => try self.airStore(inst), | 592 | .store => try self.airStore(inst), |
| 591 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), | 593 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), |
| 592 | .struct_field_val=> try self.airStructFieldVal(inst), | 594 | .struct_field_val=> try self.airStructFieldVal(inst), |
| 593 | .array_to_slice => try self.airArrayToSlice(inst), | 595 | .array_to_slice => try self.airArrayToSlice(inst), |
| 594 | .int_to_float => @panic("TODO try self.airIntToFloat(inst)"), | 596 | .int_to_float => try self.airIntToFloat(inst), |
| 595 | .float_to_int => @panic("TODO try self.airFloatToInt(inst)"), | 597 | .float_to_int => try self.airFloatToInt(inst), |
| 596 | .cmpxchg_strong => @panic("TODO try self.airCmpxchg(inst)"), | 598 | .cmpxchg_strong => @panic("TODO try self.airCmpxchg(inst)"), |
| 597 | .cmpxchg_weak => @panic("TODO try self.airCmpxchg(inst)"), | 599 | .cmpxchg_weak => @panic("TODO try self.airCmpxchg(inst)"), |
| 598 | .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"), | 600 | .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"), |
| ... | @@ -601,12 +603,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -601,12 +603,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 601 | .memset => try self.airMemset(inst), | 603 | .memset => try self.airMemset(inst), |
| 602 | .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"), | 604 | .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"), |
| 603 | .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"), | 605 | .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"), |
| 604 | .clz => @panic("TODO try self.airClz(inst)"), | 606 | .clz => try self.airClz(inst), |
| 605 | .ctz => @panic("TODO try self.airCtz(inst)"), | 607 | .ctz => try self.airCtz(inst), |
| 606 | .popcount => @panic("TODO try self.airPopcount(inst)"), | 608 | .popcount => try self.airPopcount(inst), |
| 607 | .byte_swap => @panic("TODO try self.airByteSwap(inst)"), | 609 | .byte_swap => @panic("TODO try self.airByteSwap(inst)"), |
| 608 | .bit_reverse => @panic("TODO try self.airBitReverse(inst)"), | 610 | .bit_reverse => @panic("TODO try self.airBitReverse(inst)"), |
| 609 | .tag_name => @panic("TODO try self.airTagName(inst)"), | 611 | .tag_name => try self.airTagName(inst), |
| 610 | .error_name => @panic("TODO try self.airErrorName(inst)"), | 612 | .error_name => @panic("TODO try self.airErrorName(inst)"), |
| 611 | .splat => @panic("TODO try self.airSplat(inst)"), | 613 | .splat => @panic("TODO try self.airSplat(inst)"), |
| 612 | .select => @panic("TODO try self.airSelect(inst)"), | 614 | .select => @panic("TODO try self.airSelect(inst)"), |
| ... | @@ -614,7 +616,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -614,7 +616,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 614 | .reduce => @panic("TODO try self.airReduce(inst)"), | 616 | .reduce => @panic("TODO try self.airReduce(inst)"), |
| 615 | .aggregate_init => try self.airAggregateInit(inst), | 617 | .aggregate_init => try self.airAggregateInit(inst), |
| 616 | .union_init => @panic("TODO try self.airUnionInit(inst)"), | 618 | .union_init => @panic("TODO try self.airUnionInit(inst)"), |
| 617 | .prefetch => @panic("TODO try self.airPrefetch(inst)"), | 619 | .prefetch => try self.airPrefetch(inst), |
| 618 | .mul_add => @panic("TODO try self.airMulAdd(inst)"), | 620 | .mul_add => @panic("TODO try self.airMulAdd(inst)"), |
| 619 | | 621 | |
| 620 | .@"try" => try self.airTry(inst), | 622 | .@"try" => try self.airTry(inst), |
| ... | @@ -650,7 +652,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -650,7 +652,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 650 | .field_parent_ptr => @panic("TODO try self.airFieldParentPtr(inst)"), | 652 | .field_parent_ptr => @panic("TODO try self.airFieldParentPtr(inst)"), |
| 651 | | 653 | |
| 652 | .switch_br => try self.airSwitch(inst), | 654 | .switch_br => try self.airSwitch(inst), |
| 653 | .slice_ptr => @panic("TODO try self.airSlicePtr(inst)"), | 655 | .slice_ptr => try self.airSlicePtr(inst), |
| 654 | .slice_len => try self.airSliceLen(inst), | 656 | .slice_len => try self.airSliceLen(inst), |
| 655 | | 657 | |
| 656 | .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"), | 658 | .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"), |
| ... | @@ -659,16 +661,16 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -659,16 +661,16 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 659 | .array_elem_val => try self.airArrayElemVal(inst), | 661 | .array_elem_val => try self.airArrayElemVal(inst), |
| 660 | .slice_elem_val => try self.airSliceElemVal(inst), | 662 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 661 | .slice_elem_ptr => @panic("TODO try self.airSliceElemPtr(inst)"), | 663 | .slice_elem_ptr => @panic("TODO try self.airSliceElemPtr(inst)"), |
| 662 | .ptr_elem_val => @panic("TODO try self.airPtrElemVal(inst)"), | 664 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 663 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 665 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 664 | | 666 | |
| 665 | .constant => unreachable, // excluded from function bodies | 667 | .constant => unreachable, // excluded from function bodies |
| 666 | .const_ty => unreachable, // excluded from function bodies | 668 | .const_ty => unreachable, // excluded from function bodies |
| 667 | .unreach => self.finishAirBookkeeping(), | 669 | .unreach => self.finishAirBookkeeping(), |
| 668 | | 670 | |
| 669 | .optional_payload => @panic("TODO try self.airOptionalPayload(inst)"), | 671 | .optional_payload => try self.airOptionalPayload(inst), |
| 670 | .optional_payload_ptr => @panic("TODO try self.airOptionalPayloadPtr(inst)"), | 672 | .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), |
| 671 | .optional_payload_ptr_set => @panic("TODO try self.airOptionalPayloadPtrSet(inst)"), | 673 | .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), |
| 672 | .unwrap_errunion_err => try self.airUnwrapErrErr(inst), | 674 | .unwrap_errunion_err => try self.airUnwrapErrErr(inst), |
| 673 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), | 675 | .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), |
| 674 | .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"), | 676 | .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"), |
| ... | @@ -677,7 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -677,7 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 677 | .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"), | 679 | .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"), |
| 678 | .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"), | 680 | .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"), |
| 679 | | 681 | |
| 680 | .wrap_optional => @panic("TODO try self.airWrapOptional(inst)"), | 682 | .wrap_optional => try self.airWrapOptional(inst), |
| 681 | .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), | 683 | .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), |
| 682 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), | 684 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 683 | | 685 | |
| ... | @@ -723,6 +725,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -723,6 +725,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 723 | } | 725 | } |
| 724 | } | 726 | } |
| 725 | | 727 | |
| | 728 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| | 729 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 730 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); |
| | 731 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 732 | } |
| | 733 | |
| 726 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 734 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 727 | const tag = self.air.instructions.items(.tag)[inst]; | 735 | const tag = self.air.instructions.items(.tag)[inst]; |
| 728 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 736 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| ... | @@ -763,7 +771,6 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -763,7 +771,6 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 763 | }; | 771 | }; |
| 764 | | 772 | |
| 765 | try self.spillConditionFlagsIfOccupied(); | 773 | try self.spillConditionFlagsIfOccupied(); |
| 766 | self.condition_flags_inst = inst; | | |
| 767 | | 774 | |
| 768 | const dest = blk: { | 775 | const dest = blk: { |
| 769 | if (rhs_immediate_ok) { | 776 | if (rhs_immediate_ok) { |
| ... | @@ -1241,6 +1248,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -1241,6 +1248,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 1241 | return bt.finishAir(result); | 1248 | return bt.finishAir(result); |
| 1242 | } | 1249 | } |
| 1243 | | 1250 | |
| | 1251 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| | 1252 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1253 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airClz for {}", .{self.target.cpu.arch}); |
| | 1254 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1255 | } |
| | 1256 | |
| 1244 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 1257 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1245 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1258 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1246 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1259 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| ... | @@ -1299,6 +1312,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1299,6 +1312,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1299 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1312 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1300 | } | 1313 | } |
| 1301 | | 1314 | |
| | 1315 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| | 1316 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 1317 | const operand = try self.resolveInst(un_op); |
| | 1318 | _ = operand; |
| | 1319 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCmpLtErrorsLen for {}", .{self.target.cpu.arch}); |
| | 1320 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| | 1321 | } |
| | 1322 | |
| 1302 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 1323 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1303 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 1324 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1304 | const condition = try self.resolveInst(pl_op.operand); | 1325 | const condition = try self.resolveInst(pl_op.operand); |
| ... | @@ -1446,6 +1467,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1446,6 +1467,12 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1446 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | 1467 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| 1447 | } | 1468 | } |
| 1448 | | 1469 | |
| | 1470 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| | 1471 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1472 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airCtz for {}", .{self.target.cpu.arch}); |
| | 1473 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1474 | } |
| | 1475 | |
| 1449 | fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { | 1476 | fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 1450 | // TODO emit debug info lexical block | 1477 | // TODO emit debug info lexical block |
| 1451 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 1478 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | @@ -1519,6 +1546,14 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1519,6 +1546,14 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| 1519 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 1546 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| 1520 | } | 1547 | } |
| 1521 | | 1548 | |
| | 1549 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| | 1550 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1551 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFloatToInt for {}", .{ |
| | 1552 | self.target.cpu.arch, |
| | 1553 | }); |
| | 1554 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1555 | } |
| | 1556 | |
| 1522 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 1557 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1523 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1558 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1524 | if (self.liveness.isUnused(inst)) | 1559 | if (self.liveness.isUnused(inst)) |
| ... | @@ -1537,6 +1572,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1537,6 +1572,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1537 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); | 1572 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); |
| 1538 | } | 1573 | } |
| 1539 | | 1574 | |
| | 1575 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| | 1576 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1577 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airIntToFloat for {}", .{ |
| | 1578 | self.target.cpu.arch, |
| | 1579 | }); |
| | 1580 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1581 | } |
| | 1582 | |
| 1540 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | 1583 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1541 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1584 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1542 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1585 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| ... | @@ -1768,6 +1811,78 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1768,6 +1811,78 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1768 | return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none }); | 1811 | return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1769 | } | 1812 | } |
| 1770 | | 1813 | |
| | 1814 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| | 1815 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 1816 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); |
| | 1817 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1818 | } |
| | 1819 | |
| | 1820 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| | 1821 | //const tag = self.air.instructions.items(.tag)[inst]; |
| | 1822 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 1823 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 1824 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1825 | const lhs = try self.resolveInst(extra.lhs); |
| | 1826 | const rhs = try self.resolveInst(extra.rhs); |
| | 1827 | const lhs_ty = self.air.typeOf(extra.lhs); |
| | 1828 | const rhs_ty = self.air.typeOf(extra.rhs); |
| | 1829 | |
| | 1830 | switch (lhs_ty.zigTypeTag()) { |
| | 1831 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| | 1832 | .Int => { |
| | 1833 | const mod = self.bin_file.options.module.?; |
| | 1834 | assert(lhs_ty.eql(rhs_ty, mod)); |
| | 1835 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1836 | switch (int_info.bits) { |
| | 1837 | 1...32 => { |
| | 1838 | try self.spillConditionFlagsIfOccupied(); |
| | 1839 | |
| | 1840 | const dest = try self.binOp(.mul, lhs, rhs, lhs_ty, rhs_ty, null); |
| | 1841 | |
| | 1842 | const dest_reg = dest.register; |
| | 1843 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| | 1844 | defer self.register_manager.unlockReg(dest_reg_lock); |
| | 1845 | |
| | 1846 | const truncated_reg = try self.register_manager.allocReg(null, gp); |
| | 1847 | const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg); |
| | 1848 | defer self.register_manager.unlockReg(truncated_reg_lock); |
| | 1849 | |
| | 1850 | try self.truncRegister( |
| | 1851 | dest_reg, |
| | 1852 | truncated_reg, |
| | 1853 | int_info.signedness, |
| | 1854 | int_info.bits, |
| | 1855 | ); |
| | 1856 | |
| | 1857 | _ = try self.addInst(.{ |
| | 1858 | .tag = .cmp, |
| | 1859 | .data = .{ .arithmetic_2op = .{ |
| | 1860 | .is_imm = false, |
| | 1861 | .rs1 = dest_reg, |
| | 1862 | .rs2_or_imm = .{ .rs2 = truncated_reg }, |
| | 1863 | } }, |
| | 1864 | }); |
| | 1865 | |
| | 1866 | const cond = Instruction.ICondition.ne; |
| | 1867 | const ccr = Instruction.CCR.xcc; |
| | 1868 | |
| | 1869 | break :result MCValue{ .register_with_overflow = .{ |
| | 1870 | .reg = truncated_reg, |
| | 1871 | .flag = .{ .cond = cond, .ccr = ccr }, |
| | 1872 | } }; |
| | 1873 | }, |
| | 1874 | // XXX DO NOT call __multi3 directly as it'll result in us doing six multiplications, |
| | 1875 | // which is far more than strictly necessary |
| | 1876 | 33...64 => return self.fail("TODO copy compiler-rt's mulddi3 for a 64x64->128 multiply", .{}), |
| | 1877 | else => return self.fail("TODO overflow operations on other integer sizes", .{}), |
| | 1878 | } |
| | 1879 | }, |
| | 1880 | else => unreachable, |
| | 1881 | } |
| | 1882 | }; |
| | 1883 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| | 1884 | } |
| | 1885 | |
| 1771 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | 1886 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1772 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1887 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1773 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1888 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| ... | @@ -1863,6 +1978,43 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1863,6 +1978,43 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1863 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1978 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1864 | } | 1979 | } |
| 1865 | | 1980 | |
| | 1981 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| | 1982 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1983 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch}); |
| | 1984 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1985 | } |
| | 1986 | |
| | 1987 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| | 1988 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1989 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}); |
| | 1990 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1991 | } |
| | 1992 | |
| | 1993 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| | 1994 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1995 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch}); |
| | 1996 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 1997 | } |
| | 1998 | |
| | 1999 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| | 2000 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2001 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airPopcount for {}", .{self.target.cpu.arch}); |
| | 2002 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 2003 | } |
| | 2004 | |
| | 2005 | fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| | 2006 | const prefetch = self.air.instructions.items(.data)[inst].prefetch; |
| | 2007 | // TODO Emit a PREFETCH/IPREFETCH as necessary, see A.7 and A.42 |
| | 2008 | return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none }); |
| | 2009 | } |
| | 2010 | |
| | 2011 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| | 2012 | const is_volatile = false; // TODO |
| | 2013 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 2014 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_val for {}", .{self.target.cpu.arch}); |
| | 2015 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 2016 | } |
| | 2017 | |
| 1866 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 2018 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1867 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2019 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1868 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2020 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1870,6 +2022,12 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1870,6 +2022,12 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1870 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 2022 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 1871 | } | 2023 | } |
| 1872 | | 2024 | |
| | 2025 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| | 2026 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 2027 | const result = try self.resolveInst(un_op); |
| | 2028 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| | 2029 | } |
| | 2030 | |
| 1873 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { | 2031 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1874 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2032 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1875 | const lhs = try self.resolveInst(bin_op.lhs); | 2033 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | @@ -1911,6 +2069,101 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1911,6 +2069,101 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1911 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); | 2069 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); |
| 1912 | } | 2070 | } |
| 1913 | | 2071 | |
| | 2072 | fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| | 2073 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 2074 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); |
| | 2075 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 2076 | } |
| | 2077 | |
| | 2078 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| | 2079 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 2080 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| | 2081 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2082 | const lhs = try self.resolveInst(extra.lhs); |
| | 2083 | const rhs = try self.resolveInst(extra.rhs); |
| | 2084 | const lhs_ty = self.air.typeOf(extra.lhs); |
| | 2085 | const rhs_ty = self.air.typeOf(extra.rhs); |
| | 2086 | |
| | 2087 | switch (lhs_ty.zigTypeTag()) { |
| | 2088 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| | 2089 | .Int => { |
| | 2090 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2091 | if (int_info.bits <= 64) { |
| | 2092 | try self.spillConditionFlagsIfOccupied(); |
| | 2093 | |
| | 2094 | const lhs_lock: ?RegisterLock = if (lhs == .register) |
| | 2095 | self.register_manager.lockRegAssumeUnused(lhs.register) |
| | 2096 | else |
| | 2097 | null; |
| | 2098 | // TODO this currently crashes stage1 |
| | 2099 | // defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 2100 | |
| | 2101 | // Increase shift amount (i.e, rhs) by shamt_bits - int_info.bits |
| | 2102 | // e.g if shifting a i48 then use sr*x (shamt_bits == 64) but increase rhs by 16 |
| | 2103 | // and if shifting a i24 then use sr* (shamt_bits == 32) but increase rhs by 8 |
| | 2104 | const new_rhs = switch (int_info.bits) { |
| | 2105 | 1...31 => if (rhs == .immediate) MCValue{ |
| | 2106 | .immediate = rhs.immediate + 32 - int_info.bits, |
| | 2107 | } else try self.binOp(.add, rhs, .{ .immediate = 32 - int_info.bits }, rhs_ty, rhs_ty, null), |
| | 2108 | 33...63 => if (rhs == .immediate) MCValue{ |
| | 2109 | .immediate = rhs.immediate + 64 - int_info.bits, |
| | 2110 | } else try self.binOp(.add, rhs, .{ .immediate = 64 - int_info.bits }, rhs_ty, rhs_ty, null), |
| | 2111 | 32, 64 => rhs, |
| | 2112 | else => unreachable, |
| | 2113 | }; |
| | 2114 | |
| | 2115 | const new_rhs_lock: ?RegisterLock = if (new_rhs == .register) |
| | 2116 | self.register_manager.lockRegAssumeUnused(new_rhs.register) |
| | 2117 | else |
| | 2118 | null; |
| | 2119 | // TODO this currently crashes stage1 |
| | 2120 | // defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 2121 | |
| | 2122 | const dest = try self.binOp(.shl, lhs, new_rhs, lhs_ty, rhs_ty, null); |
| | 2123 | const dest_reg = dest.register; |
| | 2124 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| | 2125 | defer self.register_manager.unlockReg(dest_reg_lock); |
| | 2126 | |
| | 2127 | const shr = try self.binOp(.shr, dest, new_rhs, lhs_ty, rhs_ty, null); |
| | 2128 | |
| | 2129 | _ = try self.addInst(.{ |
| | 2130 | .tag = .cmp, |
| | 2131 | .data = .{ .arithmetic_2op = .{ |
| | 2132 | .is_imm = false, |
| | 2133 | .rs1 = dest_reg, |
| | 2134 | .rs2_or_imm = .{ .rs2 = shr.register }, |
| | 2135 | } }, |
| | 2136 | }); |
| | 2137 | |
| | 2138 | const cond = Instruction.ICondition.ne; |
| | 2139 | const ccr = switch (int_info.bits) { |
| | 2140 | 1...32 => Instruction.CCR.icc, |
| | 2141 | 33...64 => Instruction.CCR.xcc, |
| | 2142 | else => unreachable, |
| | 2143 | }; |
| | 2144 | |
| | 2145 | // TODO Those should really be written as defers, however stage1 currently |
| | 2146 | // panics when those are turned into defer statements so those are |
| | 2147 | // written here at the end as ordinary statements. |
| | 2148 | // Because of that, on failure, the lock on those registers wouldn't be |
| | 2149 | // released. |
| | 2150 | if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 2151 | if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); |
| | 2152 | |
| | 2153 | break :result MCValue{ .register_with_overflow = .{ |
| | 2154 | .reg = dest_reg, |
| | 2155 | .flag = .{ .cond = cond, .ccr = ccr }, |
| | 2156 | } }; |
| | 2157 | } else { |
| | 2158 | return self.fail("TODO overflow operations on other integer sizes", .{}); |
| | 2159 | } |
| | 2160 | }, |
| | 2161 | else => unreachable, |
| | 2162 | } |
| | 2163 | }; |
| | 2164 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| | 2165 | } |
| | 2166 | |
| 1914 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 2167 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1915 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2168 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1916 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2169 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1996,6 +2249,25 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1996,6 +2249,25 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1996 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2249 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1997 | } | 2250 | } |
| 1998 | | 2251 | |
| | 2252 | fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| | 2253 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2254 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2255 | const mcv = try self.resolveInst(ty_op.operand); |
| | 2256 | switch (mcv) { |
| | 2257 | .dead, .unreach, .none => unreachable, |
| | 2258 | .register => unreachable, // a slice doesn't fit in one register |
| | 2259 | .stack_offset => |off| { |
| | 2260 | break :result MCValue{ .stack_offset = off }; |
| | 2261 | }, |
| | 2262 | .memory => |addr| { |
| | 2263 | break :result MCValue{ .memory = addr }; |
| | 2264 | }, |
| | 2265 | else => return self.fail("TODO implement slice_len for {}", .{mcv}), |
| | 2266 | } |
| | 2267 | }; |
| | 2268 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 2269 | } |
| | 2270 | |
| 1999 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { | 2271 | fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 2000 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2272 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2001 | const ptr = try self.resolveInst(bin_op.lhs); | 2273 | const ptr = try self.resolveInst(bin_op.lhs); |
| ... | @@ -2083,11 +2355,27 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2083,11 +2355,27 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2083 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); | 2355 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); |
| 2084 | } | 2356 | } |
| 2085 | | 2357 | |
| | 2358 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| | 2359 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 2360 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); |
| | 2361 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 2362 | } |
| | 2363 | |
| 2086 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 2364 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2087 | _ = inst; | 2365 | _ = inst; |
| 2088 | return self.fail("TODO implement switch for {}", .{self.target.cpu.arch}); | 2366 | return self.fail("TODO implement switch for {}", .{self.target.cpu.arch}); |
| 2089 | } | 2367 | } |
| 2090 | | 2368 | |
| | 2369 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| | 2370 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 2371 | const operand = try self.resolveInst(un_op); |
| | 2372 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { |
| | 2373 | _ = operand; |
| | 2374 | return self.fail("TODO implement airTagName for {}", .{self.target.cpu.arch}); |
| | 2375 | }; |
| | 2376 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| | 2377 | } |
| | 2378 | |
| 2091 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { | 2379 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 2092 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 2380 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2093 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 2381 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| ... | @@ -2106,6 +2394,15 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2106,6 +2394,15 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 2106 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); | 2394 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); |
| 2107 | } | 2395 | } |
| 2108 | | 2396 | |
| | 2397 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| | 2398 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| | 2399 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| | 2400 | .dead |
| | 2401 | else |
| | 2402 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); |
| | 2403 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| | 2404 | } |
| | 2405 | |
| 2109 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 2406 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2110 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2407 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2111 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2408 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| ... | @@ -2145,6 +2442,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2145,6 +2442,20 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2145 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2442 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2146 | } | 2443 | } |
| 2147 | | 2444 | |
| | 2445 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| | 2446 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 2447 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2448 | const optional_ty = self.air.typeOfIndex(inst); |
| | 2449 | |
| | 2450 | // Optional with a zero-bit payload type is just a boolean true |
| | 2451 | if (optional_ty.abiSize(self.target.*) == 1) |
| | 2452 | break :result MCValue{ .immediate = 1 }; |
| | 2453 | |
| | 2454 | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); |
| | 2455 | }; |
| | 2456 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| | 2457 | } |
| | 2458 | |
| 2148 | // Common helper functions | 2459 | // Common helper functions |
| 2149 | | 2460 | |
| 2150 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 2461 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| ... | @@ -2264,6 +2575,10 @@ fn binOp( | ... | @@ -2264,6 +2575,10 @@ fn binOp( |
| 2264 | switch (tag) { | 2575 | switch (tag) { |
| 2265 | .add, | 2576 | .add, |
| 2266 | .sub, | 2577 | .sub, |
| | 2578 | .mul, |
| | 2579 | .bit_and, |
| | 2580 | .bit_or, |
| | 2581 | .xor, |
| 2267 | .cmp_eq, | 2582 | .cmp_eq, |
| 2268 | => { | 2583 | => { |
| 2269 | switch (lhs_ty.zigTypeTag()) { | 2584 | switch (lhs_ty.zigTypeTag()) { |
| ... | @@ -2278,12 +2593,20 @@ fn binOp( | ... | @@ -2278,12 +2593,20 @@ fn binOp( |
| 2278 | // operands | 2593 | // operands |
| 2279 | const lhs_immediate_ok = switch (tag) { | 2594 | const lhs_immediate_ok = switch (tag) { |
| 2280 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), | 2595 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| | 2596 | .mul => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| | 2597 | .bit_and => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| | 2598 | .bit_or => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| | 2599 | .xor => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2281 | .sub, .cmp_eq => false, | 2600 | .sub, .cmp_eq => false, |
| 2282 | else => unreachable, | 2601 | else => unreachable, |
| 2283 | }; | 2602 | }; |
| 2284 | const rhs_immediate_ok = switch (tag) { | 2603 | const rhs_immediate_ok = switch (tag) { |
| 2285 | .add, | 2604 | .add, |
| 2286 | .sub, | 2605 | .sub, |
| | 2606 | .mul, |
| | 2607 | .bit_and, |
| | 2608 | .bit_or, |
| | 2609 | .xor, |
| 2287 | .cmp_eq, | 2610 | .cmp_eq, |
| 2288 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), | 2611 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2289 | else => unreachable, | 2612 | else => unreachable, |
| ... | @@ -2292,6 +2615,10 @@ fn binOp( | ... | @@ -2292,6 +2615,10 @@ fn binOp( |
| 2292 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2615 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2293 | .add => .add, | 2616 | .add => .add, |
| 2294 | .sub => .sub, | 2617 | .sub => .sub, |
| | 2618 | .mul => .mulx, |
| | 2619 | .bit_and => .@"and", |
| | 2620 | .bit_or => .@"or", |
| | 2621 | .xor => .xor, |
| 2295 | .cmp_eq => .cmp, | 2622 | .cmp_eq => .cmp, |
| 2296 | else => unreachable, | 2623 | else => unreachable, |
| 2297 | }; | 2624 | }; |
| ... | @@ -2313,72 +2640,60 @@ fn binOp( | ... | @@ -2313,72 +2640,60 @@ fn binOp( |
| 2313 | } | 2640 | } |
| 2314 | }, | 2641 | }, |
| 2315 | | 2642 | |
| 2316 | .div_trunc => { | 2643 | .addwrap, |
| | 2644 | .subwrap, |
| | 2645 | .mulwrap, |
| | 2646 | => { |
| | 2647 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 2648 | .addwrap => .add, |
| | 2649 | .subwrap => .sub, |
| | 2650 | .mulwrap => .mul, |
| | 2651 | else => unreachable, |
| | 2652 | }; |
| | 2653 | |
| | 2654 | // Generate the base operation |
| | 2655 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| | 2656 | |
| | 2657 | // Truncate if necessary |
| 2317 | switch (lhs_ty.zigTypeTag()) { | 2658 | switch (lhs_ty.zigTypeTag()) { |
| 2318 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2659 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2319 | .Int => { | 2660 | .Int => { |
| 2320 | assert(lhs_ty.eql(rhs_ty, mod)); | | |
| 2321 | const int_info = lhs_ty.intInfo(self.target.*); | 2661 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2322 | if (int_info.bits <= 64) { | 2662 | if (int_info.bits <= 64) { |
| 2323 | const rhs_immediate_ok = switch (tag) { | 2663 | const result_reg = result.register; |
| 2324 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), | 2664 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 2325 | else => unreachable, | 2665 | return result; |
| 2326 | }; | | |
| 2327 | | | |
| 2328 | const mir_tag: Mir.Inst.Tag = switch (tag) { | | |
| 2329 | .div_trunc => switch (int_info.signedness) { | | |
| 2330 | .signed => Mir.Inst.Tag.sdivx, | | |
| 2331 | .unsigned => Mir.Inst.Tag.udivx, | | |
| 2332 | }, | | |
| 2333 | else => unreachable, | | |
| 2334 | }; | | |
| 2335 | | | |
| 2336 | if (rhs_immediate_ok) { | | |
| 2337 | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata); | | |
| 2338 | } else { | | |
| 2339 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 2340 | } | | |
| 2341 | } else { | 2666 | } else { |
| 2342 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 2667 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| 2343 | } | 2668 | } |
| 2344 | }, | 2669 | }, |
| 2345 | else => unreachable, | 2670 | else => unreachable, |
| 2346 | } | 2671 | } |
| 2347 | }, | 2672 | }, |
| 2348 | | 2673 | |
| 2349 | .mul => { | 2674 | .div_trunc => { |
| 2350 | switch (lhs_ty.zigTypeTag()) { | 2675 | switch (lhs_ty.zigTypeTag()) { |
| 2351 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2676 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2352 | .Int => { | 2677 | .Int => { |
| 2353 | assert(lhs_ty.eql(rhs_ty, mod)); | 2678 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2354 | const int_info = lhs_ty.intInfo(self.target.*); | 2679 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2355 | if (int_info.bits <= 64) { | 2680 | if (int_info.bits <= 64) { |
| 2356 | // Only say yes if the operation is | | |
| 2357 | // commutative, i.e. we can swap both of the | | |
| 2358 | // operands | | |
| 2359 | const lhs_immediate_ok = switch (tag) { | | |
| 2360 | .mul => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), | | |
| 2361 | else => unreachable, | | |
| 2362 | }; | | |
| 2363 | const rhs_immediate_ok = switch (tag) { | 2681 | const rhs_immediate_ok = switch (tag) { |
| 2364 | .mul => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), | 2682 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2365 | else => unreachable, | 2683 | else => unreachable, |
| 2366 | }; | 2684 | }; |
| 2367 | | 2685 | |
| 2368 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2686 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2369 | .mul => .mulx, | 2687 | .div_trunc => switch (int_info.signedness) { |
| | 2688 | .signed => Mir.Inst.Tag.sdivx, |
| | 2689 | .unsigned => Mir.Inst.Tag.udivx, |
| | 2690 | }, |
| 2370 | else => unreachable, | 2691 | else => unreachable, |
| 2371 | }; | 2692 | }; |
| 2372 | | 2693 | |
| 2373 | if (rhs_immediate_ok) { | 2694 | if (rhs_immediate_ok) { |
| 2374 | // At this point, rhs is an immediate | 2695 | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata); |
| 2375 | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata); | | |
| 2376 | } else if (lhs_immediate_ok) { | | |
| 2377 | // swap lhs and rhs | | |
| 2378 | // At this point, lhs is an immediate | | |
| 2379 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | | |
| 2380 | } else { | 2696 | } else { |
| 2381 | // TODO convert large immediates to register before adding | | |
| 2382 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | 2697 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2383 | } | 2698 | } |
| 2384 | } else { | 2699 | } else { |
| ... | @@ -2419,88 +2734,61 @@ fn binOp( | ... | @@ -2419,88 +2734,61 @@ fn binOp( |
| 2419 | } | 2734 | } |
| 2420 | }, | 2735 | }, |
| 2421 | | 2736 | |
| 2422 | .bit_and, | 2737 | .bool_and, |
| 2423 | .bit_or, | 2738 | .bool_or, |
| 2424 | .xor, | | |
| 2425 | => { | 2739 | => { |
| 2426 | switch (lhs_ty.zigTypeTag()) { | 2740 | switch (lhs_ty.zigTypeTag()) { |
| 2427 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2741 | .Bool => { |
| 2428 | .Int => { | 2742 | assert(lhs != .immediate); // should have been handled by Sema |
| 2429 | assert(lhs_ty.eql(rhs_ty, mod)); | 2743 | assert(rhs != .immediate); // should have been handled by Sema |
| 2430 | const int_info = lhs_ty.intInfo(self.target.*); | 2744 | |
| 2431 | if (int_info.bits <= 64) { | 2745 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2432 | // Only say yes if the operation is | 2746 | .bool_and => .@"and", |
| 2433 | // commutative, i.e. we can swap both of the | 2747 | .bool_or => .@"or", |
| 2434 | // operands | 2748 | else => unreachable, |
| 2435 | const lhs_immediate_ok = switch (tag) { | 2749 | }; |
| 2436 | .bit_and, | | |
| 2437 | .bit_or, | | |
| 2438 | .xor, | | |
| 2439 | => lhs == .immediate and lhs.immediate <= std.math.maxInt(u13), | | |
| 2440 | else => unreachable, | | |
| 2441 | }; | | |
| 2442 | const rhs_immediate_ok = switch (tag) { | | |
| 2443 | .bit_and, | | |
| 2444 | .bit_or, | | |
| 2445 | .xor, | | |
| 2446 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u13), | | |
| 2447 | else => unreachable, | | |
| 2448 | }; | | |
| 2449 | | | |
| 2450 | const mir_tag: Mir.Inst.Tag = switch (tag) { | | |
| 2451 | .bit_and => .@"and", | | |
| 2452 | .bit_or => .@"or", | | |
| 2453 | .xor => .xor, | | |
| 2454 | else => unreachable, | | |
| 2455 | }; | | |
| 2456 | | 2750 | |
| 2457 | if (rhs_immediate_ok) { | 2751 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2458 | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata); | | |
| 2459 | } else if (lhs_immediate_ok) { | | |
| 2460 | // swap lhs and rhs | | |
| 2461 | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); | | |
| 2462 | } else { | | |
| 2463 | // TODO convert large immediates to register before adding | | |
| 2464 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 2465 | } | | |
| 2466 | } else { | | |
| 2467 | return self.fail("TODO binary operations on int with bits > 64", .{}); | | |
| 2468 | } | | |
| 2469 | }, | 2752 | }, |
| 2470 | else => unreachable, | 2753 | else => unreachable, |
| 2471 | } | 2754 | } |
| 2472 | }, | 2755 | }, |
| 2473 | | 2756 | |
| 2474 | .shl => { | 2757 | .shl, |
| | 2758 | .shr, |
| | 2759 | => { |
| 2475 | const base_tag: Air.Inst.Tag = switch (tag) { | 2760 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2476 | .shl => .shl_exact, | 2761 | .shl => .shl_exact, |
| | 2762 | .shr => .shr_exact, |
| 2477 | else => unreachable, | 2763 | else => unreachable, |
| 2478 | }; | 2764 | }; |
| 2479 | | 2765 | |
| 2480 | // Generate a shl_exact/shr_exact | 2766 | // Generate the base operation |
| 2481 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | 2767 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2482 | | 2768 | |
| 2483 | // Truncate if necessary | 2769 | // Truncate if necessary |
| 2484 | switch (tag) { | 2770 | switch (lhs_ty.zigTypeTag()) { |
| 2485 | .shl => switch (lhs_ty.zigTypeTag()) { | 2771 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2486 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2772 | .Int => { |
| 2487 | .Int => { | 2773 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2488 | const int_info = lhs_ty.intInfo(self.target.*); | 2774 | if (int_info.bits <= 64) { |
| 2489 | if (int_info.bits <= 64) { | 2775 | // 32 and 64 bit operands doesn't need truncating |
| 2490 | const result_reg = result.register; | 2776 | if (int_info.bits == 32 or int_info.bits == 64) return result; |
| 2491 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); | 2777 | |
| 2492 | return result; | 2778 | const result_reg = result.register; |
| 2493 | } else { | 2779 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| 2494 | return self.fail("TODO binary operations on integers > u64/i64", .{}); | 2780 | return result; |
| 2495 | } | 2781 | } else { |
| 2496 | }, | 2782 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| 2497 | else => unreachable, | 2783 | } |
| 2498 | }, | 2784 | }, |
| 2499 | else => unreachable, | 2785 | else => unreachable, |
| 2500 | } | 2786 | } |
| 2501 | }, | 2787 | }, |
| 2502 | | 2788 | |
| 2503 | .shl_exact => { | 2789 | .shl_exact, |
| | 2790 | .shr_exact, |
| | 2791 | => { |
| 2504 | switch (lhs_ty.zigTypeTag()) { | 2792 | switch (lhs_ty.zigTypeTag()) { |
| 2505 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2793 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2506 | .Int => { | 2794 | .Int => { |
| ... | @@ -2509,7 +2797,11 @@ fn binOp( | ... | @@ -2509,7 +2797,11 @@ fn binOp( |
| 2509 | const rhs_immediate_ok = rhs == .immediate; | 2797 | const rhs_immediate_ok = rhs == .immediate; |
| 2510 | | 2798 | |
| 2511 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2799 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 2512 | .shl_exact => .sllx, | 2800 | .shl_exact => if (int_info.bits <= 32) Mir.Inst.Tag.sll else Mir.Inst.Tag.sllx, |
| | 2801 | .shr_exact => switch (int_info.signedness) { |
| | 2802 | .signed => if (int_info.bits <= 32) Mir.Inst.Tag.sra else Mir.Inst.Tag.srax, |
| | 2803 | .unsigned => if (int_info.bits <= 32) Mir.Inst.Tag.srl else Mir.Inst.Tag.srlx, |
| | 2804 | }, |
| 2513 | else => unreachable, | 2805 | else => unreachable, |
| 2514 | }; | 2806 | }; |
| 2515 | | 2807 | |
| ... | @@ -2616,7 +2908,21 @@ fn binOpImmediate( | ... | @@ -2616,7 +2908,21 @@ fn binOpImmediate( |
| 2616 | .rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) }, | 2908 | .rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) }, |
| 2617 | }, | 2909 | }, |
| 2618 | }, | 2910 | }, |
| 2619 | .sllx => .{ | 2911 | .sll, |
| | 2912 | .srl, |
| | 2913 | .sra, |
| | 2914 | => .{ |
| | 2915 | .shift = .{ |
| | 2916 | .is_imm = true, |
| | 2917 | .rd = dest_reg, |
| | 2918 | .rs1 = lhs_reg, |
| | 2919 | .rs2_or_imm = .{ .imm = @intCast(u5, rhs.immediate) }, |
| | 2920 | }, |
| | 2921 | }, |
| | 2922 | .sllx, |
| | 2923 | .srlx, |
| | 2924 | .srax, |
| | 2925 | => .{ |
| 2620 | .shift = .{ | 2926 | .shift = .{ |
| 2621 | .is_imm = true, | 2927 | .is_imm = true, |
| 2622 | .rd = dest_reg, | 2928 | .rd = dest_reg, |
| ... | @@ -2740,7 +3046,13 @@ fn binOpRegister( | ... | @@ -2740,7 +3046,13 @@ fn binOpRegister( |
| 2740 | .rs2_or_imm = .{ .rs2 = rhs_reg }, | 3046 | .rs2_or_imm = .{ .rs2 = rhs_reg }, |
| 2741 | }, | 3047 | }, |
| 2742 | }, | 3048 | }, |
| 2743 | .sllx => .{ | 3049 | .sll, |
| | 3050 | .srl, |
| | 3051 | .sra, |
| | 3052 | .sllx, |
| | 3053 | .srlx, |
| | 3054 | .srax, |
| | 3055 | => .{ |
| 2744 | .shift = .{ | 3056 | .shift = .{ |
| 2745 | .is_imm = false, | 3057 | .is_imm = false, |
| 2746 | .rd = dest_reg, | 3058 | .rd = dest_reg, |