| ... | @@ -376,7 +376,7 @@ fn gen(self: *Self) !void { | ... | @@ -376,7 +376,7 @@ fn gen(self: *Self) !void { |
| 376 | // mov fp, sp | 376 | // mov fp, sp |
| 377 | _ = try self.addInst(.{ | 377 | _ = try self.addInst(.{ |
| 378 | .tag = .mov_to_from_sp, | 378 | .tag = .mov_to_from_sp, |
| 379 | .data = .{ .rr = .{ .rd = .x29, .rn = .xzr } }, | 379 | .data = .{ .rr = .{ .rd = .x29, .rn = .sp } }, |
| 380 | }); | 380 | }); |
| 381 | | 381 | |
| 382 | // sub sp, sp, #reloc | 382 | // sub sp, sp, #reloc |
| ... | @@ -421,7 +421,7 @@ fn gen(self: *Self) !void { | ... | @@ -421,7 +421,7 @@ fn gen(self: *Self) !void { |
| 421 | if (math.cast(u12, stack_size)) |size| { | 421 | if (math.cast(u12, stack_size)) |size| { |
| 422 | self.mir_instructions.set(backpatch_reloc, .{ | 422 | self.mir_instructions.set(backpatch_reloc, .{ |
| 423 | .tag = .sub_immediate, | 423 | .tag = .sub_immediate, |
| 424 | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = size } }, | 424 | .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = size } }, |
| 425 | }); | 425 | }); |
| 426 | } else |_| { | 426 | } else |_| { |
| 427 | return self.failSymbol("TODO AArch64: allow larger stacks", .{}); | 427 | return self.failSymbol("TODO AArch64: allow larger stacks", .{}); |
| ... | @@ -453,7 +453,7 @@ fn gen(self: *Self) !void { | ... | @@ -453,7 +453,7 @@ fn gen(self: *Self) !void { |
| 453 | // add sp, sp, #stack_size | 453 | // add sp, sp, #stack_size |
| 454 | _ = try self.addInst(.{ | 454 | _ = try self.addInst(.{ |
| 455 | .tag = .add_immediate, | 455 | .tag = .add_immediate, |
| 456 | .data = .{ .rr_imm12_sh = .{ .rd = .xzr, .rn = .xzr, .imm12 = @intCast(u12, stack_size) } }, | 456 | .data = .{ .rr_imm12_sh = .{ .rd = .sp, .rn = .sp, .imm12 = @intCast(u12, stack_size) } }, |
| 457 | }); | 457 | }); |
| 458 | | 458 | |
| 459 | // <load other registers> | 459 | // <load other registers> |
| ... | @@ -512,13 +512,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -512,13 +512,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 512 | switch (air_tags[inst]) { | 512 | switch (air_tags[inst]) { |
| 513 | // zig fmt: off | 513 | // zig fmt: off |
| 514 | .add, .ptr_add => try self.airBinOp(inst), | 514 | .add, .ptr_add => try self.airBinOp(inst), |
| 515 | .addwrap => try self.airAddWrap(inst), | 515 | .addwrap => try self.airBinOp(inst), |
| 516 | .add_sat => try self.airAddSat(inst), | 516 | .add_sat => try self.airAddSat(inst), |
| 517 | .sub, .ptr_sub => try self.airBinOp(inst), | 517 | .sub, .ptr_sub => try self.airBinOp(inst), |
| 518 | .subwrap => try self.airSubWrap(inst), | 518 | .subwrap => try self.airBinOp(inst), |
| 519 | .sub_sat => try self.airSubSat(inst), | 519 | .sub_sat => try self.airSubSat(inst), |
| 520 | .mul => try self.airBinOp(inst), | 520 | .mul => try self.airBinOp(inst), |
| 521 | .mulwrap => try self.airMulWrap(inst), | 521 | .mulwrap => try self.airBinOp(inst), |
| 522 | .mul_sat => try self.airMulSat(inst), | 522 | .mul_sat => try self.airMulSat(inst), |
| 523 | .rem => try self.airRem(inst), | 523 | .rem => try self.airRem(inst), |
| 524 | .mod => try self.airMod(inst), | 524 | .mod => try self.airMod(inst), |
| ... | @@ -882,7 +882,8 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -882,7 +882,8 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 882 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 882 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 883 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 883 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 884 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 884 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 885 | const reg = try self.register_manager.allocReg(null); | 885 | const raw_reg = try self.register_manager.allocReg(null); |
| | 886 | const reg = registerAlias(raw_reg, ty.abiSize(self.target.*)); |
| 886 | try self.genSetReg(ty, reg, mcv); | 887 | try self.genSetReg(ty, reg, mcv); |
| 887 | return reg; | 888 | return reg; |
| 888 | } | 889 | } |
| ... | @@ -891,7 +892,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -891,7 +892,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 891 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 892 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 892 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 893 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 893 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 894 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 894 | const reg = try self.register_manager.allocReg(reg_owner); | 895 | const raw_reg = try self.register_manager.allocReg(reg_owner); |
| | 896 | const ty = self.air.typeOfIndex(reg_owner); |
| | 897 | const reg = registerAlias(raw_reg, ty.abiSize(self.target.*)); |
| 895 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 898 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 896 | return MCValue{ .register = reg }; | 899 | return MCValue{ .register = reg }; |
| 897 | } | 900 | } |
| ... | @@ -936,14 +939,99 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -936,14 +939,99 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 936 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); | 939 | return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch}); |
| 937 | } | 940 | } |
| 938 | | 941 | |
| | 942 | fn truncRegister( |
| | 943 | self: *Self, |
| | 944 | operand_reg: Register, |
| | 945 | dest_reg: Register, |
| | 946 | int_signedness: std.builtin.Signedness, |
| | 947 | int_bits: u16, |
| | 948 | ) !void { |
| | 949 | switch (int_bits) { |
| | 950 | 1...31, 33...63 => { |
| | 951 | _ = try self.addInst(.{ |
| | 952 | .tag = switch (int_signedness) { |
| | 953 | .signed => .sbfx, |
| | 954 | .unsigned => .ubfx, |
| | 955 | }, |
| | 956 | .data = .{ .rr_lsb_width = .{ |
| | 957 | .rd = dest_reg, |
| | 958 | .rn = operand_reg, |
| | 959 | .lsb = 0, |
| | 960 | .width = @intCast(u6, int_bits), |
| | 961 | } }, |
| | 962 | }); |
| | 963 | }, |
| | 964 | 32, 64 => { |
| | 965 | _ = try self.addInst(.{ |
| | 966 | .tag = .mov_register, |
| | 967 | .data = .{ .rr = .{ |
| | 968 | .rd = dest_reg, |
| | 969 | .rn = operand_reg, |
| | 970 | } }, |
| | 971 | }); |
| | 972 | }, |
| | 973 | else => unreachable, |
| | 974 | } |
| | 975 | } |
| | 976 | |
| | 977 | fn trunc( |
| | 978 | self: *Self, |
| | 979 | maybe_inst: ?Air.Inst.Index, |
| | 980 | operand: MCValue, |
| | 981 | operand_ty: Type, |
| | 982 | dest_ty: Type, |
| | 983 | ) !MCValue { |
| | 984 | const info_a = operand_ty.intInfo(self.target.*); |
| | 985 | const info_b = dest_ty.intInfo(self.target.*); |
| | 986 | |
| | 987 | if (info_b.bits <= 64) { |
| | 988 | const operand_reg = switch (operand) { |
| | 989 | .register => |r| r, |
| | 990 | else => operand_reg: { |
| | 991 | if (info_a.bits <= 64) { |
| | 992 | const raw_reg = try self.copyToTmpRegister(operand_ty, operand); |
| | 993 | break :operand_reg registerAlias(raw_reg, operand_ty.abiSize(self.target.*)); |
| | 994 | } else { |
| | 995 | return self.fail("TODO load least significant word into register", .{}); |
| | 996 | } |
| | 997 | }, |
| | 998 | }; |
| | 999 | self.register_manager.freezeRegs(&.{operand_reg}); |
| | 1000 | defer self.register_manager.unfreezeRegs(&.{operand_reg}); |
| | 1001 | |
| | 1002 | const dest_reg = if (maybe_inst) |inst| blk: { |
| | 1003 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1004 | |
| | 1005 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| | 1006 | break :blk registerAlias(operand_reg, dest_ty.abiSize(self.target.*)); |
| | 1007 | } else { |
| | 1008 | const raw_reg = try self.register_manager.allocReg(inst); |
| | 1009 | break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*)); |
| | 1010 | } |
| | 1011 | } else blk: { |
| | 1012 | const raw_reg = try self.register_manager.allocReg(null); |
| | 1013 | break :blk registerAlias(raw_reg, dest_ty.abiSize(self.target.*)); |
| | 1014 | }; |
| | 1015 | |
| | 1016 | try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits); |
| | 1017 | |
| | 1018 | return MCValue{ .register = dest_reg }; |
| | 1019 | } else { |
| | 1020 | return self.fail("TODO: truncate to ints > 32 bits", .{}); |
| | 1021 | } |
| | 1022 | } |
| | 1023 | |
| 939 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1024 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 940 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1025 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 941 | if (self.liveness.isUnused(inst)) | | |
| 942 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | | |
| 943 | | | |
| 944 | const operand = try self.resolveInst(ty_op.operand); | 1026 | const operand = try self.resolveInst(ty_op.operand); |
| 945 | _ = operand; | 1027 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 946 | return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch}); | 1028 | const dest_ty = self.air.typeOfIndex(inst); |
| | 1029 | |
| | 1030 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| | 1031 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); |
| | 1032 | }; |
| | 1033 | |
| | 1034 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 947 | } | 1035 | } |
| 948 | | 1036 | |
| 949 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 1037 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1003,7 +1091,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1003,7 +1091,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1003 | break :blk op_reg; | 1091 | break :blk op_reg; |
| 1004 | } | 1092 | } |
| 1005 | | 1093 | |
| 1006 | break :blk try self.register_manager.allocReg(null); | 1094 | const raw_reg = try self.register_manager.allocReg(null); |
| | 1095 | break :blk raw_reg.to32(); |
| 1007 | }; | 1096 | }; |
| 1008 | | 1097 | |
| 1009 | _ = try self.addInst(.{ | 1098 | _ = try self.addInst(.{ |
| ... | @@ -1013,7 +1102,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1013,7 +1102,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1013 | .rn = op_reg, | 1102 | .rn = op_reg, |
| 1014 | .imms = 0b000000, | 1103 | .imms = 0b000000, |
| 1015 | .immr = 0b000000, | 1104 | .immr = 0b000000, |
| 1016 | .n = 0b1, | 1105 | .n = 0b0, |
| 1017 | } }, | 1106 | } }, |
| 1018 | }); | 1107 | }); |
| 1019 | | 1108 | |
| ... | @@ -1035,7 +1124,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1035,7 +1124,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1035 | break :blk op_reg; | 1124 | break :blk op_reg; |
| 1036 | } | 1125 | } |
| 1037 | | 1126 | |
| 1038 | break :blk try self.register_manager.allocReg(null); | 1127 | const raw_reg = try self.register_manager.allocReg(null); |
| | 1128 | break :blk registerAlias(raw_reg, operand_ty.abiSize(self.target.*)); |
| 1039 | }; | 1129 | }; |
| 1040 | | 1130 | |
| 1041 | _ = try self.addInst(.{ | 1131 | _ = try self.addInst(.{ |
| ... | @@ -1048,6 +1138,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1048,6 +1138,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1048 | } }, | 1138 | } }, |
| 1049 | }); | 1139 | }); |
| 1050 | | 1140 | |
| | 1141 | try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); |
| | 1142 | |
| 1051 | break :result MCValue{ .register = dest_reg }; | 1143 | break :result MCValue{ .register = dest_reg }; |
| 1052 | } else { | 1144 | } else { |
| 1053 | return self.fail("TODO AArch64 not on integers > u64/i64", .{}); | 1145 | return self.fail("TODO AArch64 not on integers > u64/i64", .{}); |
| ... | @@ -1103,7 +1195,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1103,7 +1195,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1103 | /// Asserts that generating an instruction of that form is possible. | 1195 | /// Asserts that generating an instruction of that form is possible. |
| 1104 | fn binOpRegister( | 1196 | fn binOpRegister( |
| 1105 | self: *Self, | 1197 | self: *Self, |
| 1106 | tag: Air.Inst.Tag, | 1198 | mir_tag: Mir.Inst.Tag, |
| 1107 | maybe_inst: ?Air.Inst.Index, | 1199 | maybe_inst: ?Air.Inst.Index, |
| 1108 | lhs: MCValue, | 1200 | lhs: MCValue, |
| 1109 | rhs: MCValue, | 1201 | rhs: MCValue, |
| ... | @@ -1124,7 +1216,8 @@ fn binOpRegister( | ... | @@ -1124,7 +1216,8 @@ fn binOpRegister( |
| 1124 | break :inst Air.refToIndex(bin_op.lhs).?; | 1216 | break :inst Air.refToIndex(bin_op.lhs).?; |
| 1125 | } else null; | 1217 | } else null; |
| 1126 | | 1218 | |
| 1127 | const reg = try self.register_manager.allocReg(track_inst); | 1219 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| | 1220 | const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1128 | self.register_manager.freezeRegs(&.{reg}); | 1221 | self.register_manager.freezeRegs(&.{reg}); |
| 1129 | | 1222 | |
| 1130 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 1223 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | @@ -1139,7 +1232,8 @@ fn binOpRegister( | ... | @@ -1139,7 +1232,8 @@ fn binOpRegister( |
| 1139 | break :inst Air.refToIndex(bin_op.rhs).?; | 1232 | break :inst Air.refToIndex(bin_op.rhs).?; |
| 1140 | } else null; | 1233 | } else null; |
| 1141 | | 1234 | |
| 1142 | const reg = try self.register_manager.allocReg(track_inst); | 1235 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| | 1236 | const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*)); |
| 1143 | self.register_manager.freezeRegs(&.{reg}); | 1237 | self.register_manager.freezeRegs(&.{reg}); |
| 1144 | | 1238 | |
| 1145 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 1239 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | @@ -1156,45 +1250,17 @@ fn binOpRegister( | ... | @@ -1156,45 +1250,17 @@ fn binOpRegister( |
| 1156 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { | 1250 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1157 | break :blk rhs_reg; | 1251 | break :blk rhs_reg; |
| 1158 | } else { | 1252 | } else { |
| 1159 | break :blk try self.register_manager.allocReg(inst); | 1253 | const raw_reg = try self.register_manager.allocReg(inst); |
| | 1254 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1160 | } | 1255 | } |
| 1161 | } else try self.register_manager.allocReg(null); | 1256 | } else try self.register_manager.allocReg(null); |
| 1162 | | 1257 | |
| 1163 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1258 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1164 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); | 1259 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| 1165 | | 1260 | |
| 1166 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 1261 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1167 | .add, | 1262 | .add_shifted_register, |
| 1168 | .ptr_add, | 1263 | .sub_shifted_register, |
| 1169 | => .add_shifted_register, | | |
| 1170 | .sub, | | |
| 1171 | .ptr_sub, | | |
| 1172 | => .sub_shifted_register, | | |
| 1173 | .cmp_eq => .cmp_shifted_register, | | |
| 1174 | .mul => .mul, | | |
| 1175 | .bit_and, | | |
| 1176 | .bool_and, | | |
| 1177 | => .and_shifted_register, | | |
| 1178 | .bit_or, | | |
| 1179 | .bool_or, | | |
| 1180 | => .orr_shifted_register, | | |
| 1181 | .shl, | | |
| 1182 | .shl_exact, | | |
| 1183 | => .lsl_register, | | |
| 1184 | .shr, | | |
| 1185 | .shr_exact, | | |
| 1186 | => switch (lhs_ty.intInfo(self.target.*).signedness) { | | |
| 1187 | .signed => Mir.Inst.Tag.asr_register, | | |
| 1188 | .unsigned => Mir.Inst.Tag.lsr_register, | | |
| 1189 | }, | | |
| 1190 | .xor => .eor_shifted_register, | | |
| 1191 | else => unreachable, | | |
| 1192 | }; | | |
| 1193 | const mir_data: Mir.Inst.Data = switch (tag) { | | |
| 1194 | .add, | | |
| 1195 | .sub, | | |
| 1196 | .ptr_add, | | |
| 1197 | .ptr_sub, | | |
| 1198 | => .{ .rrr_imm6_shift = .{ | 1264 | => .{ .rrr_imm6_shift = .{ |
| 1199 | .rd = dest_reg, | 1265 | .rd = dest_reg, |
| 1200 | .rn = lhs_reg, | 1266 | .rn = lhs_reg, |
| ... | @@ -1202,27 +1268,24 @@ fn binOpRegister( | ... | @@ -1202,27 +1268,24 @@ fn binOpRegister( |
| 1202 | .imm6 = 0, | 1268 | .imm6 = 0, |
| 1203 | .shift = .lsl, | 1269 | .shift = .lsl, |
| 1204 | } }, | 1270 | } }, |
| 1205 | .cmp_eq => .{ .rr_imm6_shift = .{ | 1271 | .cmp_shifted_register => .{ .rr_imm6_shift = .{ |
| 1206 | .rn = lhs_reg, | 1272 | .rn = lhs_reg, |
| 1207 | .rm = rhs_reg, | 1273 | .rm = rhs_reg, |
| 1208 | .imm6 = 0, | 1274 | .imm6 = 0, |
| 1209 | .shift = .lsl, | 1275 | .shift = .lsl, |
| 1210 | } }, | 1276 | } }, |
| 1211 | .mul, | 1277 | .mul, |
| 1212 | .shl, | 1278 | .lsl_register, |
| 1213 | .shl_exact, | 1279 | .asr_register, |
| 1214 | .shr, | 1280 | .lsr_register, |
| 1215 | .shr_exact, | | |
| 1216 | => .{ .rrr = .{ | 1281 | => .{ .rrr = .{ |
| 1217 | .rd = dest_reg, | 1282 | .rd = dest_reg, |
| 1218 | .rn = lhs_reg, | 1283 | .rn = lhs_reg, |
| 1219 | .rm = rhs_reg, | 1284 | .rm = rhs_reg, |
| 1220 | } }, | 1285 | } }, |
| 1221 | .bit_and, | 1286 | .and_shifted_register, |
| 1222 | .bool_and, | 1287 | .orr_shifted_register, |
| 1223 | .bit_or, | 1288 | .eor_shifted_register, |
| 1224 | .bool_or, | | |
| 1225 | .xor, | | |
| 1226 | => .{ .rrr_imm6_logical_shift = .{ | 1289 | => .{ .rrr_imm6_logical_shift = .{ |
| 1227 | .rd = dest_reg, | 1290 | .rd = dest_reg, |
| 1228 | .rn = lhs_reg, | 1291 | .rn = lhs_reg, |
| ... | @@ -1255,7 +1318,7 @@ fn binOpRegister( | ... | @@ -1255,7 +1318,7 @@ fn binOpRegister( |
| 1255 | /// Asserts that generating an instruction of that form is possible. | 1318 | /// Asserts that generating an instruction of that form is possible. |
| 1256 | fn binOpImmediate( | 1319 | fn binOpImmediate( |
| 1257 | self: *Self, | 1320 | self: *Self, |
| 1258 | tag: Air.Inst.Tag, | 1321 | mir_tag: Mir.Inst.Tag, |
| 1259 | maybe_inst: ?Air.Inst.Index, | 1322 | maybe_inst: ?Air.Inst.Index, |
| 1260 | lhs: MCValue, | 1323 | lhs: MCValue, |
| 1261 | rhs: MCValue, | 1324 | rhs: MCValue, |
| ... | @@ -1276,7 +1339,8 @@ fn binOpImmediate( | ... | @@ -1276,7 +1339,8 @@ fn binOpImmediate( |
| 1276 | ).?; | 1339 | ).?; |
| 1277 | } else null; | 1340 | } else null; |
| 1278 | | 1341 | |
| 1279 | const reg = try self.register_manager.allocReg(track_inst); | 1342 | const raw_reg = try self.register_manager.allocReg(track_inst); |
| | 1343 | const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1280 | self.register_manager.freezeRegs(&.{reg}); | 1344 | self.register_manager.freezeRegs(&.{reg}); |
| 1281 | | 1345 | |
| 1282 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); | 1346 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | @@ -1285,8 +1349,8 @@ fn binOpImmediate( | ... | @@ -1285,8 +1349,8 @@ fn binOpImmediate( |
| 1285 | }; | 1349 | }; |
| 1286 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); | 1350 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1287 | | 1351 | |
| 1288 | const dest_reg = switch (tag) { | 1352 | const dest_reg = switch (mir_tag) { |
| 1289 | .cmp_eq => undefined, // cmp has no destination register | 1353 | .cmp_immediate => undefined, // cmp has no destination register |
| 1290 | else => if (maybe_inst) |inst| blk: { | 1354 | else => if (maybe_inst) |inst| blk: { |
| 1291 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1355 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1292 | | 1356 | |
| ... | @@ -1298,46 +1362,31 @@ fn binOpImmediate( | ... | @@ -1298,46 +1362,31 @@ fn binOpImmediate( |
| 1298 | )) { | 1362 | )) { |
| 1299 | break :blk lhs_reg; | 1363 | break :blk lhs_reg; |
| 1300 | } else { | 1364 | } else { |
| 1301 | break :blk try self.register_manager.allocReg(inst); | 1365 | const raw_reg = try self.register_manager.allocReg(inst); |
| | 1366 | break :blk registerAlias(raw_reg, lhs_ty.abiSize(self.target.*)); |
| 1302 | } | 1367 | } |
| 1303 | } else try self.register_manager.allocReg(null), | 1368 | } else try self.register_manager.allocReg(null), |
| 1304 | }; | 1369 | }; |
| 1305 | | 1370 | |
| 1306 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1371 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1307 | | 1372 | |
| 1308 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 1373 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1309 | .add => .add_immediate, | 1374 | .add_immediate, |
| 1310 | .sub => .sub_immediate, | 1375 | .sub_immediate, |
| 1311 | .shl, | | |
| 1312 | .shl_exact, | | |
| 1313 | => .lsl_immediate, | | |
| 1314 | .shr, | | |
| 1315 | .shr_exact, | | |
| 1316 | => switch (lhs_ty.intInfo(self.target.*).signedness) { | | |
| 1317 | .signed => Mir.Inst.Tag.asr_immediate, | | |
| 1318 | .unsigned => Mir.Inst.Tag.lsr_immediate, | | |
| 1319 | }, | | |
| 1320 | .cmp_eq => .cmp_immediate, | | |
| 1321 | else => unreachable, | | |
| 1322 | }; | | |
| 1323 | const mir_data: Mir.Inst.Data = switch (tag) { | | |
| 1324 | .add, | | |
| 1325 | .sub, | | |
| 1326 | => .{ .rr_imm12_sh = .{ | 1376 | => .{ .rr_imm12_sh = .{ |
| 1327 | .rd = dest_reg, | 1377 | .rd = dest_reg, |
| 1328 | .rn = lhs_reg, | 1378 | .rn = lhs_reg, |
| 1329 | .imm12 = @intCast(u12, rhs.immediate), | 1379 | .imm12 = @intCast(u12, rhs.immediate), |
| 1330 | } }, | 1380 | } }, |
| 1331 | .shl, | 1381 | .lsl_immediate, |
| 1332 | .shl_exact, | 1382 | .asr_immediate, |
| 1333 | .shr, | 1383 | .lsr_immediate, |
| 1334 | .shr_exact, | | |
| 1335 | => .{ .rr_shift = .{ | 1384 | => .{ .rr_shift = .{ |
| 1336 | .rd = dest_reg, | 1385 | .rd = dest_reg, |
| 1337 | .rn = lhs_reg, | 1386 | .rn = lhs_reg, |
| 1338 | .shift = @intCast(u6, rhs.immediate), | 1387 | .shift = @intCast(u6, rhs.immediate), |
| 1339 | } }, | 1388 | } }, |
| 1340 | .cmp_eq => .{ .r_imm12_sh = .{ | 1389 | .cmp_immediate => .{ .r_imm12_sh = .{ |
| 1341 | .rn = lhs_reg, | 1390 | .rn = lhs_reg, |
| 1342 | .imm12 = @intCast(u12, rhs.immediate), | 1391 | .imm12 = @intCast(u12, rhs.immediate), |
| 1343 | } }, | 1392 | } }, |
| ... | @@ -1375,7 +1424,6 @@ fn binOp( | ... | @@ -1375,7 +1424,6 @@ fn binOp( |
| 1375 | ) InnerError!MCValue { | 1424 | ) InnerError!MCValue { |
| 1376 | const target = self.target.*; | 1425 | const target = self.target.*; |
| 1377 | switch (tag) { | 1426 | switch (tag) { |
| 1378 | // Arithmetic operations on integers and floats | | |
| 1379 | .add, | 1427 | .add, |
| 1380 | .sub, | 1428 | .sub, |
| 1381 | .cmp_eq, | 1429 | .cmp_eq, |
| ... | @@ -1403,13 +1451,26 @@ fn binOp( | ... | @@ -1403,13 +1451,26 @@ fn binOp( |
| 1403 | else => unreachable, | 1451 | else => unreachable, |
| 1404 | }; | 1452 | }; |
| 1405 | | 1453 | |
| | 1454 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 1455 | .add => .add_shifted_register, |
| | 1456 | .sub => .sub_shifted_register, |
| | 1457 | .cmp_eq => .cmp_shifted_register, |
| | 1458 | else => unreachable, |
| | 1459 | }; |
| | 1460 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| | 1461 | .add => .add_immediate, |
| | 1462 | .sub => .sub_immediate, |
| | 1463 | .cmp_eq => .cmp_immediate, |
| | 1464 | else => unreachable, |
| | 1465 | }; |
| | 1466 | |
| 1406 | if (rhs_immediate_ok) { | 1467 | if (rhs_immediate_ok) { |
| 1407 | return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); | 1468 | return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false); |
| 1408 | } else if (lhs_immediate_ok) { | 1469 | } else if (lhs_immediate_ok) { |
| 1409 | // swap lhs and rhs | 1470 | // swap lhs and rhs |
| 1410 | return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true); | 1471 | return try self.binOpImmediate(mir_tag_immediate, maybe_inst, rhs, lhs, rhs_ty, true); |
| 1411 | } else { | 1472 | } else { |
| 1412 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1473 | return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1413 | } | 1474 | } |
| 1414 | } else { | 1475 | } else { |
| 1415 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1476 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | @@ -1428,7 +1489,7 @@ fn binOp( | ... | @@ -1428,7 +1489,7 @@ fn binOp( |
| 1428 | // TODO add optimisations for multiplication | 1489 | // TODO add optimisations for multiplication |
| 1429 | // with immediates, for example a * 2 can be | 1490 | // with immediates, for example a * 2 can be |
| 1430 | // lowered to a << 1 | 1491 | // lowered to a << 1 |
| 1431 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1492 | return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1432 | } else { | 1493 | } else { |
| 1433 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1494 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1434 | } | 1495 | } |
| ... | @@ -1436,7 +1497,36 @@ fn binOp( | ... | @@ -1436,7 +1497,36 @@ fn binOp( |
| 1436 | else => unreachable, | 1497 | else => unreachable, |
| 1437 | } | 1498 | } |
| 1438 | }, | 1499 | }, |
| 1439 | // Bitwise operations on integers | 1500 | .addwrap, |
| | 1501 | .subwrap, |
| | 1502 | .mulwrap, |
| | 1503 | => { |
| | 1504 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1505 | .addwrap => .add, |
| | 1506 | .subwrap => .sub, |
| | 1507 | .mulwrap => .mul, |
| | 1508 | else => unreachable, |
| | 1509 | }; |
| | 1510 | |
| | 1511 | // Generate an add/sub/mul |
| | 1512 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1513 | |
| | 1514 | // Truncate if necessary |
| | 1515 | switch (lhs_ty.zigTypeTag()) { |
| | 1516 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 1517 | .Int => { |
| | 1518 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1519 | if (int_info.bits <= 64) { |
| | 1520 | const result_reg = result.register; |
| | 1521 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| | 1522 | return result; |
| | 1523 | } else { |
| | 1524 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| | 1525 | } |
| | 1526 | }, |
| | 1527 | else => unreachable, |
| | 1528 | } |
| | 1529 | }, |
| 1440 | .bit_and, | 1530 | .bit_and, |
| 1441 | .bit_or, | 1531 | .bit_or, |
| 1442 | .xor, | 1532 | .xor, |
| ... | @@ -1448,7 +1538,14 @@ fn binOp( | ... | @@ -1448,7 +1538,14 @@ fn binOp( |
| 1448 | const int_info = lhs_ty.intInfo(self.target.*); | 1538 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1449 | if (int_info.bits <= 64) { | 1539 | if (int_info.bits <= 64) { |
| 1450 | // TODO implement bitwise operations with immediates | 1540 | // TODO implement bitwise operations with immediates |
| 1451 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1541 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 1542 | .bit_and => .and_shifted_register, |
| | 1543 | .bit_or => .orr_shifted_register, |
| | 1544 | .xor => .eor_shifted_register, |
| | 1545 | else => unreachable, |
| | 1546 | }; |
| | 1547 | |
| | 1548 | return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1452 | } else { | 1549 | } else { |
| 1453 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1550 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1454 | } | 1551 | } |
| ... | @@ -1456,8 +1553,8 @@ fn binOp( | ... | @@ -1456,8 +1553,8 @@ fn binOp( |
| 1456 | else => unreachable, | 1553 | else => unreachable, |
| 1457 | } | 1554 | } |
| 1458 | }, | 1555 | }, |
| 1459 | .shl, | 1556 | .shl_exact, |
| 1460 | .shr, | 1557 | .shr_exact, |
| 1461 | => { | 1558 | => { |
| 1462 | switch (lhs_ty.zigTypeTag()) { | 1559 | switch (lhs_ty.zigTypeTag()) { |
| 1463 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 1560 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | @@ -1466,10 +1563,27 @@ fn binOp( | ... | @@ -1466,10 +1563,27 @@ fn binOp( |
| 1466 | if (int_info.bits <= 64) { | 1563 | if (int_info.bits <= 64) { |
| 1467 | const rhs_immediate_ok = rhs == .immediate; | 1564 | const rhs_immediate_ok = rhs == .immediate; |
| 1468 | | 1565 | |
| | 1566 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 1567 | .shl_exact => .lsl_register, |
| | 1568 | .shr_exact => switch (int_info.signedness) { |
| | 1569 | .signed => Mir.Inst.Tag.asr_register, |
| | 1570 | .unsigned => Mir.Inst.Tag.lsr_register, |
| | 1571 | }, |
| | 1572 | else => unreachable, |
| | 1573 | }; |
| | 1574 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| | 1575 | .shl_exact => .lsl_immediate, |
| | 1576 | .shr_exact => switch (int_info.signedness) { |
| | 1577 | .signed => Mir.Inst.Tag.asr_immediate, |
| | 1578 | .unsigned => Mir.Inst.Tag.lsr_immediate, |
| | 1579 | }, |
| | 1580 | else => unreachable, |
| | 1581 | }; |
| | 1582 | |
| 1469 | if (rhs_immediate_ok) { | 1583 | if (rhs_immediate_ok) { |
| 1470 | return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); | 1584 | return try self.binOpImmediate(mir_tag_immediate, maybe_inst, lhs, rhs, lhs_ty, false); |
| 1471 | } else { | 1585 | } else { |
| 1472 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1586 | return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1473 | } | 1587 | } |
| 1474 | } else { | 1588 | } else { |
| 1475 | return self.fail("TODO binary operations on int with bits > 64", .{}); | 1589 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | @@ -1478,6 +1592,38 @@ fn binOp( | ... | @@ -1478,6 +1592,38 @@ fn binOp( |
| 1478 | else => unreachable, | 1592 | else => unreachable, |
| 1479 | } | 1593 | } |
| 1480 | }, | 1594 | }, |
| | 1595 | .shl, |
| | 1596 | .shr, |
| | 1597 | => { |
| | 1598 | const base_tag: Air.Inst.Tag = switch (tag) { |
| | 1599 | .shl => .shl_exact, |
| | 1600 | .shr => .shr_exact, |
| | 1601 | else => unreachable, |
| | 1602 | }; |
| | 1603 | |
| | 1604 | // Generate a shl_exact/shr_exact |
| | 1605 | const result = try self.binOp(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1606 | |
| | 1607 | // Truncate if necessary |
| | 1608 | switch (tag) { |
| | 1609 | .shr => return result, |
| | 1610 | .shl => switch (lhs_ty.zigTypeTag()) { |
| | 1611 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 1612 | .Int => { |
| | 1613 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1614 | if (int_info.bits <= 64) { |
| | 1615 | const result_reg = result.register; |
| | 1616 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| | 1617 | return result; |
| | 1618 | } else { |
| | 1619 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| | 1620 | } |
| | 1621 | }, |
| | 1622 | else => unreachable, |
| | 1623 | }, |
| | 1624 | else => unreachable, |
| | 1625 | } |
| | 1626 | }, |
| 1481 | .bool_and, | 1627 | .bool_and, |
| 1482 | .bool_or, | 1628 | .bool_or, |
| 1483 | => { | 1629 | => { |
| ... | @@ -1486,7 +1632,13 @@ fn binOp( | ... | @@ -1486,7 +1632,13 @@ fn binOp( |
| 1486 | assert(lhs != .immediate); // should have been handled by Sema | 1632 | assert(lhs != .immediate); // should have been handled by Sema |
| 1487 | assert(rhs != .immediate); // should have been handled by Sema | 1633 | assert(rhs != .immediate); // should have been handled by Sema |
| 1488 | | 1634 | |
| 1489 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1635 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 1636 | .bool_and => .and_shifted_register, |
| | 1637 | .bool_or => .orr_shifted_register, |
| | 1638 | else => unreachable, |
| | 1639 | }; |
| | 1640 | |
| | 1641 | return try self.binOpRegister(mir_tag_register, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1490 | }, | 1642 | }, |
| 1491 | else => unreachable, | 1643 | else => unreachable, |
| 1492 | } | 1644 | } |
| ... | @@ -1504,9 +1656,9 @@ fn binOp( | ... | @@ -1504,9 +1656,9 @@ fn binOp( |
| 1504 | const elem_size = elem_ty.abiSize(self.target.*); | 1656 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1505 | | 1657 | |
| 1506 | if (elem_size == 1) { | 1658 | if (elem_size == 1) { |
| 1507 | const base_tag: Air.Inst.Tag = switch (tag) { | 1659 | const base_tag: Mir.Inst.Tag = switch (tag) { |
| 1508 | .ptr_add => .add, | 1660 | .ptr_add => .add_shifted_register, |
| 1509 | .ptr_sub => .sub, | 1661 | .ptr_sub => .sub_shifted_register, |
| 1510 | else => unreachable, | 1662 | else => unreachable, |
| 1511 | }; | 1663 | }; |
| 1512 | | 1664 | |
| ... | @@ -1538,36 +1690,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1538,36 +1690,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1538 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1690 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1539 | } | 1691 | } |
| 1540 | | 1692 | |
| 1541 | fn airAddWrap(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1542 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1543 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement addwrap for {}", .{self.target.cpu.arch}); | | |
| 1544 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1545 | } | | |
| 1546 | | | |
| 1547 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | 1693 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1548 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1694 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1549 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); | 1695 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); |
| 1550 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1696 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1551 | } | 1697 | } |
| 1552 | | 1698 | |
| 1553 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1554 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1555 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch}); | | |
| 1556 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1557 | } | | |
| 1558 | | | |
| 1559 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | 1699 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1560 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1700 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1561 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); | 1701 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); |
| 1562 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1702 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1563 | } | 1703 | } |
| 1564 | | 1704 | |
| 1565 | fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1566 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1567 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}); | | |
| 1568 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1569 | } | | |
| 1570 | | | |
| 1571 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | 1705 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1572 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1706 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1573 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); | 1707 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch}); |
| ... | @@ -1961,11 +2095,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1961,11 +2095,12 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1961 | .undef => unreachable, | 2095 | .undef => unreachable, |
| 1962 | .compare_flags_signed, .compare_flags_unsigned => unreachable, | 2096 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1963 | .register => |dst_reg| { | 2097 | .register => |dst_reg| { |
| 1964 | try self.genLdrRegister(dst_reg, addr_reg, elem_size); | 2098 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); |
| 1965 | }, | 2099 | }, |
| 1966 | .stack_offset => |off| { | 2100 | .stack_offset => |off| { |
| 1967 | if (elem_size <= 8) { | 2101 | if (elem_size <= 8) { |
| 1968 | const tmp_reg = try self.register_manager.allocReg(null); | 2102 | const raw_tmp_reg = try self.register_manager.allocReg(null); |
| | 2103 | const tmp_reg = registerAlias(raw_tmp_reg, elem_size); |
| 1969 | self.register_manager.freezeRegs(&.{tmp_reg}); | 2104 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1970 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); | 2105 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 1971 | | 2106 | |
| ... | @@ -2001,12 +2136,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2001,12 +2136,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2001 | .got_load, | 2136 | .got_load, |
| 2002 | .direct_load, | 2137 | .direct_load, |
| 2003 | => { | 2138 | => { |
| 2004 | const reg = try self.register_manager.allocReg(null); | 2139 | const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 2005 | self.register_manager.freezeRegs(&.{reg}); | 2140 | try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty); |
| 2006 | defer self.register_manager.unfreezeRegs(&.{reg}); | | |
| 2007 | | | |
| 2008 | try self.genSetReg(ptr_ty, reg, ptr); | | |
| 2009 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); | | |
| 2010 | }, | 2141 | }, |
| 2011 | } | 2142 | } |
| 2012 | } | 2143 | } |
| ... | @@ -2091,6 +2222,7 @@ fn genInlineMemcpy( | ... | @@ -2091,6 +2222,7 @@ fn genInlineMemcpy( |
| 2091 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 2222 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2092 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2223 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2093 | const elem_ty = self.air.typeOfIndex(inst); | 2224 | const elem_ty = self.air.typeOfIndex(inst); |
| | 2225 | const elem_size = elem_ty.abiSize(self.target.*); |
| 2094 | const result: MCValue = result: { | 2226 | const result: MCValue = result: { |
| 2095 | if (!elem_ty.hasRuntimeBits()) | 2227 | if (!elem_ty.hasRuntimeBits()) |
| 2096 | break :result MCValue.none; | 2228 | break :result MCValue.none; |
| ... | @@ -2101,9 +2233,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2101,9 +2233,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2101 | break :result MCValue.dead; | 2233 | break :result MCValue.dead; |
| 2102 | | 2234 | |
| 2103 | const dst_mcv: MCValue = blk: { | 2235 | const dst_mcv: MCValue = blk: { |
| 2104 | if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) { | 2236 | if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { |
| 2105 | // The MCValue that holds the pointer can be re-used as the value. | 2237 | // The MCValue that holds the pointer can be re-used as the value. |
| 2106 | break :blk ptr; | 2238 | break :blk switch (ptr) { |
| | 2239 | .register => |r| MCValue{ .register = registerAlias(r, elem_size) }, |
| | 2240 | else => ptr, |
| | 2241 | }; |
| 2107 | } else { | 2242 | } else { |
| 2108 | break :blk try self.allocRegOrMem(inst, true); | 2243 | break :blk try self.allocRegOrMem(inst, true); |
| 2109 | } | 2244 | } |
| ... | @@ -2114,101 +2249,52 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2114,101 +2249,52 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2114 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2249 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2115 | } | 2250 | } |
| 2116 | | 2251 | |
| 2117 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void { | 2252 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 2118 | switch (abi_size) { | 2253 | const abi_size = ty.abiSize(self.target.*); |
| 2119 | 1 => { | 2254 | |
| 2120 | _ = try self.addInst(.{ | 2255 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2121 | .tag = .ldrb_immediate, | 2256 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, |
| 2122 | .data = .{ .load_store_register_immediate = .{ | 2257 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, |
| 2123 | .rt = value_reg.to32(), | 2258 | 4 => .ldr_immediate, |
| 2124 | .rn = addr_reg, | 2259 | 8 => .ldr_immediate, |
| 2125 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2126 | } }, | | |
| 2127 | }); | | |
| 2128 | }, | | |
| 2129 | 2 => { | | |
| 2130 | _ = try self.addInst(.{ | | |
| 2131 | .tag = .ldrh_immediate, | | |
| 2132 | .data = .{ .load_store_register_immediate = .{ | | |
| 2133 | .rt = value_reg.to32(), | | |
| 2134 | .rn = addr_reg, | | |
| 2135 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2136 | } }, | | |
| 2137 | }); | | |
| 2138 | }, | | |
| 2139 | 4 => { | | |
| 2140 | _ = try self.addInst(.{ | | |
| 2141 | .tag = .ldr_immediate, | | |
| 2142 | .data = .{ .load_store_register_immediate = .{ | | |
| 2143 | .rt = value_reg.to32(), | | |
| 2144 | .rn = addr_reg, | | |
| 2145 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2146 | } }, | | |
| 2147 | }); | | |
| 2148 | }, | | |
| 2149 | 8 => { | | |
| 2150 | _ = try self.addInst(.{ | | |
| 2151 | .tag = .ldr_immediate, | | |
| 2152 | .data = .{ .load_store_register_immediate = .{ | | |
| 2153 | .rt = value_reg.to64(), | | |
| 2154 | .rn = addr_reg, | | |
| 2155 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2156 | } }, | | |
| 2157 | }); | | |
| 2158 | }, | | |
| 2159 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), | 2260 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), |
| 2160 | else => unreachable, | 2261 | else => unreachable, |
| 2161 | } | 2262 | }; |
| | 2263 | |
| | 2264 | _ = try self.addInst(.{ |
| | 2265 | .tag = tag, |
| | 2266 | .data = .{ .load_store_register_immediate = .{ |
| | 2267 | .rt = value_reg, |
| | 2268 | .rn = addr_reg, |
| | 2269 | .offset = Instruction.LoadStoreOffset.none.immediate, |
| | 2270 | } }, |
| | 2271 | }); |
| 2162 | } | 2272 | } |
| 2163 | | 2273 | |
| 2164 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void { | 2274 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 2165 | switch (abi_size) { | 2275 | const abi_size = ty.abiSize(self.target.*); |
| 2166 | 1 => { | 2276 | |
| 2167 | _ = try self.addInst(.{ | 2277 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2168 | .tag = .strb_immediate, | 2278 | 1 => .strb_immediate, |
| 2169 | .data = .{ .load_store_register_immediate = .{ | 2279 | 2 => .strh_immediate, |
| 2170 | .rt = value_reg.to32(), | 2280 | 4, 8 => .str_immediate, |
| 2171 | .rn = addr_reg, | | |
| 2172 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2173 | } }, | | |
| 2174 | }); | | |
| 2175 | }, | | |
| 2176 | 2 => { | | |
| 2177 | _ = try self.addInst(.{ | | |
| 2178 | .tag = .strh_immediate, | | |
| 2179 | .data = .{ .load_store_register_immediate = .{ | | |
| 2180 | .rt = value_reg.to32(), | | |
| 2181 | .rn = addr_reg, | | |
| 2182 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2183 | } }, | | |
| 2184 | }); | | |
| 2185 | }, | | |
| 2186 | 4 => { | | |
| 2187 | _ = try self.addInst(.{ | | |
| 2188 | .tag = .str_immediate, | | |
| 2189 | .data = .{ .load_store_register_immediate = .{ | | |
| 2190 | .rt = value_reg.to32(), | | |
| 2191 | .rn = addr_reg, | | |
| 2192 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2193 | } }, | | |
| 2194 | }); | | |
| 2195 | }, | | |
| 2196 | 8 => { | | |
| 2197 | _ = try self.addInst(.{ | | |
| 2198 | .tag = .str_immediate, | | |
| 2199 | .data = .{ .load_store_register_immediate = .{ | | |
| 2200 | .rt = value_reg.to64(), | | |
| 2201 | .rn = addr_reg, | | |
| 2202 | .offset = Instruction.LoadStoreOffset.none.immediate, | | |
| 2203 | } }, | | |
| 2204 | }); | | |
| 2205 | }, | | |
| 2206 | 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}), | 2281 | 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}), |
| 2207 | else => unreachable, | 2282 | else => unreachable, |
| 2208 | } | 2283 | }; |
| | 2284 | |
| | 2285 | _ = try self.addInst(.{ |
| | 2286 | .tag = tag, |
| | 2287 | .data = .{ .load_store_register_immediate = .{ |
| | 2288 | .rt = value_reg, |
| | 2289 | .rn = addr_reg, |
| | 2290 | .offset = Instruction.LoadStoreOffset.none.immediate, |
| | 2291 | } }, |
| | 2292 | }); |
| 2209 | } | 2293 | } |
| 2210 | | 2294 | |
| 2211 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 2295 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| | 2296 | const abi_size = value_ty.abiSize(self.target.*); |
| | 2297 | |
| 2212 | switch (ptr) { | 2298 | switch (ptr) { |
| 2213 | .none => unreachable, | 2299 | .none => unreachable, |
| 2214 | .undef => unreachable, | 2300 | .undef => unreachable, |
| ... | @@ -2226,14 +2312,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2226,14 +2312,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2226 | self.register_manager.freezeRegs(&.{addr_reg}); | 2312 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2227 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 2313 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 2228 | | 2314 | |
| 2229 | const abi_size = value_ty.abiSize(self.target.*); | | |
| 2230 | switch (value) { | 2315 | switch (value) { |
| 2231 | .register => |value_reg| { | 2316 | .register => |value_reg| { |
| 2232 | try self.genStrRegister(value_reg, addr_reg, abi_size); | 2317 | try self.genStrRegister(value_reg, addr_reg, value_ty); |
| 2233 | }, | 2318 | }, |
| 2234 | else => { | 2319 | else => { |
| 2235 | if (abi_size <= 8) { | 2320 | if (abi_size <= 8) { |
| 2236 | const tmp_reg = try self.register_manager.allocReg(null); | 2321 | const raw_tmp_reg = try self.register_manager.allocReg(null); |
| | 2322 | const tmp_reg = registerAlias(raw_tmp_reg, abi_size); |
| 2237 | self.register_manager.freezeRegs(&.{tmp_reg}); | 2323 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 2238 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); | 2324 | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 2239 | | 2325 | |
| ... | @@ -3470,23 +3556,26 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3470,23 +3556,26 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3470 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x) } }, | 3556 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x) } }, |
| 3471 | }); | 3557 | }); |
| 3472 | | 3558 | |
| 3473 | if (x > math.maxInt(u16)) { | 3559 | if (x & 0x0000_0000_ffff_0000 != 0) { |
| 3474 | _ = try self.addInst(.{ | 3560 | _ = try self.addInst(.{ |
| 3475 | .tag = .movk, | 3561 | .tag = .movk, |
| 3476 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 16), .hw = 1 } }, | 3562 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 16), .hw = 1 } }, |
| 3477 | }); | 3563 | }); |
| 3478 | } | 3564 | } |
| 3479 | if (x > math.maxInt(u32)) { | 3565 | |
| 3480 | _ = try self.addInst(.{ | 3566 | if (reg.size() == 64) { |
| 3481 | .tag = .movk, | 3567 | if (x & 0x0000_ffff_0000_0000 != 0) { |
| 3482 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } }, | 3568 | _ = try self.addInst(.{ |
| 3483 | }); | 3569 | .tag = .movk, |
| 3484 | } | 3570 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } }, |
| 3485 | if (x > math.maxInt(u48)) { | 3571 | }); |
| 3486 | _ = try self.addInst(.{ | 3572 | } |
| 3487 | .tag = .movk, | 3573 | if (x & 0xffff_0000_0000_0000 != 0) { |
| 3488 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } }, | 3574 | _ = try self.addInst(.{ |
| 3489 | }); | 3575 | .tag = .movk, |
| | 3576 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } }, |
| | 3577 | }); |
| | 3578 | } |
| 3490 | } | 3579 | } |
| 3491 | }, | 3580 | }, |
| 3492 | .register => |src_reg| { | 3581 | .register => |src_reg| { |
| ... | @@ -3522,8 +3611,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3522,8 +3611,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3522 | .memory => |addr| { | 3611 | .memory => |addr| { |
| 3523 | // The value is in memory at a hard-coded address. | 3612 | // The value is in memory at a hard-coded address. |
| 3524 | // If the type is a pointer, it means the pointer address is at this memory location. | 3613 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3525 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 3614 | try self.genSetReg(ty, reg.to64(), .{ .immediate = addr }); |
| 3526 | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); | 3615 | try self.genLdrRegister(reg, reg.to64(), ty); |
| 3527 | }, | 3616 | }, |
| 3528 | .stack_offset => |off| { | 3617 | .stack_offset => |off| { |
| 3529 | const abi_size = ty.abiSize(self.target.*); | 3618 | const abi_size = ty.abiSize(self.target.*); |
| ... | @@ -3531,21 +3620,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3531,21 +3620,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3531 | switch (abi_size) { | 3620 | switch (abi_size) { |
| 3532 | 1, 2, 4, 8 => { | 3621 | 1, 2, 4, 8 => { |
| 3533 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3622 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3534 | 1 => .ldrb_stack, | 3623 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, |
| 3535 | 2 => .ldrh_stack, | 3624 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, |
| 3536 | 4, 8 => .ldr_stack, | 3625 | 4, 8 => .ldr_stack, |
| 3537 | else => unreachable, // unexpected abi size | 3626 | else => unreachable, // unexpected abi size |
| 3538 | }; | 3627 | }; |
| 3539 | const rt: Register = switch (abi_size) { | | |
| 3540 | 1, 2, 4 => reg.to32(), | | |
| 3541 | 8 => reg.to64(), | | |
| 3542 | else => unreachable, // unexpected abi size | | |
| 3543 | }; | | |
| 3544 | | 3628 | |
| 3545 | _ = try self.addInst(.{ | 3629 | _ = try self.addInst(.{ |
| 3546 | .tag = tag, | 3630 | .tag = tag, |
| 3547 | .data = .{ .load_store_stack = .{ | 3631 | .data = .{ .load_store_stack = .{ |
| 3548 | .rt = rt, | 3632 | .rt = reg, |
| 3549 | .offset = @intCast(u32, off), | 3633 | .offset = @intCast(u32, off), |
| 3550 | } }, | 3634 | } }, |
| 3551 | }); | 3635 | }); |
| ... | @@ -3998,6 +4082,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -3998,6 +4082,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 3998 | var nsaa: u32 = 0; // Next stacked argument address | 4082 | var nsaa: u32 = 0; // Next stacked argument address |
| 3999 | | 4083 | |
| 4000 | for (param_types) |ty, i| { | 4084 | for (param_types) |ty, i| { |
| | 4085 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 4086 | if (param_size == 0) { |
| | 4087 | result.args[i] = .{ .none = {} }; |
| | 4088 | continue; |
| | 4089 | } |
| | 4090 | |
| 4001 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned | 4091 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 4002 | // values to spread across odd-numbered registers. | 4092 | // values to spread across odd-numbered registers. |
| 4003 | if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) { | 4093 | if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) { |
| ... | @@ -4005,10 +4095,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4005,10 +4095,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4005 | ncrn += ncrn % 2; | 4095 | ncrn += ncrn % 2; |
| 4006 | } | 4096 | } |
| 4007 | | 4097 | |
| 4008 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | | |
| 4009 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { | 4098 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { |
| 4010 | if (param_size <= 8) { | 4099 | if (param_size <= 8) { |
| 4011 | result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] }; | 4100 | result.args[i] = .{ .register = registerAlias(c_abi_int_param_regs[ncrn], param_size) }; |
| 4012 | ncrn += 1; | 4101 | ncrn += 1; |
| 4013 | } else { | 4102 | } else { |
| 4014 | return self.fail("TODO MCValues with multiple registers", .{}); | 4103 | return self.fail("TODO MCValues with multiple registers", .{}); |
| ... | @@ -4045,7 +4134,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -4045,7 +4134,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4045 | .Unspecified, .C => { | 4134 | .Unspecified, .C => { |
| 4046 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4135 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 4047 | if (ret_ty_size <= 8) { | 4136 | if (ret_ty_size <= 8) { |
| 4048 | result.return_value = .{ .register = c_abi_int_return_regs[0] }; | 4137 | result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) }; |
| 4049 | } else { | 4138 | } else { |
| 4050 | return self.fail("TODO support more return types for ARM backend", .{}); | 4139 | return self.fail("TODO support more return types for ARM backend", .{}); |
| 4051 | } | 4140 | } |