| ... | @@ -3526,6 +3526,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3526,6 +3526,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3526 | return CValue.none; | 3526 | return CValue.none; |
| 3527 | } | 3527 | } |
| 3528 | | 3528 | |
| | 3529 | fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { |
| | 3530 | return switch (constraint[0]) { |
| | 3531 | '{' => true, |
| | 3532 | 'i', 'r' => false, |
| | 3533 | else => value == .constant, |
| | 3534 | }; |
| | 3535 | } |
| | 3536 | |
| 3529 | fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | 3537 | fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3530 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3538 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3531 | const extra = f.air.extraData(Air.Asm, ty_pl.payload); | 3539 | const extra = f.air.extraData(Air.Asm, ty_pl.payload); |
| ... | @@ -3551,10 +3559,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3551,10 +3559,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3551 | break :local local; | 3559 | break :local local; |
| 3552 | } else .none; | 3560 | } else .none; |
| 3553 | | 3561 | |
| 3554 | const output_locals_begin = f.next_local_index; | 3562 | const locals_begin = f.next_local_index; |
| 3555 | f.next_local_index += outputs.len; | | |
| 3556 | const constraints_extra_begin = extra_i; | 3563 | const constraints_extra_begin = extra_i; |
| 3557 | for (outputs) |output, index| { | 3564 | for (outputs) |output| { |
| 3558 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); | 3565 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3559 | const constraint = std.mem.sliceTo(extra_bytes, 0); | 3566 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| 3560 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 3567 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| ... | @@ -3562,12 +3569,17 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3562,12 +3569,17 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3562 | // for the string, we still use the next u32 for the null terminator. | 3569 | // for the string, we still use the next u32 for the null terminator. |
| 3563 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 3570 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 3564 | | 3571 | |
| 3565 | const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType(); | 3572 | if (constraint.len < 2 or constraint[0] != '=' or |
| 3566 | if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) { | 3573 | (constraint[1] == '{' and constraint[constraint.len - 1] != '}')) |
| | 3574 | { |
| | 3575 | return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); |
| | 3576 | } |
| | 3577 | |
| | 3578 | const is_reg = constraint[1] == '{'; |
| | 3579 | if (is_reg) { |
| | 3580 | const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType(); |
| 3567 | try writer.writeAll("register "); | 3581 | try writer.writeAll("register "); |
| 3568 | try f.object.dg.renderTypeAndName(writer, output_ty, .{ | 3582 | _ = try f.allocLocal(output_ty, .Mut); |
| 3569 | .local = output_locals_begin + index, | | |
| 3570 | }, .Mut, 0); | | |
| 3571 | try writer.writeAll(" __asm(\""); | 3583 | try writer.writeAll(" __asm(\""); |
| 3572 | try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); | 3584 | try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); |
| 3573 | try writer.writeAll("\")"); | 3585 | try writer.writeAll("\")"); |
| ... | @@ -3576,13 +3588,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3576,13 +3588,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3576 | try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer); | 3588 | try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer); |
| 3577 | } | 3589 | } |
| 3578 | try writer.writeAll(";\n"); | 3590 | try writer.writeAll(";\n"); |
| 3579 | } else if (constraint.len < 2 or constraint[0] != '=') { | | |
| 3580 | return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); | | |
| 3581 | } | 3591 | } |
| 3582 | } | 3592 | } |
| 3583 | const input_locals_begin = f.next_local_index; | 3593 | for (inputs) |input| { |
| 3584 | f.next_local_index += inputs.len; | | |
| 3585 | for (inputs) |input, index| { | | |
| 3586 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); | 3594 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3587 | const constraint = std.mem.sliceTo(extra_bytes, 0); | 3595 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| 3588 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 3596 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| ... | @@ -3590,30 +3598,27 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3590,30 +3598,27 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3590 | // for the string, we still use the next u32 for the null terminator. | 3598 | // for the string, we still use the next u32 for the null terminator. |
| 3591 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 3599 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 3592 | | 3600 | |
| 3593 | const input_ty = f.air.typeOf(input); | 3601 | if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or |
| 3594 | if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) { | 3602 | (constraint[0] == '{' and constraint[constraint.len - 1] != '}')) |
| 3595 | try writer.writeAll("register "); | 3603 | { |
| 3596 | try f.object.dg.renderTypeAndName(writer, input_ty, .{ | | |
| 3597 | .local = input_locals_begin + index, | | |
| 3598 | }, .Const, 0); | | |
| 3599 | try writer.writeAll(" __asm(\""); | | |
| 3600 | try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); | | |
| 3601 | try writer.writeAll("\") = "); | | |
| 3602 | try f.writeCValue(writer, try f.resolveInst(input), .Initializer); | | |
| 3603 | try writer.writeAll(";\n"); | | |
| 3604 | } else if (constraint.len >= 1 and std.mem.indexOfScalar(u8, "=+&%", constraint[0]) == null) { | | |
| 3605 | const input_val = try f.resolveInst(input); | | |
| 3606 | if (input_val == .constant) { | | |
| 3607 | try f.object.dg.renderTypeAndName(writer, input_ty, .{ | | |
| 3608 | .local = input_locals_begin + index, | | |
| 3609 | }, .Const, 0); | | |
| 3610 | try writer.writeAll(" = "); | | |
| 3611 | try f.writeCValue(writer, input_val, .Initializer); | | |
| 3612 | try writer.writeAll(";\n"); | | |
| 3613 | } | | |
| 3614 | } else { | | |
| 3615 | return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); | 3604 | return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); |
| 3616 | } | 3605 | } |
| | 3606 | |
| | 3607 | const is_reg = constraint[0] == '{'; |
| | 3608 | const input_val = try f.resolveInst(input); |
| | 3609 | if (asmInputNeedsLocal(constraint, input_val)) { |
| | 3610 | const input_ty = f.air.typeOf(input); |
| | 3611 | if (is_reg) try writer.writeAll("register "); |
| | 3612 | _ = try f.allocLocal(input_ty, .Const); |
| | 3613 | if (is_reg) { |
| | 3614 | try writer.writeAll(" __asm(\""); |
| | 3615 | try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); |
| | 3616 | try writer.writeAll("\")"); |
| | 3617 | } |
| | 3618 | try writer.writeAll(" = "); |
| | 3619 | try f.writeCValue(writer, input_val, .Initializer); |
| | 3620 | try writer.writeAll(";\n"); |
| | 3621 | } |
| 3617 | } | 3622 | } |
| 3618 | { | 3623 | { |
| 3619 | var clobber_i: u32 = 0; | 3624 | var clobber_i: u32 = 0; |
| ... | @@ -3631,6 +3636,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3631,6 +3636,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3631 | try writer.print("({s}", .{fmtStringLiteral(asm_source)}); | 3636 | try writer.print("({s}", .{fmtStringLiteral(asm_source)}); |
| 3632 | | 3637 | |
| 3633 | extra_i = constraints_extra_begin; | 3638 | extra_i = constraints_extra_begin; |
| | 3639 | var locals_index = locals_begin; |
| 3634 | try writer.writeByte(':'); | 3640 | try writer.writeByte(':'); |
| 3635 | for (outputs) |output, index| { | 3641 | for (outputs) |output, index| { |
| 3636 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); | 3642 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| ... | @@ -3642,11 +3648,13 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3642,11 +3648,13 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3642 | | 3648 | |
| 3643 | if (index > 0) try writer.writeByte(','); | 3649 | if (index > 0) try writer.writeByte(','); |
| 3644 | try writer.writeByte(' '); | 3650 | try writer.writeByte(' '); |
| 3645 | if (constraint[1] == '{') { | 3651 | if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); |
| 3646 | try writer.print("{s}(", .{fmtStringLiteral("=r")}); | 3652 | const is_reg = constraint[1] == '{'; |
| 3647 | try f.writeCValue(writer, .{ .local = output_locals_begin + index }, .Other); | 3653 | try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)}); |
| | 3654 | if (is_reg) { |
| | 3655 | try f.writeCValue(writer, .{ .local = locals_index }, .Other); |
| | 3656 | locals_index += 1; |
| 3648 | } else { | 3657 | } else { |
| 3649 | try writer.print("{s}(", .{fmtStringLiteral(constraint)}); | | |
| 3650 | try f.writeCValueDeref(writer, try f.resolveInst(output)); | 3658 | try f.writeCValueDeref(writer, try f.resolveInst(output)); |
| 3651 | } | 3659 | } |
| 3652 | try writer.writeByte(')'); | 3660 | try writer.writeByte(')'); |
| ... | @@ -3662,17 +3670,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3662,17 +3670,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3662 | | 3670 | |
| 3663 | if (index > 0) try writer.writeByte(','); | 3671 | if (index > 0) try writer.writeByte(','); |
| 3664 | try writer.writeByte(' '); | 3672 | try writer.writeByte(' '); |
| 3665 | if (constraint[0] == '{') { | 3673 | if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); |
| 3666 | try writer.print("{s}(", .{fmtStringLiteral("r")}); | 3674 | |
| 3667 | try f.writeCValue(writer, .{ .local = input_locals_begin + index }, .Other); | 3675 | const is_reg = constraint[0] == '{'; |
| 3668 | } else { | 3676 | const input_val = try f.resolveInst(input); |
| 3669 | const input_val = try f.resolveInst(input); | 3677 | try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)}); |
| 3670 | try writer.print("{s}(", .{fmtStringLiteral(constraint)}); | 3678 | try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: { |
| 3671 | try f.writeCValue(writer, if (input_val == .constant) | 3679 | const input_local = CValue{ .local = locals_index }; |
| 3672 | CValue{ .local = input_locals_begin + index } | 3680 | locals_index += 1; |
| 3673 | else | 3681 | break :local input_local; |
| 3674 | input_val, .Other); | 3682 | } else input_val, .Other); |
| 3675 | } | | |
| 3676 | try writer.writeByte(')'); | 3683 | try writer.writeByte(')'); |
| 3677 | } | 3684 | } |
| 3678 | try writer.writeByte(':'); | 3685 | try writer.writeByte(':'); |
| ... | @@ -3693,7 +3700,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3693,7 +3700,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3693 | try writer.writeAll(");\n"); | 3700 | try writer.writeAll(");\n"); |
| 3694 | | 3701 | |
| 3695 | extra_i = constraints_extra_begin; | 3702 | extra_i = constraints_extra_begin; |
| 3696 | for (outputs) |output, index| { | 3703 | locals_index = locals_begin; |
| | 3704 | for (outputs) |output| { |
| 3697 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); | 3705 | const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); |
| 3698 | const constraint = std.mem.sliceTo(extra_bytes, 0); | 3706 | const constraint = std.mem.sliceTo(extra_bytes, 0); |
| 3699 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | 3707 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); |
| ... | @@ -3701,13 +3709,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3701,13 +3709,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3701 | // for the string, we still use the next u32 for the null terminator. | 3709 | // for the string, we still use the next u32 for the null terminator. |
| 3702 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 3710 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 3703 | | 3711 | |
| 3704 | if (constraint[1] == '{') { | 3712 | const is_reg = constraint[1] == '{'; |
| | 3713 | if (is_reg) { |
| 3705 | try f.writeCValueDeref(writer, if (output == .none) | 3714 | try f.writeCValueDeref(writer, if (output == .none) |
| 3706 | CValue{ .local_ref = local.local } | 3715 | CValue{ .local_ref = local.local } |
| 3707 | else | 3716 | else |
| 3708 | try f.resolveInst(output)); | 3717 | try f.resolveInst(output)); |
| 3709 | try writer.writeAll(" = "); | 3718 | try writer.writeAll(" = "); |
| 3710 | try f.writeCValue(writer, .{ .local = output_locals_begin + index }, .Other); | 3719 | try f.writeCValue(writer, .{ .local = locals_index }, .Other); |
| | 3720 | locals_index += 1; |
| 3711 | try writer.writeAll(";\n"); | 3721 | try writer.writeAll(";\n"); |
| 3712 | } | 3722 | } |
| 3713 | } | 3723 | } |