| ... | ... | @@ -376,7 +376,7 @@ fn gen(self: *Self) !void { |
| 376 | 376 | // mov fp, sp |
| 377 | 377 | _ = try self.addInst(.{ |
| 378 | 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 | 382 | // sub sp, sp, #reloc |
| ... | ... | @@ -421,7 +421,7 @@ fn gen(self: *Self) !void { |
| 421 | 421 | if (math.cast(u12, stack_size)) |size| { |
| 422 | 422 | self.mir_instructions.set(backpatch_reloc, .{ |
| 423 | 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 | 426 | } else |_| { |
| 427 | 427 | return self.failSymbol("TODO AArch64: allow larger stacks", .{}); |
| ... | ... | @@ -453,7 +453,7 @@ fn gen(self: *Self) !void { |
| 453 | 453 | // add sp, sp, #stack_size |
| 454 | 454 | _ = try self.addInst(.{ |
| 455 | 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 | 459 | // <load other registers> |
| ... | ... | @@ -512,13 +512,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 512 | 512 | switch (air_tags[inst]) { |
| 513 | 513 | // zig fmt: off |
| 514 | 514 | .add, .ptr_add => try self.airBinOp(inst), |
| 515 | | .addwrap => try self.airAddWrap(inst), |
| 515 | .addwrap => try self.airBinOp(inst), |
| 516 | 516 | .add_sat => try self.airAddSat(inst), |
| 517 | 517 | .sub, .ptr_sub => try self.airBinOp(inst), |
| 518 | | .subwrap => try self.airSubWrap(inst), |
| 518 | .subwrap => try self.airBinOp(inst), |
| 519 | 519 | .sub_sat => try self.airSubSat(inst), |
| 520 | 520 | .mul => try self.airBinOp(inst), |
| 521 | | .mulwrap => try self.airMulWrap(inst), |
| 521 | .mulwrap => try self.airBinOp(inst), |
| 522 | 522 | .mul_sat => try self.airMulSat(inst), |
| 523 | 523 | .rem => try self.airRem(inst), |
| 524 | 524 | .mod => try self.airMod(inst), |
| ... | ... | @@ -882,7 +882,8 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 882 | 882 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 883 | 883 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 884 | 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 | 887 | try self.genSetReg(ty, reg, mcv); |
| 887 | 888 | return reg; |
| 888 | 889 | } |
| ... | ... | @@ -891,7 +892,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 891 | 892 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 892 | 893 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 893 | 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 | 898 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); |
| 896 | 899 | return MCValue{ .register = reg }; |
| 897 | 900 | } |
| ... | ... | @@ -936,14 +939,99 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 936 | 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 | 1024 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 940 | 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 | 1026 | const operand = try self.resolveInst(ty_op.operand); |
| 945 | | _ = operand; |
| 946 | | return self.fail("TODO implement trunc for {}", .{self.target.cpu.arch}); |
| 1027 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 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 | 1037 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1003,7 +1091,8 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1003 | 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 | 1098 | _ = try self.addInst(.{ |
| ... | ... | @@ -1013,7 +1102,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1013 | 1102 | .rn = op_reg, |
| 1014 | 1103 | .imms = 0b000000, |
| 1015 | 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 | 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 | 1131 | _ = try self.addInst(.{ |
| ... | ... | @@ -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 | 1143 | break :result MCValue{ .register = dest_reg }; |
| 1052 | 1144 | } else { |
| 1053 | 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 | 1195 | /// Asserts that generating an instruction of that form is possible. |
| 1104 | 1196 | fn binOpRegister( |
| 1105 | 1197 | self: *Self, |
| 1106 | | tag: Air.Inst.Tag, |
| 1198 | mir_tag: Mir.Inst.Tag, |
| 1107 | 1199 | maybe_inst: ?Air.Inst.Index, |
| 1108 | 1200 | lhs: MCValue, |
| 1109 | 1201 | rhs: MCValue, |
| ... | ... | @@ -1124,7 +1216,8 @@ fn binOpRegister( |
| 1124 | 1216 | break :inst Air.refToIndex(bin_op.lhs).?; |
| 1125 | 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 | 1221 | self.register_manager.freezeRegs(&.{reg}); |
| 1129 | 1222 | |
| 1130 | 1223 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1139,7 +1232,8 @@ fn binOpRegister( |
| 1139 | 1232 | break :inst Air.refToIndex(bin_op.rhs).?; |
| 1140 | 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 | 1237 | self.register_manager.freezeRegs(&.{reg}); |
| 1144 | 1238 | |
| 1145 | 1239 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1156,45 +1250,17 @@ fn binOpRegister( |
| 1156 | 1250 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { |
| 1157 | 1251 | break :blk rhs_reg; |
| 1158 | 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 | 1256 | } else try self.register_manager.allocReg(null); |
| 1162 | 1257 | |
| 1163 | 1258 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1164 | 1259 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| 1165 | 1260 | |
| 1166 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1167 | | .add, |
| 1168 | | .ptr_add, |
| 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, |
| 1261 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1262 | .add_shifted_register, |
| 1263 | .sub_shifted_register, |
| 1198 | 1264 | => .{ .rrr_imm6_shift = .{ |
| 1199 | 1265 | .rd = dest_reg, |
| 1200 | 1266 | .rn = lhs_reg, |
| ... | ... | @@ -1202,27 +1268,24 @@ fn binOpRegister( |
| 1202 | 1268 | .imm6 = 0, |
| 1203 | 1269 | .shift = .lsl, |
| 1204 | 1270 | } }, |
| 1205 | | .cmp_eq => .{ .rr_imm6_shift = .{ |
| 1271 | .cmp_shifted_register => .{ .rr_imm6_shift = .{ |
| 1206 | 1272 | .rn = lhs_reg, |
| 1207 | 1273 | .rm = rhs_reg, |
| 1208 | 1274 | .imm6 = 0, |
| 1209 | 1275 | .shift = .lsl, |
| 1210 | 1276 | } }, |
| 1211 | 1277 | .mul, |
| 1212 | | .shl, |
| 1213 | | .shl_exact, |
| 1214 | | .shr, |
| 1215 | | .shr_exact, |
| 1278 | .lsl_register, |
| 1279 | .asr_register, |
| 1280 | .lsr_register, |
| 1216 | 1281 | => .{ .rrr = .{ |
| 1217 | 1282 | .rd = dest_reg, |
| 1218 | 1283 | .rn = lhs_reg, |
| 1219 | 1284 | .rm = rhs_reg, |
| 1220 | 1285 | } }, |
| 1221 | | .bit_and, |
| 1222 | | .bool_and, |
| 1223 | | .bit_or, |
| 1224 | | .bool_or, |
| 1225 | | .xor, |
| 1286 | .and_shifted_register, |
| 1287 | .orr_shifted_register, |
| 1288 | .eor_shifted_register, |
| 1226 | 1289 | => .{ .rrr_imm6_logical_shift = .{ |
| 1227 | 1290 | .rd = dest_reg, |
| 1228 | 1291 | .rn = lhs_reg, |
| ... | ... | @@ -1255,7 +1318,7 @@ fn binOpRegister( |
| 1255 | 1318 | /// Asserts that generating an instruction of that form is possible. |
| 1256 | 1319 | fn binOpImmediate( |
| 1257 | 1320 | self: *Self, |
| 1258 | | tag: Air.Inst.Tag, |
| 1321 | mir_tag: Mir.Inst.Tag, |
| 1259 | 1322 | maybe_inst: ?Air.Inst.Index, |
| 1260 | 1323 | lhs: MCValue, |
| 1261 | 1324 | rhs: MCValue, |
| ... | ... | @@ -1276,7 +1339,8 @@ fn binOpImmediate( |
| 1276 | 1339 | ).?; |
| 1277 | 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 | 1344 | self.register_manager.freezeRegs(&.{reg}); |
| 1281 | 1345 | |
| 1282 | 1346 | if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); |
| ... | ... | @@ -1285,8 +1349,8 @@ fn binOpImmediate( |
| 1285 | 1349 | }; |
| 1286 | 1350 | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1287 | 1351 | |
| 1288 | | const dest_reg = switch (tag) { |
| 1289 | | .cmp_eq => undefined, // cmp has no destination register |
| 1352 | const dest_reg = switch (mir_tag) { |
| 1353 | .cmp_immediate => undefined, // cmp has no destination register |
| 1290 | 1354 | else => if (maybe_inst) |inst| blk: { |
| 1291 | 1355 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1292 | 1356 | |
| ... | ... | @@ -1298,46 +1362,31 @@ fn binOpImmediate( |
| 1298 | 1362 | )) { |
| 1299 | 1363 | break :blk lhs_reg; |
| 1300 | 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 | 1368 | } else try self.register_manager.allocReg(null), |
| 1304 | 1369 | }; |
| 1305 | 1370 | |
| 1306 | 1371 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1307 | 1372 | |
| 1308 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1309 | | .add => .add_immediate, |
| 1310 | | .sub => .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, |
| 1373 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1374 | .add_immediate, |
| 1375 | .sub_immediate, |
| 1326 | 1376 | => .{ .rr_imm12_sh = .{ |
| 1327 | 1377 | .rd = dest_reg, |
| 1328 | 1378 | .rn = lhs_reg, |
| 1329 | 1379 | .imm12 = @intCast(u12, rhs.immediate), |
| 1330 | 1380 | } }, |
| 1331 | | .shl, |
| 1332 | | .shl_exact, |
| 1333 | | .shr, |
| 1334 | | .shr_exact, |
| 1381 | .lsl_immediate, |
| 1382 | .asr_immediate, |
| 1383 | .lsr_immediate, |
| 1335 | 1384 | => .{ .rr_shift = .{ |
| 1336 | 1385 | .rd = dest_reg, |
| 1337 | 1386 | .rn = lhs_reg, |
| 1338 | 1387 | .shift = @intCast(u6, rhs.immediate), |
| 1339 | 1388 | } }, |
| 1340 | | .cmp_eq => .{ .r_imm12_sh = .{ |
| 1389 | .cmp_immediate => .{ .r_imm12_sh = .{ |
| 1341 | 1390 | .rn = lhs_reg, |
| 1342 | 1391 | .imm12 = @intCast(u12, rhs.immediate), |
| 1343 | 1392 | } }, |
| ... | ... | @@ -1375,7 +1424,6 @@ fn binOp( |
| 1375 | 1424 | ) InnerError!MCValue { |
| 1376 | 1425 | const target = self.target.*; |
| 1377 | 1426 | switch (tag) { |
| 1378 | | // Arithmetic operations on integers and floats |
| 1379 | 1427 | .add, |
| 1380 | 1428 | .sub, |
| 1381 | 1429 | .cmp_eq, |
| ... | ... | @@ -1403,13 +1451,26 @@ fn binOp( |
| 1403 | 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 | 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 | 1469 | } else if (lhs_immediate_ok) { |
| 1409 | 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 | 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 | 1475 | } else { |
| 1415 | 1476 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1428,7 +1489,7 @@ fn binOp( |
| 1428 | 1489 | // TODO add optimisations for multiplication |
| 1429 | 1490 | // with immediates, for example a * 2 can be |
| 1430 | 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 | 1493 | } else { |
| 1433 | 1494 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1434 | 1495 | } |
| ... | ... | @@ -1436,7 +1497,36 @@ fn binOp( |
| 1436 | 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 | 1530 | .bit_and, |
| 1441 | 1531 | .bit_or, |
| 1442 | 1532 | .xor, |
| ... | ... | @@ -1448,7 +1538,14 @@ fn binOp( |
| 1448 | 1538 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1449 | 1539 | if (int_info.bits <= 64) { |
| 1450 | 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 | 1549 | } else { |
| 1453 | 1550 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1454 | 1551 | } |
| ... | ... | @@ -1456,8 +1553,8 @@ fn binOp( |
| 1456 | 1553 | else => unreachable, |
| 1457 | 1554 | } |
| 1458 | 1555 | }, |
| 1459 | | .shl, |
| 1460 | | .shr, |
| 1556 | .shl_exact, |
| 1557 | .shr_exact, |
| 1461 | 1558 | => { |
| 1462 | 1559 | switch (lhs_ty.zigTypeTag()) { |
| 1463 | 1560 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | ... | @@ -1466,10 +1563,27 @@ fn binOp( |
| 1466 | 1563 | if (int_info.bits <= 64) { |
| 1467 | 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 | 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 | 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 | 1588 | } else { |
| 1475 | 1589 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| ... | ... | @@ -1478,6 +1592,38 @@ fn binOp( |
| 1478 | 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 | 1627 | .bool_and, |
| 1482 | 1628 | .bool_or, |
| 1483 | 1629 | => { |
| ... | ... | @@ -1486,7 +1632,13 @@ fn binOp( |
| 1486 | 1632 | assert(lhs != .immediate); // should have been handled by Sema |
| 1487 | 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 | 1643 | else => unreachable, |
| 1492 | 1644 | } |
| ... | ... | @@ -1504,9 +1656,9 @@ fn binOp( |
| 1504 | 1656 | const elem_size = elem_ty.abiSize(self.target.*); |
| 1505 | 1657 | |
| 1506 | 1658 | if (elem_size == 1) { |
| 1507 | | const base_tag: Air.Inst.Tag = switch (tag) { |
| 1508 | | .ptr_add => .add, |
| 1509 | | .ptr_sub => .sub, |
| 1659 | const base_tag: Mir.Inst.Tag = switch (tag) { |
| 1660 | .ptr_add => .add_shifted_register, |
| 1661 | .ptr_sub => .sub_shifted_register, |
| 1510 | 1662 | else => unreachable, |
| 1511 | 1663 | }; |
| 1512 | 1664 | |
| ... | ... | @@ -1538,36 +1690,18 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1538 | 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 | 1693 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1548 | 1694 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1549 | 1695 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch}); |
| 1550 | 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 | 1699 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1560 | 1700 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1561 | 1701 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch}); |
| 1562 | 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 | 1705 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1572 | 1706 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1573 | 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 | 2095 | .undef => unreachable, |
| 1962 | 2096 | .compare_flags_signed, .compare_flags_unsigned => unreachable, |
| 1963 | 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 | 2100 | .stack_offset => |off| { |
| 1967 | 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 | 2104 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 1970 | 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 | 2136 | .got_load, |
| 2002 | 2137 | .direct_load, |
| 2003 | 2138 | => { |
| 2004 | | const reg = try self.register_manager.allocReg(null); |
| 2005 | | self.register_manager.freezeRegs(&.{reg}); |
| 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); |
| 2139 | const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 2140 | try self.load(dst_mcv, .{ .register = addr_reg }, ptr_ty); |
| 2010 | 2141 | }, |
| 2011 | 2142 | } |
| 2012 | 2143 | } |
| ... | ... | @@ -2091,6 +2222,7 @@ fn genInlineMemcpy( |
| 2091 | 2222 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2092 | 2223 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2093 | 2224 | const elem_ty = self.air.typeOfIndex(inst); |
| 2225 | const elem_size = elem_ty.abiSize(self.target.*); |
| 2094 | 2226 | const result: MCValue = result: { |
| 2095 | 2227 | if (!elem_ty.hasRuntimeBits()) |
| 2096 | 2228 | break :result MCValue.none; |
| ... | ... | @@ -2101,9 +2233,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2101 | 2233 | break :result MCValue.dead; |
| 2102 | 2234 | |
| 2103 | 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 | 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 | 2242 | } else { |
| 2108 | 2243 | break :blk try self.allocRegOrMem(inst, true); |
| 2109 | 2244 | } |
| ... | ... | @@ -2114,101 +2249,52 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2114 | 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 { |
| 2118 | | switch (abi_size) { |
| 2119 | | 1 => { |
| 2120 | | _ = try self.addInst(.{ |
| 2121 | | .tag = .ldrb_immediate, |
| 2122 | | .data = .{ .load_store_register_immediate = .{ |
| 2123 | | .rt = value_reg.to32(), |
| 2124 | | .rn = addr_reg, |
| 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 | | }, |
| 2252 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 2253 | const abi_size = ty.abiSize(self.target.*); |
| 2254 | |
| 2255 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2256 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, |
| 2257 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, |
| 2258 | 4 => .ldr_immediate, |
| 2259 | 8 => .ldr_immediate, |
| 2159 | 2260 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), |
| 2160 | 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 { |
| 2165 | | switch (abi_size) { |
| 2166 | | 1 => { |
| 2167 | | _ = try self.addInst(.{ |
| 2168 | | .tag = .strb_immediate, |
| 2169 | | .data = .{ .load_store_register_immediate = .{ |
| 2170 | | .rt = value_reg.to32(), |
| 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 | | }, |
| 2274 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 2275 | const abi_size = ty.abiSize(self.target.*); |
| 2276 | |
| 2277 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 2278 | 1 => .strb_immediate, |
| 2279 | 2 => .strh_immediate, |
| 2280 | 4, 8 => .str_immediate, |
| 2206 | 2281 | 3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}), |
| 2207 | 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 | 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 | 2298 | switch (ptr) { |
| 2213 | 2299 | .none => unreachable, |
| 2214 | 2300 | .undef => unreachable, |
| ... | ... | @@ -2226,14 +2312,14 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2226 | 2312 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2227 | 2313 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 2228 | 2314 | |
| 2229 | | const abi_size = value_ty.abiSize(self.target.*); |
| 2230 | 2315 | switch (value) { |
| 2231 | 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 | 2319 | else => { |
| 2235 | 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 | 2323 | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 2238 | 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 | 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 | 3560 | _ = try self.addInst(.{ |
| 3475 | 3561 | .tag = .movk, |
| 3476 | 3562 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 16), .hw = 1 } }, |
| 3477 | 3563 | }); |
| 3478 | 3564 | } |
| 3479 | | if (x > math.maxInt(u32)) { |
| 3480 | | _ = try self.addInst(.{ |
| 3481 | | .tag = .movk, |
| 3482 | | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } }, |
| 3483 | | }); |
| 3484 | | } |
| 3485 | | if (x > math.maxInt(u48)) { |
| 3486 | | _ = try self.addInst(.{ |
| 3487 | | .tag = .movk, |
| 3488 | | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } }, |
| 3489 | | }); |
| 3565 | |
| 3566 | if (reg.size() == 64) { |
| 3567 | if (x & 0x0000_ffff_0000_0000 != 0) { |
| 3568 | _ = try self.addInst(.{ |
| 3569 | .tag = .movk, |
| 3570 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 32), .hw = 2 } }, |
| 3571 | }); |
| 3572 | } |
| 3573 | if (x & 0xffff_0000_0000_0000 != 0) { |
| 3574 | _ = try self.addInst(.{ |
| 3575 | .tag = .movk, |
| 3576 | .data = .{ .r_imm16_sh = .{ .rd = reg, .imm16 = @truncate(u16, x >> 48), .hw = 3 } }, |
| 3577 | }); |
| 3578 | } |
| 3490 | 3579 | } |
| 3491 | 3580 | }, |
| 3492 | 3581 | .register => |src_reg| { |
| ... | ... | @@ -3522,8 +3611,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3522 | 3611 | .memory => |addr| { |
| 3523 | 3612 | // The value is in memory at a hard-coded address. |
| 3524 | 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 }); |
| 3526 | | try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); |
| 3614 | try self.genSetReg(ty, reg.to64(), .{ .immediate = addr }); |
| 3615 | try self.genLdrRegister(reg, reg.to64(), ty); |
| 3527 | 3616 | }, |
| 3528 | 3617 | .stack_offset => |off| { |
| 3529 | 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 | 3620 | switch (abi_size) { |
| 3532 | 3621 | 1, 2, 4, 8 => { |
| 3533 | 3622 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3534 | | 1 => .ldrb_stack, |
| 3535 | | 2 => .ldrh_stack, |
| 3623 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, |
| 3624 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, |
| 3536 | 3625 | 4, 8 => .ldr_stack, |
| 3537 | 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 | 3629 | _ = try self.addInst(.{ |
| 3546 | 3630 | .tag = tag, |
| 3547 | 3631 | .data = .{ .load_store_stack = .{ |
| 3548 | | .rt = rt, |
| 3632 | .rt = reg, |
| 3549 | 3633 | .offset = @intCast(u32, off), |
| 3550 | 3634 | } }, |
| 3551 | 3635 | }); |
| ... | ... | @@ -3998,6 +4082,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 3998 | 4082 | var nsaa: u32 = 0; // Next stacked argument address |
| 3999 | 4083 | |
| 4000 | 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 | 4091 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 4002 | 4092 | // values to spread across odd-numbered registers. |
| 4003 | 4093 | if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) { |
| ... | ... | @@ -4005,10 +4095,9 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4005 | 4095 | ncrn += ncrn % 2; |
| 4006 | 4096 | } |
| 4007 | 4097 | |
| 4008 | | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 4009 | 4098 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { |
| 4010 | 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 | 4101 | ncrn += 1; |
| 4013 | 4102 | } else { |
| 4014 | 4103 | return self.fail("TODO MCValues with multiple registers", .{}); |
| ... | ... | @@ -4045,7 +4134,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4045 | 4134 | .Unspecified, .C => { |
| 4046 | 4135 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 4047 | 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 | 4138 | } else { |
| 4050 | 4139 | return self.fail("TODO support more return types for ARM backend", .{}); |
| 4051 | 4140 | } |