authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-20 09:44:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-20 09:44:43+02:00
log1a1b5ee264d8b2219c34d53cc9602692e6d2ba24
tree6ccf27612a093414ed1e50933a27bde1bc6920f7
parente3cbea934ee196b3833f4c4269bc3b2796c11928
parentfa85a739d9a85084fbb6d934c2c8803042fa7d48
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11462 from joachimschmidt557/stage2-aarch64

stage2 AArch64: truncation support

7 files changed, 611 insertions(+), 364 deletions(-)

src/arch/aarch64/CodeGen.zig+336-247
...@@ -376,7 +376,7 @@ fn gen(self: *Self) !void {...@@ -376,7 +376,7 @@ fn gen(self: *Self) !void {
376 // mov fp, sp376 // 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 });
381381
382 // sub sp, sp, #reloc382 // 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_size453 // 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 });
458458
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: off513 // 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.
884fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {884fn 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.
893fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {894fn 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}
938941
942fn 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
977fn 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
939fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1024fn 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}
9481036
949fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {1037fn 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 }
10051093
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 };
10081097
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 });
10191108
...@@ -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 }
10371126
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 };
10401130
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 });
10501140
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.
1104fn binOpRegister(1196fn 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;
11261218
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});
11291222
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;
11411234
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});
11441238
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);
11621257
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);
11651260
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.
1256fn binOpImmediate(1319fn 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;
12781341
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});
12811345
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});
12871351
1288 const dest_reg = switch (tag) {1352 const dest_reg = switch (mir_tag) {
1289 .cmp_eq => undefined, // cmp has no destination register1353 .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;
12921356
...@@ -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 };
13051370
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);
13071372
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 };
14051453
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 rhs1470 // 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 multiplication1489 // TODO add optimisations for multiplication
1429 // with immediates, for example a * 2 can be1490 // with immediates, for example a * 2 can be
1430 // lowered to a << 11491 // 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 integers1500 .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 immediates1540 // 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;
14681565
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 Sema1632 assert(lhs != .immediate); // should have been handled by Sema
1487 assert(rhs != .immediate); // should have been handled by Sema1633 assert(rhs != .immediate); // should have been handled by Sema
14881634
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.*);
15051657
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 };
15121664
...@@ -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}
15401692
1541fn 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
1547fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {1693fn 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}
15521698
1553fn 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
1559fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {1699fn 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}
15641704
1565fn 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
1571fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {1705fn 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});
19712106
...@@ -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(
2091fn airLoad(self: *Self, inst: Air.Inst.Index) !void {2222fn 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;
21022234
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}
21162251
2117fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {2252fn 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}
21632273
2164fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {2274fn 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}
22102294
2211fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {2295fn 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});
22282314
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});
22392325
...@@ -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 });
34723558
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 size3626 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 };
35443628
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 address4082 var nsaa: u32 = 0; // Next stacked argument address
39994083
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 aligned4091 // 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 }
40074097
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 }
src/arch/aarch64/Emit.zig+87-11
...@@ -131,6 +131,8 @@ pub fn emitMir(...@@ -131,6 +131,8 @@ pub fn emitMir(
131 .ldr_stack => try emit.mirLoadStoreStack(inst),131 .ldr_stack => try emit.mirLoadStoreStack(inst),
132 .ldrb_stack => try emit.mirLoadStoreStack(inst),132 .ldrb_stack => try emit.mirLoadStoreStack(inst),
133 .ldrh_stack => try emit.mirLoadStoreStack(inst),133 .ldrh_stack => try emit.mirLoadStoreStack(inst),
134 .ldrsb_stack => try emit.mirLoadStoreStack(inst),
135 .ldrsh_stack => try emit.mirLoadStoreStack(inst),
134 .str_stack => try emit.mirLoadStoreStack(inst),136 .str_stack => try emit.mirLoadStoreStack(inst),
135 .strb_stack => try emit.mirLoadStoreStack(inst),137 .strb_stack => try emit.mirLoadStoreStack(inst),
136 .strh_stack => try emit.mirLoadStoreStack(inst),138 .strh_stack => try emit.mirLoadStoreStack(inst),
...@@ -145,6 +147,9 @@ pub fn emitMir(...@@ -145,6 +147,9 @@ pub fn emitMir(
145 .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),147 .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
146 .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),148 .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
147 .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),149 .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150 .ldrsb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
151 .ldrsh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
152 .ldrsw_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
148 .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),153 .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
149 .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),154 .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
150 .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),155 .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
...@@ -162,6 +167,17 @@ pub fn emitMir(...@@ -162,6 +167,17 @@ pub fn emitMir(
162167
163 .push_regs => try emit.mirPushPopRegs(inst),168 .push_regs => try emit.mirPushPopRegs(inst),
164 .pop_regs => try emit.mirPushPopRegs(inst),169 .pop_regs => try emit.mirPushPopRegs(inst),
170
171 .sbfx,
172 .ubfx,
173 => try emit.mirBitfieldExtract(inst),
174
175 .sxtb,
176 .sxth,
177 .sxtw,
178 .uxtb,
179 .uxth,
180 => try emit.mirExtend(inst),
165 }181 }
166 }182 }
167}183}
...@@ -457,8 +473,13 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -457,8 +473,13 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
457 const rn = r_imm12_sh.rn;473 const rn = r_imm12_sh.rn;
458 const imm12 = r_imm12_sh.imm12;474 const imm12 = r_imm12_sh.imm12;
459 const sh = r_imm12_sh.sh == 1;475 const sh = r_imm12_sh.sh == 1;
476 const zr: Register = switch (rn.size()) {
477 32 => .wzr,
478 64 => .xzr,
479 else => unreachable,
480 };
460481
461 try emit.writeInstruction(Instruction.subs(.xzr, rn, imm12, sh));482 try emit.writeInstruction(Instruction.subs(zr, rn, imm12, sh));
462 },483 },
463 else => unreachable,484 else => unreachable,
464 }485 }
...@@ -674,8 +695,13 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -674,8 +695,13 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
674 const rm = rr_imm6_shift.rm;695 const rm = rr_imm6_shift.rm;
675 const shift = rr_imm6_shift.shift;696 const shift = rr_imm6_shift.shift;
676 const imm6 = rr_imm6_shift.imm6;697 const imm6 = rr_imm6_shift.imm6;
698 const zr: Register = switch (rn.size()) {
699 32 => .wzr,
700 64 => .xzr,
701 else => unreachable,
702 };
677703
678 try emit.writeInstruction(Instruction.subsShiftedRegister(.xzr, rn, rm, shift, imm6));704 try emit.writeInstruction(Instruction.subsShiftedRegister(zr, rn, rm, shift, imm6));
679 },705 },
680 else => unreachable,706 else => unreachable,
681 }707 }
...@@ -686,7 +712,12 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -686,7 +712,12 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
686 switch (tag) {712 switch (tag) {
687 .cset => {713 .cset => {
688 const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;714 const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
689 try emit.writeInstruction(Instruction.csinc(r_cond.rd, .xzr, .xzr, r_cond.cond));715 const zr: Register = switch (r_cond.rd.size()) {
716 32 => .wzr,
717 64 => .xzr,
718 else => unreachable,
719 };
720 try emit.writeInstruction(Instruction.csinc(r_cond.rd, zr, zr, r_cond.cond));
690 },721 },
691 else => unreachable,722 else => unreachable,
692 }723 }
...@@ -718,14 +749,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -718,14 +749,14 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
718 // PC-relative displacement to the entry in memory.749 // PC-relative displacement to the entry in memory.
719 // adrp750 // adrp
720 const offset = @intCast(u32, emit.code.items.len);751 const offset = @intCast(u32, emit.code.items.len);
721 try emit.writeInstruction(Instruction.adrp(reg, 0));752 try emit.writeInstruction(Instruction.adrp(reg.to64(), 0));
722753
723 switch (tag) {754 switch (tag) {
724 .load_memory_got => {755 .load_memory_got => {
725 // ldr reg, reg, offset756 // ldr reg, reg, offset
726 try emit.writeInstruction(Instruction.ldr(757 try emit.writeInstruction(Instruction.ldr(
727 reg,758 reg,
728 reg,759 reg.to64(),
729 Instruction.LoadStoreOffset.imm(0),760 Instruction.LoadStoreOffset.imm(0),
730 ));761 ));
731 },762 },
...@@ -739,11 +770,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -739,11 +770,11 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
739 // Note that this can potentially be optimised out by the codegen/linker if the770 // Note that this can potentially be optimised out by the codegen/linker if the
740 // target address is appropriately aligned.771 // target address is appropriately aligned.
741 // add reg, reg, offset772 // add reg, reg, offset
742 try emit.writeInstruction(Instruction.add(reg, reg, 0, false));773 try emit.writeInstruction(Instruction.add(reg.to64(), reg.to64(), 0, false));
743 // ldr reg, reg, offset774 // ldr reg, reg, offset
744 try emit.writeInstruction(Instruction.ldr(775 try emit.writeInstruction(Instruction.ldr(
745 reg,776 reg,
746 reg,777 reg.to64(),
747 Instruction.LoadStoreOffset.imm(0),778 Instruction.LoadStoreOffset.imm(0),
748 ));779 ));
749 },780 },
...@@ -821,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -821,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
821852
822 const raw_offset = emit.stack_size - load_store_stack.offset;853 const raw_offset = emit.stack_size - load_store_stack.offset;
823 const offset = switch (tag) {854 const offset = switch (tag) {
824 .ldrb_stack, .strb_stack => blk: {855 .ldrb_stack, .ldrsb_stack, .strb_stack => blk: {
825 if (math.cast(u12, raw_offset)) |imm| {856 if (math.cast(u12, raw_offset)) |imm| {
826 break :blk Instruction.LoadStoreOffset.imm(imm);857 break :blk Instruction.LoadStoreOffset.imm(imm);
827 } else |_| {858 } else |_| {
828 return emit.fail("TODO load/store stack byte with larger offset", .{});859 return emit.fail("TODO load/store stack byte with larger offset", .{});
829 }860 }
830 },861 },
831 .ldrh_stack, .strh_stack => blk: {862 .ldrh_stack, .ldrsh_stack, .strh_stack => blk: {
832 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry863 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
833 if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {864 if (math.cast(u12, @divExact(raw_offset, 2))) |imm| {
834 break :blk Instruction.LoadStoreOffset.imm(imm);865 break :blk Instruction.LoadStoreOffset.imm(imm);
...@@ -857,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -857,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
857 .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),888 .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
858 .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),889 .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
859 .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),890 .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
891 .ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
892 .ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
860 .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),893 .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)),
861 .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),894 .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)),
862 .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),895 .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)),
...@@ -875,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -875,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
875 .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),908 .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)),
876 .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),909 .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)),
877 .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),910 .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)),
911 .ldrsb_immediate => try emit.writeInstruction(Instruction.ldrsb(rt, rn, offset)),
912 .ldrsh_immediate => try emit.writeInstruction(Instruction.ldrsh(rt, rn, offset)),
913 .ldrsw_immediate => try emit.writeInstruction(Instruction.ldrsw(rt, rn, offset)),
878 .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)),914 .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)),
879 .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),915 .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)),
880 .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),916 .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)),
...@@ -905,7 +941,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -905,7 +941,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
905 switch (tag) {941 switch (tag) {
906 .mov_register => {942 .mov_register => {
907 const rr = emit.mir.instructions.items(.data)[inst].rr;943 const rr = emit.mir.instructions.items(.data)[inst].rr;
908 try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, .xzr, rr.rn, .lsl, 0));944 const zr: Register = switch (rr.rd.size()) {
945 32 => .wzr,
946 64 => .xzr,
947 else => unreachable,
948 };
949
950 try emit.writeInstruction(Instruction.orrShiftedRegister(rr.rd, zr, rr.rn, .lsl, 0));
909 },951 },
910 .mov_to_from_sp => {952 .mov_to_from_sp => {
911 const rr = emit.mir.instructions.items(.data)[inst].rr;953 const rr = emit.mir.instructions.items(.data)[inst].rr;
...@@ -917,8 +959,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -917,8 +959,13 @@ fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
917 const rm = rr_imm6_logical_shift.rm;959 const rm = rr_imm6_logical_shift.rm;
918 const shift = rr_imm6_logical_shift.shift;960 const shift = rr_imm6_logical_shift.shift;
919 const imm6 = rr_imm6_logical_shift.imm6;961 const imm6 = rr_imm6_logical_shift.imm6;
962 const zr: Register = switch (rd.size()) {
963 32 => .wzr,
964 64 => .xzr,
965 else => unreachable,
966 };
920967
921 try emit.writeInstruction(Instruction.ornShiftedRegister(rd, .xzr, rm, shift, imm6));968 try emit.writeInstruction(Instruction.ornShiftedRegister(rd, zr, rm, shift, imm6));
922 },969 },
923 else => unreachable,970 else => unreachable,
924 }971 }
...@@ -1024,3 +1071,32 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -1024,3 +1071,32 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
1024 else => unreachable,1071 else => unreachable,
1025 }1072 }
1026}1073}
1074
1075fn mirBitfieldExtract(emit: *Emit, inst: Mir.Inst.Index) !void {
1076 const tag = emit.mir.instructions.items(.tag)[inst];
1077 const rr_lsb_width = emit.mir.instructions.items(.data)[inst].rr_lsb_width;
1078 const rd = rr_lsb_width.rd;
1079 const rn = rr_lsb_width.rn;
1080 const lsb = rr_lsb_width.lsb;
1081 const width = rr_lsb_width.width;
1082
1083 switch (tag) {
1084 .sbfx => try emit.writeInstruction(Instruction.sbfx(rd, rn, lsb, width)),
1085 .ubfx => try emit.writeInstruction(Instruction.ubfx(rd, rn, lsb, width)),
1086 else => unreachable,
1087 }
1088}
1089
1090fn mirExtend(emit: *Emit, inst: Mir.Inst.Index) !void {
1091 const tag = emit.mir.instructions.items(.tag)[inst];
1092 const rr = emit.mir.instructions.items(.data)[inst].rr;
1093
1094 switch (tag) {
1095 .sxtb => try emit.writeInstruction(Instruction.sxtb(rr.rd, rr.rn)),
1096 .sxth => try emit.writeInstruction(Instruction.sxth(rr.rd, rr.rn)),
1097 .sxtw => try emit.writeInstruction(Instruction.sxtw(rr.rd, rr.rn)),
1098 .uxtb => try emit.writeInstruction(Instruction.uxtb(rr.rd, rr.rn)),
1099 .uxth => try emit.writeInstruction(Instruction.uxth(rr.rd, rr.rn)),
1100 else => unreachable,
1101 }
1102}
src/arch/aarch64/Mir.zig+41-7
...@@ -100,6 +100,16 @@ pub const Inst = struct {...@@ -100,6 +100,16 @@ pub const Inst = struct {
100 ldrh_immediate,100 ldrh_immediate,
101 /// Load Register Halfword (register)101 /// Load Register Halfword (register)
102 ldrh_register,102 ldrh_register,
103 /// Load Register Signed Byte (immediate)
104 ldrsb_immediate,
105 /// Pseudo-instruction: Load signed byte from stack
106 ldrsb_stack,
107 /// Load Register Signed Halfword (immediate)
108 ldrsh_immediate,
109 /// Pseudo-instruction: Load signed halfword from stack
110 ldrsh_stack,
111 /// Load Register Signed Word (immediate)
112 ldrsw_immediate,
103 /// Logical Shift Left (immediate)113 /// Logical Shift Left (immediate)
104 lsl_immediate,114 lsl_immediate,
105 /// Logical Shift Left (register)115 /// Logical Shift Left (register)
...@@ -130,6 +140,14 @@ pub const Inst = struct {...@@ -130,6 +140,14 @@ pub const Inst = struct {
130 push_regs,140 push_regs,
131 /// Return from subroutine141 /// Return from subroutine
132 ret,142 ret,
143 /// Signed bitfield extract
144 sbfx,
145 /// Signed extend byte
146 sxtb,
147 /// Signed extend halfword
148 sxth,
149 /// Signed extend word
150 sxtw,
133 /// Store Pair of Registers151 /// Store Pair of Registers
134 stp,152 stp,
135 /// Pseudo-instruction: Store to stack153 /// Pseudo-instruction: Store to stack
...@@ -156,6 +174,12 @@ pub const Inst = struct {...@@ -156,6 +174,12 @@ pub const Inst = struct {
156 sub_shifted_register,174 sub_shifted_register,
157 /// Supervisor Call175 /// Supervisor Call
158 svc,176 svc,
177 /// Unsigned bitfield extract
178 ubfx,
179 /// Unsigned extend byte
180 uxtb,
181 /// Unsigned extend halfword
182 uxth,
159 };183 };
160184
161 /// The position of an MIR instruction within the `Mir` instructions array.185 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -225,13 +249,6 @@ pub const Inst = struct {...@@ -225,13 +249,6 @@ pub const Inst = struct {
225 rt: Register,249 rt: Register,
226 inst: Index,250 inst: Index,
227 },251 },
228 /// Two registers
229 ///
230 /// Used by e.g. mov_register
231 rr: struct {
232 rd: Register,
233 rn: Register,
234 },
235 /// A register, an unsigned 12-bit immediate, and an optional shift252 /// A register, an unsigned 12-bit immediate, and an optional shift
236 ///253 ///
237 /// Used by e.g. cmp_immediate254 /// Used by e.g. cmp_immediate
...@@ -240,6 +257,13 @@ pub const Inst = struct {...@@ -240,6 +257,13 @@ pub const Inst = struct {
240 imm12: u12,257 imm12: u12,
241 sh: u1 = 0,258 sh: u1 = 0,
242 },259 },
260 /// Two registers
261 ///
262 /// Used by e.g. mov_register
263 rr: struct {
264 rd: Register,
265 rn: Register,
266 },
243 /// Two registers, an unsigned 12-bit immediate, and an optional shift267 /// Two registers, an unsigned 12-bit immediate, and an optional shift
244 ///268 ///
245 /// Used by e.g. sub_immediate269 /// Used by e.g. sub_immediate
...@@ -268,6 +292,16 @@ pub const Inst = struct {...@@ -268,6 +292,16 @@ pub const Inst = struct {
268 imm6: u6,292 imm6: u6,
269 shift: bits.Instruction.LogicalShiftedRegisterShift,293 shift: bits.Instruction.LogicalShiftedRegisterShift,
270 },294 },
295 /// Two registers and a lsb (range 0-63) and a width (range
296 /// 1-64)
297 ///
298 /// Used by e.g. ubfx
299 rr_lsb_width: struct {
300 rd: Register,
301 rn: Register,
302 lsb: u6,
303 width: u7,
304 },
271 /// Two registers and a bitmask immediate305 /// Two registers and a bitmask immediate
272 ///306 ///
273 /// Used by e.g. eor_immediate307 /// Used by e.g. eor_immediate
src/arch/aarch64/bits.zig+147-79
...@@ -510,33 +510,23 @@ pub const Instruction = union(enum) {...@@ -510,33 +510,23 @@ pub const Instruction = union(enum) {
510 imm16: u16,510 imm16: u16,
511 shift: u6,511 shift: u6,
512 ) Instruction {512 ) Instruction {
513 switch (rd.size()) {513 assert(shift % 16 == 0);
514 32 => {514 assert(!(rd.size() == 32 and shift > 16));
515 assert(shift % 16 == 0 and shift <= 16);515 assert(!(rd.size() == 64 and shift > 48));
516 return Instruction{516
517 .move_wide_immediate = .{517 return Instruction{
518 .rd = rd.enc(),518 .move_wide_immediate = .{
519 .imm16 = imm16,519 .rd = rd.enc(),
520 .hw = @intCast(u2, shift / 16),520 .imm16 = imm16,
521 .opc = opc,521 .hw = @intCast(u2, shift / 16),
522 .sf = 0,522 .opc = opc,
523 },523 .sf = switch (rd.size()) {
524 };524 32 => 0,
525 },525 64 => 1,
526 64 => {526 else => unreachable, // unexpected register size
527 assert(shift % 16 == 0 and shift <= 48);527 },
528 return Instruction{
529 .move_wide_immediate = .{
530 .rd = rd.enc(),
531 .imm16 = imm16,
532 .hw = @intCast(u2, shift / 16),
533 .opc = opc,
534 .sf = 1,
535 },
536 };
537 },528 },
538 else => unreachable, // unexpected register size529 };
539 }
540 }530 }
541531
542 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {532 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {
...@@ -675,18 +665,24 @@ pub const Instruction = union(enum) {...@@ -675,18 +665,24 @@ pub const Instruction = union(enum) {
675665
676 /// Which kind of load/store to perform666 /// Which kind of load/store to perform
677 const LoadStoreVariant = enum {667 const LoadStoreVariant = enum {
678 /// 32-bit or 64-bit668 /// 32 bits or 64 bits
679 str,669 str,
680 /// 16-bit, zero-extended670 /// 8 bits, zero-extended
681 strh,
682 /// 8-bit, zero-extended
683 strb,671 strb,
684 /// 32-bit or 64-bit672 /// 16 bits, zero-extended
673 strh,
674 /// 32 bits or 64 bits
685 ldr,675 ldr,
686 /// 16-bit, zero-extended676 /// 8 bits, zero-extended
687 ldrh,
688 /// 8-bit, zero-extended
689 ldrb,677 ldrb,
678 /// 16 bits, zero-extended
679 ldrh,
680 /// 8 bits, sign extended
681 ldrsb,
682 /// 16 bits, sign extended
683 ldrsh,
684 /// 32 bits, sign extended
685 ldrsw,
690 };686 };
691687
692 fn loadStoreRegister(688 fn loadStoreRegister(
...@@ -695,7 +691,11 @@ pub const Instruction = union(enum) {...@@ -695,7 +691,11 @@ pub const Instruction = union(enum) {
695 offset: LoadStoreOffset,691 offset: LoadStoreOffset,
696 variant: LoadStoreVariant,692 variant: LoadStoreVariant,
697 ) Instruction {693 ) Instruction {
694 assert(rn.size() == 64);
695 assert(rn.id() != Register.xzr.id());
696
698 const off = offset.toU12();697 const off = offset.toU12();
698
699 const op1: u2 = blk: {699 const op1: u2 = blk: {
700 switch (offset) {700 switch (offset) {
701 .immediate => |imm| switch (imm) {701 .immediate => |imm| switch (imm) {
...@@ -706,10 +706,35 @@ pub const Instruction = union(enum) {...@@ -706,10 +706,35 @@ pub const Instruction = union(enum) {
706 }706 }
707 break :blk 0b00;707 break :blk 0b00;
708 };708 };
709 const opc: u2 = switch (variant) {709
710 .ldr, .ldrh, .ldrb => 0b01,710 const opc: u2 = blk: {
711 .str, .strh, .strb => 0b00,711 switch (variant) {
712 .ldr, .ldrh, .ldrb => break :blk 0b01,
713 .str, .strh, .strb => break :blk 0b00,
714 .ldrsb,
715 .ldrsh,
716 => switch (rt.size()) {
717 32 => break :blk 0b11,
718 64 => break :blk 0b10,
719 else => unreachable, // unexpected register size
720 },
721 .ldrsw => break :blk 0b10,
722 }
723 };
724
725 const size: u2 = blk: {
726 switch (variant) {
727 .ldr, .str => switch (rt.size()) {
728 32 => break :blk 0b10,
729 64 => break :blk 0b11,
730 else => unreachable, // unexpected register size
731 },
732 .ldrsw => break :blk 0b10,
733 .ldrh, .ldrsh, .strh => break :blk 0b01,
734 .ldrb, .ldrsb, .strb => break :blk 0b00,
735 }
712 };736 };
737
713 return Instruction{738 return Instruction{
714 .load_store_register = .{739 .load_store_register = .{
715 .rt = rt.enc(),740 .rt = rt.enc(),
...@@ -718,17 +743,7 @@ pub const Instruction = union(enum) {...@@ -718,17 +743,7 @@ pub const Instruction = union(enum) {
718 .opc = opc,743 .opc = opc,
719 .op1 = op1,744 .op1 = op1,
720 .v = 0,745 .v = 0,
721 .size = blk: {746 .size = size,
722 switch (variant) {
723 .ldr, .str => switch (rt.size()) {
724 32 => break :blk 0b10,
725 64 => break :blk 0b11,
726 else => unreachable, // unexpected register size
727 },
728 .ldrh, .strh => break :blk 0b01,
729 .ldrb, .strb => break :blk 0b00,
730 }
731 },
732 },747 },
733 };748 };
734 }749 }
...@@ -741,6 +756,9 @@ pub const Instruction = union(enum) {...@@ -741,6 +756,9 @@ pub const Instruction = union(enum) {
741 encoding: u2,756 encoding: u2,
742 load: bool,757 load: bool,
743 ) Instruction {758 ) Instruction {
759 assert(rn.size() == 64);
760 assert(rn.id() != Register.xzr.id());
761
744 switch (rt1.size()) {762 switch (rt1.size()) {
745 32 => {763 32 => {
746 assert(-256 <= offset and offset <= 252);764 assert(-256 <= offset and offset <= 252);
...@@ -849,38 +867,26 @@ pub const Instruction = union(enum) {...@@ -849,38 +867,26 @@ pub const Instruction = union(enum) {
849 shift: LogicalShiftedRegisterShift,867 shift: LogicalShiftedRegisterShift,
850 amount: u6,868 amount: u6,
851 ) Instruction {869 ) Instruction {
852 switch (rd.size()) {870 assert(rd.size() == rn.size());
853 32 => {871 assert(rd.size() == rm.size());
854 assert(amount < 32);872 if (rd.size() == 32) assert(amount < 32);
855 return Instruction{873
856 .logical_shifted_register = .{874 return Instruction{
857 .rd = rd.enc(),875 .logical_shifted_register = .{
858 .rn = rn.enc(),876 .rd = rd.enc(),
859 .imm6 = amount,877 .rn = rn.enc(),
860 .rm = rm.enc(),878 .imm6 = amount,
861 .n = n,879 .rm = rm.enc(),
862 .shift = @enumToInt(shift),880 .n = n,
863 .opc = opc,881 .shift = @enumToInt(shift),
864 .sf = 0b0,882 .opc = opc,
865 },883 .sf = switch (rd.size()) {
866 };884 32 => 0b0,
867 },885 64 => 0b1,
868 64 => {886 else => unreachable,
869 return Instruction{887 },
870 .logical_shifted_register = .{
871 .rd = rd.enc(),
872 .rn = rn.enc(),
873 .imm6 = amount,
874 .rm = rm.enc(),
875 .n = n,
876 .shift = @enumToInt(shift),
877 .opc = opc,
878 .sf = 0b1,
879 },
880 };
881 },888 },
882 else => unreachable, // unexpected register size889 };
883 }
884 }890 }
885891
886 fn addSubtractImmediate(892 fn addSubtractImmediate(
...@@ -891,6 +897,9 @@ pub const Instruction = union(enum) {...@@ -891,6 +897,9 @@ pub const Instruction = union(enum) {
891 imm12: u12,897 imm12: u12,
892 shift: bool,898 shift: bool,
893 ) Instruction {899 ) Instruction {
900 assert(rd.size() == rn.size());
901 assert(rn.id() != Register.xzr.id());
902
894 return Instruction{903 return Instruction{
895 .add_subtract_immediate = .{904 .add_subtract_immediate = .{
896 .rd = rd.enc(),905 .rd = rd.enc(),
...@@ -916,6 +925,9 @@ pub const Instruction = union(enum) {...@@ -916,6 +925,9 @@ pub const Instruction = union(enum) {
916 immr: u6,925 immr: u6,
917 n: u1,926 n: u1,
918 ) Instruction {927 ) Instruction {
928 assert(rd.size() == rn.size());
929 assert(!(rd.size() == 32 and n != 0));
930
919 return Instruction{931 return Instruction{
920 .logical_immediate = .{932 .logical_immediate = .{
921 .rd = rd.enc(),933 .rd = rd.enc(),
...@@ -941,6 +953,10 @@ pub const Instruction = union(enum) {...@@ -941,6 +953,10 @@ pub const Instruction = union(enum) {
941 immr: u6,953 immr: u6,
942 imms: u6,954 imms: u6,
943 ) Instruction {955 ) Instruction {
956 assert(rd.size() == rn.size());
957 assert(!(rd.size() == 64 and n != 1));
958 assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0)));
959
944 return Instruction{960 return Instruction{
945 .bitfield = .{961 .bitfield = .{
946 .rd = rd.enc(),962 .rd = rd.enc(),
...@@ -969,6 +985,9 @@ pub const Instruction = union(enum) {...@@ -969,6 +985,9 @@ pub const Instruction = union(enum) {
969 rm: Register,985 rm: Register,
970 imm6: u6,986 imm6: u6,
971 ) Instruction {987 ) Instruction {
988 assert(rd.size() == rn.size());
989 assert(rd.size() == rm.size());
990
972 return Instruction{991 return Instruction{
973 .add_subtract_shifted_register = .{992 .add_subtract_shifted_register = .{
974 .rd = rd.enc(),993 .rd = rd.enc(),
...@@ -994,6 +1013,7 @@ pub const Instruction = union(enum) {...@@ -994,6 +1013,7 @@ pub const Instruction = union(enum) {
994 offset: i21,1013 offset: i21,
995 ) Instruction {1014 ) Instruction {
996 assert(offset & 0b11 == 0b00);1015 assert(offset & 0b11 == 0b00);
1016
997 return Instruction{1017 return Instruction{
998 .conditional_branch = .{1018 .conditional_branch = .{
999 .cond = @enumToInt(cond),1019 .cond = @enumToInt(cond),
...@@ -1010,6 +1030,7 @@ pub const Instruction = union(enum) {...@@ -1010,6 +1030,7 @@ pub const Instruction = union(enum) {
1010 offset: i21,1030 offset: i21,
1011 ) Instruction {1031 ) Instruction {
1012 assert(offset & 0b11 == 0b00);1032 assert(offset & 0b11 == 0b00);
1033
1013 return Instruction{1034 return Instruction{
1014 .compare_and_branch = .{1035 .compare_and_branch = .{
1015 .rt = rt.enc(),1036 .rt = rt.enc(),
...@@ -1033,6 +1054,9 @@ pub const Instruction = union(enum) {...@@ -1033,6 +1054,9 @@ pub const Instruction = union(enum) {
1033 rm: Register,1054 rm: Register,
1034 cond: Condition,1055 cond: Condition,
1035 ) Instruction {1056 ) Instruction {
1057 assert(rd.size() == rn.size());
1058 assert(rd.size() == rm.size());
1059
1036 return Instruction{1060 return Instruction{
1037 .conditional_select = .{1061 .conditional_select = .{
1038 .rd = rd.enc(),1062 .rd = rd.enc(),
...@@ -1085,6 +1109,9 @@ pub const Instruction = union(enum) {...@@ -1085,6 +1109,9 @@ pub const Instruction = union(enum) {
1085 rn: Register,1109 rn: Register,
1086 rm: Register,1110 rm: Register,
1087 ) Instruction {1111 ) Instruction {
1112 assert(rd.size() == rn.size());
1113 assert(rd.size() == rm.size());
1114
1088 return Instruction{1115 return Instruction{
1089 .data_processing_2_source = .{1116 .data_processing_2_source = .{
1090 .rd = rd.enc(),1117 .rd = rd.enc(),
...@@ -1145,6 +1172,18 @@ pub const Instruction = union(enum) {...@@ -1145,6 +1172,18 @@ pub const Instruction = union(enum) {
1145 return loadStoreRegister(rt, rn, offset, .ldrb);1172 return loadStoreRegister(rt, rn, offset, .ldrb);
1146 }1173 }
11471174
1175 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1176 return loadStoreRegister(rt, rn, offset, .ldrsb);
1177 }
1178
1179 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1180 return loadStoreRegister(rt, rn, offset, .ldrsh);
1181 }
1182
1183 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1184 return loadStoreRegister(rt, rn, offset, .ldrsw);
1185 }
1186
1148 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {1187 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1149 return loadStoreRegister(rt, rn, offset, .str);1188 return loadStoreRegister(rt, rn, offset, .str);
1150 }1189 }
...@@ -1404,6 +1443,23 @@ pub const Instruction = union(enum) {...@@ -1404,6 +1443,23 @@ pub const Instruction = union(enum) {
1404 return sbfm(rd, rn, shift, imms);1443 return sbfm(rd, rn, shift, imms);
1405 }1444 }
14061445
1446 pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1447 return sbfm(rd, rn, lsb, @intCast(u6, lsb + width - 1));
1448 }
1449
1450 pub fn sxtb(rd: Register, rn: Register) Instruction {
1451 return sbfm(rd, rn, 0, 7);
1452 }
1453
1454 pub fn sxth(rd: Register, rn: Register) Instruction {
1455 return sbfm(rd, rn, 0, 15);
1456 }
1457
1458 pub fn sxtw(rd: Register, rn: Register) Instruction {
1459 assert(rd.size() == 64);
1460 return sbfm(rd, rn, 0, 31);
1461 }
1462
1407 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {1463 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1408 const size = @intCast(u6, rd.size() - 1);1464 const size = @intCast(u6, rd.size() - 1);
1409 return ubfm(rd, rn, size - shift + 1, size - shift);1465 return ubfm(rd, rn, size - shift + 1, size - shift);
...@@ -1414,6 +1470,18 @@ pub const Instruction = union(enum) {...@@ -1414,6 +1470,18 @@ pub const Instruction = union(enum) {
1414 return ubfm(rd, rn, shift, imms);1470 return ubfm(rd, rn, shift, imms);
1415 }1471 }
14161472
1473 pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1474 return ubfm(rd, rn, lsb, @intCast(u6, lsb + width - 1));
1475 }
1476
1477 pub fn uxtb(rd: Register, rn: Register) Instruction {
1478 return ubfm(rd, rn, 0, 7);
1479 }
1480
1481 pub fn uxth(rd: Register, rn: Register) Instruction {
1482 return ubfm(rd, rn, 0, 15);
1483 }
1484
1417 // Add/subtract (shifted register)1485 // Add/subtract (shifted register)
14181486
1419 pub fn addShiftedRegister(1487 pub fn addShiftedRegister(
test/behavior/basic.zig-4
...@@ -15,8 +15,6 @@ test "empty function with comments" {...@@ -15,8 +15,6 @@ test "empty function with comments" {
15}15}
1616
17test "truncate" {17test "truncate" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19
20 try expect(testTruncate(0x10fd) == 0xfd);18 try expect(testTruncate(0x10fd) == 0xfd);
21 comptime try expect(testTruncate(0x10fd) == 0xfd);19 comptime try expect(testTruncate(0x10fd) == 0xfd);
22}20}
...@@ -25,8 +23,6 @@ fn testTruncate(x: u32) u8 {...@@ -25,8 +23,6 @@ fn testTruncate(x: u32) u8 {
25}23}
2624
27test "truncate to non-power-of-two integers" {25test "truncate to non-power-of-two integers" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29
30 try testTrunc(u32, u1, 0b10101, 0b1);26 try testTrunc(u32, u1, 0b10101, 0b1);
31 try testTrunc(u32, u1, 0b10110, 0b0);27 try testTrunc(u32, u1, 0b10110, 0b0);
32 try testTrunc(u32, u2, 0b10101, 0b01);28 try testTrunc(u32, u2, 0b10101, 0b01);
test/behavior/math.zig-14
...@@ -363,7 +363,6 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int...@@ -363,7 +363,6 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int
363test "binary not" {363test "binary not" {
364 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO364 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO365 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
367366
368 try expect(comptime x: {367 try expect(comptime x: {
369 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;368 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
...@@ -499,8 +498,6 @@ fn mod(comptime T: type, a: T, b: T) T {...@@ -499,8 +498,6 @@ fn mod(comptime T: type, a: T, b: T) T {
499}498}
500499
501test "unsigned wrapping" {500test "unsigned wrapping" {
502 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
503
504 try testUnsignedWrappingEval(maxInt(u32));501 try testUnsignedWrappingEval(maxInt(u32));
505 comptime try testUnsignedWrappingEval(maxInt(u32));502 comptime try testUnsignedWrappingEval(maxInt(u32));
506}503}
...@@ -512,8 +509,6 @@ fn testUnsignedWrappingEval(x: u32) !void {...@@ -512,8 +509,6 @@ fn testUnsignedWrappingEval(x: u32) !void {
512}509}
513510
514test "signed wrapping" {511test "signed wrapping" {
515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
516
517 try testSignedWrappingEval(maxInt(i32));512 try testSignedWrappingEval(maxInt(i32));
518 comptime try testSignedWrappingEval(maxInt(i32));513 comptime try testSignedWrappingEval(maxInt(i32));
519}514}
...@@ -525,8 +520,6 @@ fn testSignedWrappingEval(x: i32) !void {...@@ -525,8 +520,6 @@ fn testSignedWrappingEval(x: i32) !void {
525}520}
526521
527test "signed negation wrapping" {522test "signed negation wrapping" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529
530 try testSignedNegationWrappingEval(minInt(i16));523 try testSignedNegationWrappingEval(minInt(i16));
531 comptime try testSignedNegationWrappingEval(minInt(i16));524 comptime try testSignedNegationWrappingEval(minInt(i16));
532}525}
...@@ -537,8 +530,6 @@ fn testSignedNegationWrappingEval(x: i16) !void {...@@ -537,8 +530,6 @@ fn testSignedNegationWrappingEval(x: i16) !void {
537}530}
538531
539test "unsigned negation wrapping" {532test "unsigned negation wrapping" {
540 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
541
542 try testUnsignedNegationWrappingEval(1);533 try testUnsignedNegationWrappingEval(1);
543 comptime try testUnsignedNegationWrappingEval(1);534 comptime try testUnsignedNegationWrappingEval(1);
544}535}
...@@ -859,8 +850,6 @@ test "quad hex float literal parsing accurate" {...@@ -859,8 +850,6 @@ test "quad hex float literal parsing accurate" {
859}850}
860851
861test "truncating shift left" {852test "truncating shift left" {
862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
863
864 try testShlTrunc(maxInt(u16));853 try testShlTrunc(maxInt(u16));
865 comptime try testShlTrunc(maxInt(u16));854 comptime try testShlTrunc(maxInt(u16));
866}855}
...@@ -871,7 +860,6 @@ fn testShlTrunc(x: u16) !void {...@@ -871,7 +860,6 @@ fn testShlTrunc(x: u16) !void {
871860
872test "exact shift left" {861test "exact shift left" {
873 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO862 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
875863
876 try testShlExact(0b00110101);864 try testShlExact(0b00110101);
877 comptime try testShlExact(0b00110101);865 comptime try testShlExact(0b00110101);
...@@ -883,7 +871,6 @@ fn testShlExact(x: u8) !void {...@@ -883,7 +871,6 @@ fn testShlExact(x: u8) !void {
883871
884test "exact shift right" {872test "exact shift right" {
885 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO873 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
887874
888 try testShrExact(0b10110100);875 try testShrExact(0b10110100);
889 comptime try testShrExact(0b10110100);876 comptime try testShrExact(0b10110100);
...@@ -895,7 +882,6 @@ fn testShrExact(x: u8) !void {...@@ -895,7 +882,6 @@ fn testShrExact(x: u8) !void {
895882
896test "shift left/right on u0 operand" {883test "shift left/right on u0 operand" {
897 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO884 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
899885
900 const S = struct {886 const S = struct {
901 fn doTheTest() !void {887 fn doTheTest() !void {
test/behavior/truncate.zig-2
...@@ -49,8 +49,6 @@ test "truncate.i0.var" {...@@ -49,8 +49,6 @@ test "truncate.i0.var" {
49}49}
5050
51test "truncate on comptime integer" {51test "truncate on comptime integer" {
52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
53
54 var x = @truncate(u16, 9999);52 var x = @truncate(u16, 9999);
55 try expect(x == 9999);53 try expect(x == 9999);
56 var y = @truncate(u16, -21555);54 var y = @truncate(u16, -21555);