authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-15 07:05:24+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-15 07:05:24+01:00
logbe98f30a2d647075564e02791813ddfb599f6cd7
tree7cb73181d19a46ef8c1fbf671ce85a17fe0c9644
parentdc6553d93eb856a1593d43f0d1ea387c74fa7b44
parent6c195db03a502074952181261807cf9a8e140d8d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10893 from joachimschmidt557/stage2-aarch64

stage2 AArch64: get zig test working; enable behavior tests

33 files changed, 1477 insertions(+), 359 deletions(-)

ci/zinc/linux_test.sh+3-2
......@@ -7,8 +7,9 @@ ZIG=$DEBUG_STAGING/bin/zig
77$ZIG test test/behavior.zig -fno-stage1 -I test -fLLVM
88$ZIG test test/behavior.zig -fno-stage1 -I test -fLLVM -target aarch64-linux --test-cmd qemu-aarch64 --test-cmd-bin
99$ZIG test test/behavior.zig -fno-stage1 -I test -ofmt=c
10$ZIG test test/behavior.zig -fno-stage1 -I test -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin
11$ZIG test test/behavior.zig -fno-stage1 -I test -target arm-linux --test-cmd qemu-arm --test-cmd-bin
10$ZIG test test/behavior.zig -fno-stage1 -I test -target wasm32-wasi --test-cmd wasmtime --test-cmd-bin
11$ZIG test test/behavior.zig -fno-stage1 -I test -target arm-linux --test-cmd qemu-arm --test-cmd-bin
12$ZIG test test/behavior.zig -fno-stage1 -I test -target aarch64-linux --test-cmd qemu-aarch64 --test-cmd-bin
1213$ZIG test test/behavior.zig -fno-stage1 -I test
1314
1415$ZIG build test-behavior -fqemu -fwasmtime
src/arch/aarch64/CodeGen.zig+881-233
......@@ -511,10 +511,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
511511
512512 switch (air_tags[inst]) {
513513 // zig fmt: off
514 .add, .ptr_add => try self.airAdd(inst),
514 .add, .ptr_add => try self.airBinOp(inst),
515515 .addwrap => try self.airAddWrap(inst),
516516 .add_sat => try self.airAddSat(inst),
517 .sub, .ptr_sub => try self.airSub(inst),
517 .sub, .ptr_sub => try self.airBinOp(inst),
518518 .subwrap => try self.airSubWrap(inst),
519519 .sub_sat => try self.airSubSat(inst),
520520 .mul => try self.airMul(inst),
......@@ -894,6 +894,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
894894 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
895895 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
896896 const operand = try self.resolveInst(ty_op.operand);
897 const operand_ty = self.air.typeOf(ty_op.operand);
897898 switch (operand) {
898899 .dead => unreachable,
899900 .unreach => unreachable,
......@@ -923,12 +924,19 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
923924 };
924925 break :result r;
925926 },
926 else => {},
927 else => {
928 switch (operand_ty.zigTypeTag()) {
929 .Bool => {
930 // TODO convert this to mvn + and
931 const dest = try self.binOp(.xor, null, operand, .{ .immediate = 1 }, operand_ty, Type.bool);
932 break :result dest;
933 },
934 else => return self.fail("TODO bitwise not", .{}),
935 }
936 },
927937 }
928
929 return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch});
930938 };
931 _ = result;
939 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
932940}
933941
934942fn airMin(self: *Self, inst: Air.Inst.Index) !void {
......@@ -950,9 +958,306 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
950958 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
951959}
952960
953fn airAdd(self: *Self, inst: Air.Inst.Index) !void {
961/// Don't call this function directly. Use binOp instead.
962///
963/// Calling this function signals an intention to generate a Mir
964/// instruction of the form
965///
966/// op dest, lhs, rhs
967///
968/// Asserts that generating an instruction of that form is possible.
969fn binOpRegister(
970 self: *Self,
971 tag: Air.Inst.Tag,
972 maybe_inst: ?Air.Inst.Index,
973 lhs: MCValue,
974 rhs: MCValue,
975 lhs_ty: Type,
976 rhs_ty: Type,
977) !MCValue {
978 const lhs_is_register = lhs == .register;
979 const rhs_is_register = rhs == .register;
980
981 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
982 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
983
984 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
985
986 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
987 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
988 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
989 break :inst Air.refToIndex(bin_op.lhs).?;
990 } else null;
991
992 const reg = try self.register_manager.allocReg(track_inst);
993 self.register_manager.freezeRegs(&.{reg});
994
995 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
996
997 break :blk reg;
998 };
999 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1000
1001 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1002 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
1003 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1004 break :inst Air.refToIndex(bin_op.rhs).?;
1005 } else null;
1006
1007 const reg = try self.register_manager.allocReg(track_inst);
1008 self.register_manager.freezeRegs(&.{reg});
1009
1010 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1011
1012 break :blk reg;
1013 };
1014 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
1015
1016 const dest_reg = if (maybe_inst) |inst| blk: {
1017 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1018
1019 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1020 break :blk lhs_reg;
1021 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
1022 break :blk rhs_reg;
1023 } else {
1024 break :blk try self.register_manager.allocReg(inst);
1025 }
1026 } else try self.register_manager.allocReg(null);
1027
1028 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1029 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1030
1031 const mir_tag: Mir.Inst.Tag = switch (tag) {
1032 .add, .ptr_add => .add_shifted_register,
1033 .sub, .ptr_sub => .sub_shifted_register,
1034 .xor => .eor_shifted_register,
1035 else => unreachable,
1036 };
1037 const mir_data: Mir.Inst.Data = switch (tag) {
1038 .add,
1039 .sub,
1040 .ptr_add,
1041 .ptr_sub,
1042 => .{ .rrr_imm6_shift = .{
1043 .rd = dest_reg,
1044 .rn = lhs_reg,
1045 .rm = rhs_reg,
1046 .imm6 = 0,
1047 .shift = .lsl,
1048 } },
1049 .xor => .{ .rrr_imm6_logical_shift = .{
1050 .rd = dest_reg,
1051 .rn = lhs_reg,
1052 .rm = rhs_reg,
1053 .imm6 = 0,
1054 .shift = .lsl,
1055 } },
1056 else => unreachable,
1057 };
1058
1059 _ = try self.addInst(.{
1060 .tag = mir_tag,
1061 .data = mir_data,
1062 });
1063
1064 return MCValue{ .register = dest_reg };
1065}
1066
1067/// Don't call this function directly. Use binOp instead.
1068///
1069/// Calling this function signals an intention to generate a Mir
1070/// instruction of the form
1071///
1072/// op dest, lhs, #rhs_imm
1073///
1074/// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to
1075/// rhs and vice versa. This parameter is only used when maybe_inst !=
1076/// null.
1077///
1078/// Asserts that generating an instruction of that form is possible.
1079fn binOpImmediate(
1080 self: *Self,
1081 tag: Air.Inst.Tag,
1082 maybe_inst: ?Air.Inst.Index,
1083 lhs: MCValue,
1084 rhs: MCValue,
1085 lhs_ty: Type,
1086 lhs_and_rhs_swapped: bool,
1087) !MCValue {
1088 const lhs_is_register = lhs == .register;
1089
1090 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1091
1092 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1093
1094 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1095 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
1096 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1097 break :inst Air.refToIndex(
1098 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,
1099 ).?;
1100 } else null;
1101
1102 const reg = try self.register_manager.allocReg(track_inst);
1103 self.register_manager.freezeRegs(&.{reg});
1104
1105 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1106
1107 break :blk reg;
1108 };
1109 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
1110
1111 const dest_reg = if (maybe_inst) |inst| blk: {
1112 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1113
1114 if (lhs_is_register and self.reuseOperand(
1115 inst,
1116 if (lhs_and_rhs_swapped) bin_op.rhs else bin_op.lhs,
1117 if (lhs_and_rhs_swapped) 1 else 0,
1118 lhs,
1119 )) {
1120 break :blk lhs_reg;
1121 } else {
1122 break :blk try self.register_manager.allocReg(inst);
1123 }
1124 } else try self.register_manager.allocReg(null);
1125
1126 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1127
1128 const mir_tag: Mir.Inst.Tag = switch (tag) {
1129 .add => .add_immediate,
1130 .sub => .sub_immediate,
1131 else => unreachable,
1132 };
1133 const mir_data: Mir.Inst.Data = switch (tag) {
1134 .add,
1135 .sub,
1136 => .{ .rr_imm12_sh = .{
1137 .rd = dest_reg,
1138 .rn = lhs_reg,
1139 .imm12 = @intCast(u12, rhs.immediate),
1140 } },
1141 else => unreachable,
1142 };
1143
1144 _ = try self.addInst(.{
1145 .tag = mir_tag,
1146 .data = mir_data,
1147 });
1148
1149 return MCValue{ .register = dest_reg };
1150}
1151
1152/// For all your binary operation needs, this function will generate
1153/// the corresponding Mir instruction(s). Returns the location of the
1154/// result.
1155///
1156/// If the binary operation itself happens to be an Air instruction,
1157/// pass the corresponding index in the inst parameter. That helps
1158/// this function do stuff like reusing operands.
1159///
1160/// This function does not do any lowering to Mir itself, but instead
1161/// looks at the lhs and rhs and determines which kind of lowering
1162/// would be best suitable and then delegates the lowering to other
1163/// functions.
1164fn binOp(
1165 self: *Self,
1166 tag: Air.Inst.Tag,
1167 maybe_inst: ?Air.Inst.Index,
1168 lhs: MCValue,
1169 rhs: MCValue,
1170 lhs_ty: Type,
1171 rhs_ty: Type,
1172) !MCValue {
1173 switch (tag) {
1174 // Arithmetic operations on integers and floats
1175 .add,
1176 .sub,
1177 => {
1178 switch (lhs_ty.zigTypeTag()) {
1179 .Float => return self.fail("TODO binary operations on floats", .{}),
1180 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1181 .Int => {
1182 assert(lhs_ty.eql(rhs_ty));
1183 const int_info = lhs_ty.intInfo(self.target.*);
1184 if (int_info.bits <= 64) {
1185 // Only say yes if the operation is
1186 // commutative, i.e. we can swap both of the
1187 // operands
1188 const lhs_immediate_ok = switch (tag) {
1189 .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12),
1190 .sub => false,
1191 else => unreachable,
1192 };
1193 const rhs_immediate_ok = switch (tag) {
1194 .add,
1195 .sub,
1196 => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12),
1197 else => unreachable,
1198 };
1199
1200 if (rhs_immediate_ok) {
1201 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
1202 } else if (lhs_immediate_ok) {
1203 // swap lhs and rhs
1204 return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true);
1205 } else {
1206 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1207 }
1208 } else {
1209 return self.fail("TODO binary operations on int with bits > 64", .{});
1210 }
1211 },
1212 else => unreachable,
1213 }
1214 },
1215 // Bitwise operations on integers
1216 .xor => {
1217 switch (lhs_ty.zigTypeTag()) {
1218 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1219 .Int => return self.fail("TODO binary operations on vectors", .{}),
1220 .Bool => {
1221 assert(lhs_ty.eql(rhs_ty));
1222 // TODO boolean operations with immediates
1223 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1224 },
1225 else => unreachable,
1226 }
1227 },
1228 .ptr_add,
1229 .ptr_sub,
1230 => {
1231 switch (lhs_ty.zigTypeTag()) {
1232 .Pointer => {
1233 const ptr_ty = lhs_ty;
1234 const pointee_ty = switch (ptr_ty.ptrSize()) {
1235 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
1236 else => ptr_ty.childType(),
1237 };
1238
1239 if (pointee_ty.abiSize(self.target.*) > 1) {
1240 return self.fail("TODO ptr_add, ptr_sub with more element sizes", .{});
1241 }
1242
1243 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1244 },
1245 else => unreachable,
1246 }
1247 },
1248 else => unreachable,
1249 }
1250}
1251
1252fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1253 const tag = self.air.instructions.items(.tag)[inst];
9541254 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
955 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add for {}", .{self.target.cpu.arch});
1255 const lhs = try self.resolveInst(bin_op.lhs);
1256 const rhs = try self.resolveInst(bin_op.rhs);
1257 const lhs_ty = self.air.typeOf(bin_op.lhs);
1258 const rhs_ty = self.air.typeOf(bin_op.rhs);
1259
1260 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
9561261 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
9571262}
9581263
......@@ -968,12 +1273,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
9681273 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
9691274}
9701275
971fn airSub(self: *Self, inst: Air.Inst.Index) !void {
972 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
973 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub for {}", .{self.target.cpu.arch});
974 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
975}
976
9771276fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
9781277 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
9791278 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
......@@ -1098,13 +1397,26 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
10981397
10991398fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
11001399 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1101 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch});
1400 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1401 const error_union_ty = self.air.typeOf(ty_op.operand);
1402 const payload_ty = error_union_ty.errorUnionPayload();
1403 const mcv = try self.resolveInst(ty_op.operand);
1404 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1405
1406 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1407 };
11021408 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11031409}
11041410
11051411fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
11061412 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1107 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement unwrap error union payload for {}", .{self.target.cpu.arch});
1413 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1414 const error_union_ty = self.air.typeOf(ty_op.operand);
1415 const payload_ty = error_union_ty.errorUnionPayload();
1416 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1417
1418 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1419 };
11081420 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11091421}
11101422
......@@ -1146,7 +1458,14 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
11461458/// E to E!T
11471459fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
11481460 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1149 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion error for {}", .{self.target.cpu.arch});
1461 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1462 const error_union_ty = self.air.getRefType(ty_op.ty);
1463 const payload_ty = error_union_ty.errorUnionPayload();
1464 const mcv = try self.resolveInst(ty_op.operand);
1465 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1466
1467 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1468 };
11501469 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11511470}
11521471
......@@ -1158,7 +1477,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
11581477
11591478fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
11601479 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1161 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_len for {}", .{self.target.cpu.arch});
1480 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1481 const mcv = try self.resolveInst(ty_op.operand);
1482 switch (mcv) {
1483 .dead, .unreach => unreachable,
1484 .register => unreachable, // a slice doesn't fit in one register
1485 .stack_offset => |off| {
1486 break :result MCValue{ .stack_offset = off };
1487 },
1488 .memory => |addr| {
1489 break :result MCValue{ .memory = addr + 8 };
1490 },
1491 else => return self.fail("TODO implement slice_len for {}", .{mcv}),
1492 }
1493 };
11621494 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
11631495}
11641496
......@@ -1177,10 +1509,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
11771509fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
11781510 const is_volatile = false; // TODO
11791511 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1180 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_val for {}", .{self.target.cpu.arch});
1512
1513 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1514 const result: MCValue = result: {
1515 const slice_mcv = try self.resolveInst(bin_op.lhs);
1516
1517 // TODO optimize for the case where the index is a constant,
1518 // i.e. index_mcv == .immediate
1519 const index_mcv = try self.resolveInst(bin_op.rhs);
1520 const index_is_register = index_mcv == .register;
1521
1522 const slice_ty = self.air.typeOf(bin_op.lhs);
1523 const elem_ty = slice_ty.childType();
1524 const elem_size = elem_ty.abiSize(self.target.*);
1525
1526 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1527 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
1528
1529 if (index_is_register) self.register_manager.freezeRegs(&.{index_mcv.register});
1530 defer if (index_is_register) self.register_manager.unfreezeRegs(&.{index_mcv.register});
1531
1532 const base_mcv: MCValue = switch (slice_mcv) {
1533 .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off + 8 }) },
1534 else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
1535 };
1536 self.register_manager.freezeRegs(&.{base_mcv.register});
1537
1538 // TODO implement optimized ldr for airSliceElemVal
1539 const dst_mcv = try self.allocRegOrMem(inst, true);
1540
1541 const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size));
1542 assert(offset_mcv == .register); // result of multiplication should always be register
1543 self.register_manager.freezeRegs(&.{offset_mcv.register});
1544
1545 const addr_reg = try self.register_manager.allocReg(null);
1546 self.register_manager.freezeRegs(&.{addr_reg});
1547 defer self.register_manager.unfreezeRegs(&.{addr_reg});
1548
1549 _ = try self.addInst(.{
1550 .tag = .add_shifted_register,
1551 .data = .{ .rrr_imm6_shift = .{
1552 .rd = addr_reg,
1553 .rn = base_mcv.register,
1554 .rm = offset_mcv.register,
1555 .imm6 = 0,
1556 .shift = .lsl,
1557 } },
1558 });
1559
1560 // At this point in time, neither the base register
1561 // nor the offset register contains any valuable data
1562 // anymore.
1563 self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register });
1564
1565 try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type);
1566
1567 break :result dst_mcv;
1568 };
11811569 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11821570}
11831571
1572fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue {
1573 const lhs = try self.resolveInst(op);
1574 const rhs = MCValue{ .immediate = imm };
1575
1576 const lhs_is_register = lhs == .register;
1577
1578 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
1579 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
1580
1581 // Destination must be a register
1582 // LHS must be a register
1583 // RHS must be a register
1584 var dst_mcv: MCValue = undefined;
1585 var lhs_mcv: MCValue = lhs;
1586 var rhs_mcv: MCValue = rhs;
1587
1588 // Allocate registers for operands and/or destination
1589 // Allocate 1 or 2 registers
1590 if (lhs_is_register) {
1591 // Move RHS to register
1592 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
1593 rhs_mcv = dst_mcv;
1594 } else {
1595 // Move LHS and RHS to register
1596 const regs = try self.register_manager.allocRegs(2, .{ null, null });
1597 lhs_mcv = MCValue{ .register = regs[0] };
1598 rhs_mcv = MCValue{ .register = regs[1] };
1599 dst_mcv = lhs_mcv;
1600 }
1601
1602 // Move the operands to the newly allocated registers
1603 if (!lhs_is_register) {
1604 try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs);
1605 }
1606 try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs);
1607
1608 _ = try self.addInst(.{
1609 .tag = .mul,
1610 .data = .{ .rrr = .{
1611 .rd = dst_mcv.register,
1612 .rn = lhs_mcv.register,
1613 .rm = rhs_mcv.register,
1614 } },
1615 });
1616
1617 return dst_mcv;
1618}
1619
11841620fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
11851621 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
11861622 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -1295,8 +1731,74 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
12951731 .embedded_in_code => {
12961732 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
12971733 },
1298 .register => {
1299 return self.fail("TODO implement loading from MCValue.register for {}", .{self.target.cpu.arch});
1734 .register => |addr_reg| {
1735 self.register_manager.freezeRegs(&.{addr_reg});
1736 defer self.register_manager.unfreezeRegs(&.{addr_reg});
1737
1738 switch (dst_mcv) {
1739 .dead => unreachable,
1740 .undef => unreachable,
1741 .compare_flags_signed, .compare_flags_unsigned => unreachable,
1742 .embedded_in_code => unreachable,
1743 .register => |dst_reg| {
1744 _ = try self.addInst(.{
1745 .tag = .ldr_immediate,
1746 .data = .{ .load_store_register_immediate = .{
1747 .rt = dst_reg,
1748 .rn = addr_reg,
1749 .offset = Instruction.LoadStoreOffset.none.immediate,
1750 } },
1751 });
1752 },
1753 .stack_offset => |off| {
1754 if (elem_ty.abiSize(self.target.*) <= 8) {
1755 const tmp_reg = try self.register_manager.allocReg(null);
1756 self.register_manager.freezeRegs(&.{tmp_reg});
1757 defer self.register_manager.unfreezeRegs(&.{tmp_reg});
1758
1759 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
1760 try self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
1761 } else {
1762 // TODO optimize the register allocation
1763 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null });
1764 self.register_manager.freezeRegs(&regs);
1765 defer self.register_manager.unfreezeRegs(&regs);
1766
1767 const src_reg = addr_reg;
1768 const dst_reg = regs[0];
1769 const len_reg = regs[1];
1770 const count_reg = regs[2];
1771 const tmp_reg = regs[3];
1772
1773 // sub dst_reg, fp, #off
1774 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
1775 const adj_off = off + elem_size;
1776 const offset = math.cast(u12, adj_off) catch return self.fail("TODO load: larger stack offsets", .{});
1777 _ = try self.addInst(.{
1778 .tag = .sub_immediate,
1779 .data = .{ .rr_imm12_sh = .{
1780 .rd = dst_reg,
1781 .rn = .x29,
1782 .imm12 = offset,
1783 } },
1784 });
1785
1786 // mov len, #elem_size
1787 const len_imm = math.cast(u16, elem_size) catch return self.fail("TODO load: larger stack offsets", .{});
1788 _ = try self.addInst(.{
1789 .tag = .movk,
1790 .data = .{ .r_imm16_sh = .{
1791 .rd = len_reg,
1792 .imm16 = len_imm,
1793 } },
1794 });
1795
1796 // memcpy(src, dst, len)
1797 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
1798 }
1799 },
1800 else => return self.fail("TODO load from register into {}", .{dst_mcv}),
1801 }
13001802 },
13011803 .memory,
13021804 .stack_offset,
......@@ -1311,6 +1813,84 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
13111813 }
13121814}
13131815
1816fn genInlineMemcpy(
1817 self: *Self,
1818 src: Register,
1819 dst: Register,
1820 len: Register,
1821 count: Register,
1822 tmp: Register,
1823) !void {
1824 // movk count, #0
1825 _ = try self.addInst(.{
1826 .tag = .movk,
1827 .data = .{ .r_imm16_sh = .{
1828 .rd = count,
1829 .imm16 = 0,
1830 } },
1831 });
1832
1833 // loop:
1834 // cmp count, len
1835 _ = try self.addInst(.{
1836 .tag = .cmp_shifted_register,
1837 .data = .{ .rrr_imm6_shift = .{
1838 .rd = .xzr,
1839 .rn = count,
1840 .rm = len,
1841 .imm6 = 0,
1842 .shift = .lsl,
1843 } },
1844 });
1845
1846 // bge end
1847 _ = try self.addInst(.{
1848 .tag = .b_cond,
1849 .data = .{ .inst_cond = .{
1850 .inst = @intCast(u32, self.mir_instructions.len + 5),
1851 .cond = .ge,
1852 } },
1853 });
1854
1855 // ldrb tmp, [src, count]
1856 _ = try self.addInst(.{
1857 .tag = .ldrb_register,
1858 .data = .{ .load_store_register_register = .{
1859 .rt = tmp,
1860 .rn = src,
1861 .offset = Instruction.LoadStoreOffset.reg(count).register,
1862 } },
1863 });
1864
1865 // strb tmp, [dest, count]
1866 _ = try self.addInst(.{
1867 .tag = .strb_register,
1868 .data = .{ .load_store_register_register = .{
1869 .rt = tmp,
1870 .rn = dst,
1871 .offset = Instruction.LoadStoreOffset.reg(count).register,
1872 } },
1873 });
1874
1875 // add count, count, #1
1876 _ = try self.addInst(.{
1877 .tag = .add_immediate,
1878 .data = .{ .rr_imm12_sh = .{
1879 .rd = count,
1880 .rn = count,
1881 .imm12 = 1,
1882 } },
1883 });
1884
1885 // b loop
1886 _ = try self.addInst(.{
1887 .tag = .b,
1888 .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 5) },
1889 });
1890
1891 // end:
1892}
1893
13141894fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
13151895 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13161896 const elem_ty = self.air.typeOfIndex(inst);
......@@ -1337,11 +1917,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
13371917 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13381918}
13391919
1340fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1341 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1342 const ptr = try self.resolveInst(bin_op.lhs);
1343 const value = try self.resolveInst(bin_op.rhs);
1344 const elem_ty = self.air.typeOf(bin_op.rhs);
1920fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
13451921 switch (ptr) {
13461922 .none => unreachable,
13471923 .undef => unreachable,
......@@ -1350,13 +1926,13 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
13501926 .compare_flags_unsigned => unreachable,
13511927 .compare_flags_signed => unreachable,
13521928 .immediate => |imm| {
1353 try self.setRegOrMem(elem_ty, .{ .memory = imm }, value);
1929 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
13541930 },
13551931 .ptr_stack_offset => |off| {
1356 try self.genSetStack(elem_ty, off, value);
1932 try self.genSetStack(value_ty, off, value);
13571933 },
13581934 .ptr_embedded_in_code => |off| {
1359 try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value);
1935 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
13601936 },
13611937 .embedded_in_code => {
13621938 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
......@@ -1364,33 +1940,55 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
13641940 .register => {
13651941 return self.fail("TODO implement storing to MCValue.register", .{});
13661942 },
1367 .memory => {
1368 return self.fail("TODO implement storing to MCValue.memory", .{});
1369 },
1370 .stack_offset => {
1371 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
1943 .memory,
1944 .stack_offset,
1945 => {
1946 const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
1947 try self.store(.{ .register = addr_reg }, value, ptr_ty, value_ty);
13721948 },
13731949 }
1950}
1951
1952fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1953 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1954 const ptr = try self.resolveInst(bin_op.lhs);
1955 const value = try self.resolveInst(bin_op.rhs);
1956 const ptr_ty = self.air.typeOf(bin_op.lhs);
1957 const value_ty = self.air.typeOf(bin_op.rhs);
1958
1959 try self.store(ptr, value, ptr_ty, value_ty);
1960
13741961 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
13751962}
13761963
13771964fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
13781965 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
13791966 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1380 return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index);
1967 const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index);
1968 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
13811969}
13821970
13831971fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
13841972 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1385 return self.structFieldPtr(ty_op.operand, ty_op.ty, index);
1973 const result = try self.structFieldPtr(inst, ty_op.operand, index);
1974 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13861975}
1387fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {
1388 _ = self;
1389 _ = operand;
1390 _ = ty;
1391 _ = index;
1392 return self.fail("TODO implement codegen struct_field_ptr", .{});
1393 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1976
1977fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
1978 return if (self.liveness.isUnused(inst)) .dead else result: {
1979 const mcv = try self.resolveInst(operand);
1980 const struct_ty = self.air.typeOf(operand).childType();
1981 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));
1982 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
1983 const struct_field_ty = struct_ty.structFieldType(index);
1984 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
1985 switch (mcv) {
1986 .ptr_stack_offset => |off| {
1987 break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size };
1988 },
1989 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
1990 }
1991 };
13941992}
13951993
13961994fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1487,49 +2085,55 @@ fn airFence(self: *Self) !void {
14872085
14882086fn airCall(self: *Self, inst: Air.Inst.Index) !void {
14892087 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1490 const fn_ty = self.air.typeOf(pl_op.operand);
14912088 const callee = pl_op.operand;
14922089 const extra = self.air.extraData(Air.Call, pl_op.payload);
14932090 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]);
2091 const ty = self.air.typeOf(callee);
2092
2093 const fn_ty = switch (ty.zigTypeTag()) {
2094 .Fn => ty,
2095 .Pointer => ty.childType(),
2096 else => unreachable,
2097 };
14942098
14952099 var info = try self.resolveCallingConventionValues(fn_ty);
14962100 defer info.deinit(self);
14972101
1498 // Due to incremental compilation, how function calls are generated depends
1499 // on linking.
1500 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {
1501 for (info.args) |mc_arg, arg_i| {
1502 const arg = args[arg_i];
1503 const arg_ty = self.air.typeOf(arg);
1504 const arg_mcv = try self.resolveInst(args[arg_i]);
1505
1506 switch (mc_arg) {
1507 .none => continue,
1508 .undef => unreachable,
1509 .immediate => unreachable,
1510 .unreach => unreachable,
1511 .dead => unreachable,
1512 .embedded_in_code => unreachable,
1513 .memory => unreachable,
1514 .compare_flags_signed => unreachable,
1515 .compare_flags_unsigned => unreachable,
1516 .register => |reg| {
1517 try self.register_manager.getReg(reg, null);
1518 try self.genSetReg(arg_ty, reg, arg_mcv);
1519 },
1520 .stack_offset => {
1521 return self.fail("TODO implement calling with parameters in memory", .{});
1522 },
1523 .ptr_stack_offset => {
1524 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1525 },
1526 .ptr_embedded_in_code => {
1527 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1528 },
1529 }
2102 for (info.args) |mc_arg, arg_i| {
2103 const arg = args[arg_i];
2104 const arg_ty = self.air.typeOf(arg);
2105 const arg_mcv = try self.resolveInst(args[arg_i]);
2106
2107 switch (mc_arg) {
2108 .none => continue,
2109 .undef => unreachable,
2110 .immediate => unreachable,
2111 .unreach => unreachable,
2112 .dead => unreachable,
2113 .embedded_in_code => unreachable,
2114 .memory => unreachable,
2115 .compare_flags_signed => unreachable,
2116 .compare_flags_unsigned => unreachable,
2117 .register => |reg| {
2118 try self.register_manager.getReg(reg, null);
2119 try self.genSetReg(arg_ty, reg, arg_mcv);
2120 },
2121 .stack_offset => {
2122 return self.fail("TODO implement calling with parameters in memory", .{});
2123 },
2124 .ptr_stack_offset => {
2125 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2126 },
2127 .ptr_embedded_in_code => {
2128 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2129 },
15302130 }
2131 }
15312132
1532 if (self.air.value(callee)) |func_value| {
2133 // Due to incremental compilation, how function calls are generated depends
2134 // on linking.
2135 if (self.air.value(callee)) |func_value| {
2136 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {
15332137 if (func_value.castTag(.function)) |func_payload| {
15342138 const func = func_payload.data;
15352139 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
......@@ -1553,45 +2157,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
15532157 } else {
15542158 return self.fail("TODO implement calling bitcasted functions", .{});
15552159 }
1556 } else {
1557 return self.fail("TODO implement calling runtime known function pointer", .{});
1558 }
1559 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1560 for (info.args) |mc_arg, arg_i| {
1561 const arg = args[arg_i];
1562 const arg_ty = self.air.typeOf(arg);
1563 const arg_mcv = try self.resolveInst(args[arg_i]);
1564 // Here we do not use setRegOrMem even though the logic is similar, because
1565 // the function call will move the stack pointer, so the offsets are different.
1566 switch (mc_arg) {
1567 .none => continue,
1568 .register => |reg| {
1569 try self.register_manager.getReg(reg, null);
1570 try self.genSetReg(arg_ty, reg, arg_mcv);
1571 },
1572 .stack_offset => {
1573 // Here we need to emit instructions like this:
1574 // mov qword ptr [rsp + stack_offset], x
1575 return self.fail("TODO implement calling with parameters in memory", .{});
1576 },
1577 .ptr_stack_offset => {
1578 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1579 },
1580 .ptr_embedded_in_code => {
1581 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1582 },
1583 .undef => unreachable,
1584 .immediate => unreachable,
1585 .unreach => unreachable,
1586 .dead => unreachable,
1587 .embedded_in_code => unreachable,
1588 .memory => unreachable,
1589 .compare_flags_signed => unreachable,
1590 .compare_flags_unsigned => unreachable,
1591 }
1592 }
1593
1594 if (self.air.value(callee)) |func_value| {
2160 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
15952161 if (func_value.castTag(.function)) |func_payload| {
15962162 const func = func_payload.data;
15972163 // TODO I'm hacking my way through here by repurposing .memory for storing
......@@ -1627,41 +2193,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
16272193 } else {
16282194 return self.fail("TODO implement calling bitcasted functions", .{});
16292195 }
1630 } else {
1631 return self.fail("TODO implement calling runtime known function pointer", .{});
1632 }
1633 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
1634 for (info.args) |mc_arg, arg_i| {
1635 const arg = args[arg_i];
1636 const arg_ty = self.air.typeOf(arg);
1637 const arg_mcv = try self.resolveInst(args[arg_i]);
1638
1639 switch (mc_arg) {
1640 .none => continue,
1641 .undef => unreachable,
1642 .immediate => unreachable,
1643 .unreach => unreachable,
1644 .dead => unreachable,
1645 .embedded_in_code => unreachable,
1646 .memory => unreachable,
1647 .compare_flags_signed => unreachable,
1648 .compare_flags_unsigned => unreachable,
1649 .register => |reg| {
1650 try self.register_manager.getReg(reg, null);
1651 try self.genSetReg(arg_ty, reg, arg_mcv);
1652 },
1653 .stack_offset => {
1654 return self.fail("TODO implement calling with parameters in memory", .{});
1655 },
1656 .ptr_stack_offset => {
1657 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1658 },
1659 .ptr_embedded_in_code => {
1660 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1661 },
1662 }
1663 }
1664 if (self.air.value(callee)) |func_value| {
2196 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
16652197 if (func_value.castTag(.function)) |func_payload| {
16662198 try p9.seeDecl(func_payload.data.owner_decl);
16672199 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
......@@ -1681,10 +2213,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
16812213 } else {
16822214 return self.fail("TODO implement calling bitcasted functions", .{});
16832215 }
1684 } else {
1685 return self.fail("TODO implement calling runtime known function pointer", .{});
1686 }
1687 } else unreachable;
2216 } else unreachable;
2217 } else {
2218 assert(ty.zigTypeTag() == .Pointer);
2219 const mcv = try self.resolveInst(callee);
2220 try self.genSetReg(ty, .x30, mcv);
2221
2222 _ = try self.addInst(.{
2223 .tag = .blr,
2224 .data = .{ .reg = .x30 },
2225 });
2226 }
16882227
16892228 const result: MCValue = result: {
16902229 switch (info.return_value) {
......@@ -1741,12 +2280,23 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
17412280
17422281fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
17432282 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2283
17442284 if (self.liveness.isUnused(inst))
17452285 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2286
17462287 const ty = self.air.typeOf(bin_op.lhs);
1747 assert(ty.eql(self.air.typeOf(bin_op.rhs)));
1748 if (ty.zigTypeTag() == .ErrorSet)
1749 return self.fail("TODO implement cmp for errors", .{});
2288
2289 if (ty.abiSize(self.target.*) > 8) {
2290 return self.fail("TODO cmp for types with size > 8", .{});
2291 }
2292
2293 const signedness: std.builtin.Signedness = blk: {
2294 // by default we tell the operand type is unsigned (i.e. bools and enum values)
2295 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
2296
2297 // incase of an actual integer, we emit the correct signedness
2298 break :blk ty.intInfo(self.target.*).signedness;
2299 };
17502300
17512301 const lhs = try self.resolveInst(bin_op.lhs);
17522302 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -1812,8 +2362,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
18122362 .immediate => |imm| {
18132363 _ = try self.addInst(.{
18142364 .tag = .cmp_immediate,
1815 .data = .{ .rr_imm12_sh = .{
1816 .rd = .xzr,
2365 .data = .{ .r_imm12_sh = .{
18172366 .rn = lhs_mcv.register,
18182367 .imm12 = @intCast(u12, imm),
18192368 } },
......@@ -1822,9 +2371,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
18222371 else => unreachable,
18232372 }
18242373
1825 break :result switch (ty.isSignedInt()) {
1826 true => MCValue{ .compare_flags_signed = op },
1827 false => MCValue{ .compare_flags_unsigned = op },
2374 break :result switch (signedness) {
2375 .signed => MCValue{ .compare_flags_signed = op },
2376 .unsigned => MCValue{ .compare_flags_unsigned = op },
18282377 };
18292378 };
18302379 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -1876,7 +2425,22 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
18762425 },
18772426 },
18782427 }),
1879 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(cond)}),
2428 else => blk: {
2429 const reg = switch (cond) {
2430 .register => |r| r,
2431 else => try self.copyToTmpRegister(Type.bool, cond),
2432 };
2433
2434 break :blk try self.addInst(.{
2435 .tag = .cbz,
2436 .data = .{
2437 .r_inst = .{
2438 .rt = reg,
2439 .inst = undefined, // populated later through performReloc
2440 },
2441 },
2442 });
2443 },
18802444 };
18812445
18822446 // Capture the state of register and stack allocation state so that we can revert to it.
......@@ -2008,18 +2572,51 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {
20082572 return self.fail("TODO call isNull and invert the result", .{});
20092573}
20102574
2011fn isErr(self: *Self, operand: MCValue) !MCValue {
2575fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
20122576 _ = operand;
2013 // Here you can specialize this instruction if it makes sense to, otherwise the default
2014 // will call isNonNull and invert the result.
2015 return self.fail("TODO call isNonErr and invert the result", .{});
2577
2578 const error_type = ty.errorUnionSet();
2579 const payload_type = ty.errorUnionPayload();
2580
2581 if (!error_type.hasRuntimeBits()) {
2582 return MCValue{ .immediate = 0 }; // always false
2583 } else if (!payload_type.hasRuntimeBits()) {
2584 if (error_type.abiSize(self.target.*) <= 8) {
2585 const reg_mcv: MCValue = switch (operand) {
2586 .register => operand,
2587 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
2588 };
2589
2590 _ = try self.addInst(.{
2591 .tag = .cmp_immediate,
2592 .data = .{ .r_imm12_sh = .{
2593 .rn = reg_mcv.register,
2594 .imm12 = 0,
2595 } },
2596 });
2597
2598 return MCValue{ .compare_flags_unsigned = .gt };
2599 } else {
2600 return self.fail("TODO isErr for errors with size > 8", .{});
2601 }
2602 } else {
2603 return self.fail("TODO isErr for non-empty payloads", .{});
2604 }
20162605}
20172606
2018fn isNonErr(self: *Self, operand: MCValue) !MCValue {
2019 _ = operand;
2020 // Here you can specialize this instruction if it makes sense to, otherwise the default
2021 // will call isNull and invert the result.
2022 return self.fail("TODO call isErr and invert the result", .{});
2607fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2608 const is_err_result = try self.isErr(ty, operand);
2609 switch (is_err_result) {
2610 .compare_flags_unsigned => |op| {
2611 assert(op == .gt);
2612 return MCValue{ .compare_flags_unsigned = .lte };
2613 },
2614 .immediate => |imm| {
2615 assert(imm == 0);
2616 return MCValue{ .immediate = 1 };
2617 },
2618 else => unreachable,
2619 }
20232620}
20242621
20252622fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2080,7 +2677,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
20802677 const un_op = self.air.instructions.items(.data)[inst].un_op;
20812678 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20822679 const operand = try self.resolveInst(un_op);
2083 break :result try self.isErr(operand);
2680 const ty = self.air.typeOf(un_op);
2681 break :result try self.isErr(ty, operand);
20842682 };
20852683 return self.finishAir(inst, result, .{ un_op, .none, .none });
20862684}
......@@ -2089,6 +2687,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
20892687 const un_op = self.air.instructions.items(.data)[inst].un_op;
20902688 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
20912689 const operand_ptr = try self.resolveInst(un_op);
2690 const ptr_ty = self.air.typeOf(un_op);
20922691 const operand: MCValue = blk: {
20932692 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
20942693 // The MCValue that holds the pointer can be re-used as the value.
......@@ -2098,7 +2697,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
20982697 }
20992698 };
21002699 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
2101 break :result try self.isErr(operand);
2700 break :result try self.isErr(ptr_ty.elemType(), operand);
21022701 };
21032702 return self.finishAir(inst, result, .{ un_op, .none, .none });
21042703}
......@@ -2107,7 +2706,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
21072706 const un_op = self.air.instructions.items(.data)[inst].un_op;
21082707 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
21092708 const operand = try self.resolveInst(un_op);
2110 break :result try self.isNonErr(operand);
2709 const ty = self.air.typeOf(un_op);
2710 break :result try self.isNonErr(ty, operand);
21112711 };
21122712 return self.finishAir(inst, result, .{ un_op, .none, .none });
21132713}
......@@ -2116,6 +2716,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
21162716 const un_op = self.air.instructions.items(.data)[inst].un_op;
21172717 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
21182718 const operand_ptr = try self.resolveInst(un_op);
2719 const ptr_ty = self.air.typeOf(un_op);
21192720 const operand: MCValue = blk: {
21202721 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
21212722 // The MCValue that holds the pointer can be re-used as the value.
......@@ -2125,7 +2726,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
21252726 }
21262727 };
21272728 try self.load(operand, operand_ptr, self.air.typeOf(un_op));
2128 break :result try self.isNonErr(operand);
2729 break :result try self.isNonErr(ptr_ty.elemType(), operand);
21292730 };
21302731 return self.finishAir(inst, result, .{ un_op, .none, .none });
21312732}
......@@ -2184,8 +2785,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
21842785fn performReloc(self: *Self, inst: Mir.Inst.Index) !void {
21852786 const tag = self.mir_instructions.items(.tag)[inst];
21862787 switch (tag) {
2187 .b_cond => self.mir_instructions.items(.data)[inst].inst_cond.inst = @intCast(Air.Inst.Index, self.mir_instructions.len),
2188 .b => self.mir_instructions.items(.data)[inst].inst = @intCast(Air.Inst.Index, self.mir_instructions.len),
2788 .cbz => self.mir_instructions.items(.data)[inst].r_inst.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),
2789 .b_cond => self.mir_instructions.items(.data)[inst].inst_cond.inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),
2790 .b => self.mir_instructions.items(.data)[inst].inst = @intCast(Mir.Inst.Index, self.mir_instructions.len),
21892791 else => unreachable,
21902792 }
21912793}
......@@ -2212,7 +2814,16 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
22122814 const operand_mcv = try self.resolveInst(operand);
22132815 const block_mcv = block_data.mcv;
22142816 if (block_mcv == .none) {
2215 block_data.mcv = operand_mcv;
2817 block_data.mcv = switch (operand_mcv) {
2818 .none, .dead, .unreach => unreachable,
2819 .register, .stack_offset, .memory => operand_mcv,
2820 .immediate => blk: {
2821 const new_mcv = try self.allocRegOrMem(block, true);
2822 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
2823 break :blk new_mcv;
2824 },
2825 else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}),
2826 };
22162827 } else {
22172828 try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv);
22182829 }
......@@ -2412,8 +3023,61 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
24123023 if (stack_offset == off)
24133024 return; // Copy stack variable to itself; nothing to do.
24143025
2415 const reg = try self.copyToTmpRegister(ty, mcv);
2416 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3026 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3027 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3028 if (ty.abiSize(self.target.*) <= ptr_bytes) {
3029 const reg = try self.copyToTmpRegister(ty, mcv);
3030 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3031 } else {
3032 // TODO optimize the register allocation
3033 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });
3034 self.register_manager.freezeRegs(&regs);
3035 defer self.register_manager.unfreezeRegs(&regs);
3036
3037 const src_reg = regs[0];
3038 const dst_reg = regs[1];
3039 const len_reg = regs[2];
3040 const count_reg = regs[3];
3041 const tmp_reg = regs[4];
3042
3043 // sub src_reg, fp, #off
3044 const adj_src_offset = off + @intCast(u32, ty.abiSize(self.target.*));
3045 const src_offset = math.cast(u12, adj_src_offset) catch return self.fail("TODO load: larger stack offsets", .{});
3046 _ = try self.addInst(.{
3047 .tag = .sub_immediate,
3048 .data = .{ .rr_imm12_sh = .{
3049 .rd = src_reg,
3050 .rn = .x29,
3051 .imm12 = src_offset,
3052 } },
3053 });
3054
3055 // sub dst_reg, fp, #stack_offset
3056 const adj_dst_off = stack_offset + @intCast(u32, ty.abiSize(self.target.*));
3057 const dst_offset = math.cast(u12, adj_dst_off) catch return self.fail("TODO load: larger stack offsets", .{});
3058 _ = try self.addInst(.{
3059 .tag = .sub_immediate,
3060 .data = .{ .rr_imm12_sh = .{
3061 .rd = dst_reg,
3062 .rn = .x29,
3063 .imm12 = dst_offset,
3064 } },
3065 });
3066
3067 // mov len, #elem_size
3068 const elem_size = @intCast(u32, ty.abiSize(self.target.*));
3069 const len_imm = math.cast(u16, elem_size) catch return self.fail("TODO load: larger stack offsets", .{});
3070 _ = try self.addInst(.{
3071 .tag = .movk,
3072 .data = .{ .r_imm16_sh = .{
3073 .rd = len_reg,
3074 .imm16 = len_imm,
3075 } },
3076 });
3077
3078 // memcpy(src, dst, len)
3079 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
3080 }
24173081 },
24183082 }
24193083}
......@@ -2445,11 +3109,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
24453109
24463110 _ = try self.addInst(.{
24473111 .tag = .cset,
2448 .data = .{ .rrr_cond = .{
3112 .data = .{ .r_cond = .{
24493113 .rd = reg,
2450 .rn = .xzr,
2451 .rm = .xzr,
2452 .cond = condition,
3114 .cond = condition.negate(),
24533115 } },
24543116 });
24553117 },
......@@ -2533,7 +3195,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
25333195 } },
25343196 });
25353197 },
2536 else => return self.fail("TODO implement genSetReg other types abi_size={}", .{abi_size}),
3198 3, 5, 6, 7 => return self.fail("TODO implement genSetReg types size {}", .{abi_size}),
3199 else => unreachable,
25373200 }
25383201 },
25393202 else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}),
......@@ -2713,27 +3376,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
27133376 }
27143377}
27153378
2716/// If the MCValue is an immediate, and it does not fit within this type,
2717/// we put it in a register.
2718/// A potential opportunity for future optimization here would be keeping track
2719/// of the fact that the instruction is available both as an immediate
2720/// and as a register.
2721fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue {
2722 const mcv = try self.resolveInst(operand);
2723 const ti = @typeInfo(T).Int;
2724 switch (mcv) {
2725 .immediate => |imm| {
2726 // This immediate is unsigned.
2727 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
2728 if (imm >= math.maxInt(U)) {
2729 return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) };
2730 }
2731 },
2732 else => {},
2733 }
2734 return mcv;
2735}
2736
27373379fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
27383380 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
27393381 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
......@@ -2847,31 +3489,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
28473489 }
28483490 },
28493491 .ErrorSet => {
2850 switch (typed_value.val.tag()) {
2851 .@"error" => {
2852 const err_name = typed_value.val.castTag(.@"error").?.data.name;
2853 const module = self.bin_file.options.module.?;
2854 const global_error_set = module.global_error_set;
2855 const error_index = global_error_set.get(err_name).?;
2856 return MCValue{ .immediate = error_index };
2857 },
2858 else => {
2859 // In this case we are rendering an error union which has a 0 bits payload.
2860 return MCValue{ .immediate = 0 };
2861 },
2862 }
3492 const err_name = typed_value.val.castTag(.@"error").?.data.name;
3493 const module = self.bin_file.options.module.?;
3494 const global_error_set = module.global_error_set;
3495 const error_index = global_error_set.get(err_name).?;
3496 return MCValue{ .immediate = error_index };
28633497 },
28643498 .ErrorUnion => {
28653499 const error_type = typed_value.ty.errorUnionSet();
28663500 const payload_type = typed_value.ty.errorUnionPayload();
2867 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
28683501
2869 if (!payload_type.hasRuntimeBits()) {
2870 // We use the error type directly as the type.
2871 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
2872 }
3502 if (typed_value.val.castTag(.eu_payload)) |pl| {
3503 if (!payload_type.hasRuntimeBits()) {
3504 // We use the error type directly as the type.
3505 return MCValue{ .immediate = 0 };
3506 }
28733507
2874 return self.fail("TODO implement error union const of type '{}'", .{typed_value.ty});
3508 _ = pl;
3509 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
3510 } else {
3511 if (!payload_type.hasRuntimeBits()) {
3512 // We use the error type directly as the type.
3513 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
3514 }
3515
3516 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty});
3517 }
28753518 },
28763519 else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
28773520 }
......@@ -3015,13 +3658,18 @@ fn parseRegName(name: []const u8) ?Register {
30153658}
30163659
30173660fn registerAlias(reg: Register, size_bytes: u32) Register {
3018 _ = size_bytes;
3019
3020 return reg;
3661 if (size_bytes == 0) {
3662 unreachable; // should be comptime known
3663 } else if (size_bytes <= 4) {
3664 return reg.to32();
3665 } else if (size_bytes <= 8) {
3666 return reg.to64();
3667 } else {
3668 unreachable; // TODO handle floating-point registers
3669 }
30213670}
30223671
3023/// For most architectures this does nothing. For x86_64 it resolves any aliased registers
3024/// to the 64-bit wide ones.
3672/// Resolves any aliased registers to the 64-bit wide ones.
30253673fn toCanonicalReg(reg: Register) Register {
3026 return reg;
3674 return reg.to64();
30273675}
src/arch/aarch64/Emit.zig+131-56
......@@ -50,11 +50,13 @@ const InnerError = error{
5050};
5151
5252const BranchType = enum {
53 cbz,
5354 b_cond,
5455 unconditional_branch_immediate,
5556
5657 fn default(tag: Mir.Inst.Tag) BranchType {
5758 return switch (tag) {
59 .cbz => .cbz,
5860 .b, .bl => .unconditional_branch_immediate,
5961 .b_cond => .b_cond,
6062 else => unreachable,
......@@ -83,6 +85,8 @@ pub fn emitMir(
8385 .b => try emit.mirBranch(inst),
8486 .bl => try emit.mirBranch(inst),
8587
88 .cbz => try emit.mirCompareAndBranch(inst),
89
8690 .blr => try emit.mirUnconditionalBranchRegister(inst),
8791 .ret => try emit.mirUnconditionalBranchRegister(inst),
8892
......@@ -91,7 +95,9 @@ pub fn emitMir(
9195
9296 .call_extern => try emit.mirCallExtern(inst),
9397
98 .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
9499 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
100 .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
95101
96102 .cset => try emit.mirConditionalSelect(inst),
97103
......@@ -100,6 +106,8 @@ pub fn emitMir(
100106 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
101107 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
102108
109 .eor_shifted_register => try emit.mirLogicalShiftedRegister(inst),
110
103111 .load_memory => try emit.mirLoadMemory(inst),
104112
105113 .ldp => try emit.mirLoadStoreRegisterPair(inst),
......@@ -128,10 +136,13 @@ pub fn emitMir(
128136
129137 .mov_register => try emit.mirMoveRegister(inst),
130138 .mov_to_from_sp => try emit.mirMoveRegister(inst),
139 .mvn => try emit.mirMoveRegister(inst),
131140
132141 .movk => try emit.mirMoveWideImmediate(inst),
133142 .movz => try emit.mirMoveWideImmediate(inst),
134143
144 .mul => try emit.mirDataProcessing3Source(inst),
145
135146 .nop => try emit.mirNop(),
136147
137148 .push_regs => try emit.mirPushPopRegs(inst),
......@@ -156,15 +167,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
156167 assert(offset & 0b11 == 0);
157168
158169 switch (tag) {
170 .cbz => {
171 if (std.math.cast(i19, @shrExact(offset, 2))) |_| {
172 return BranchType.cbz;
173 } else |_| {
174 return emit.fail("TODO support cbz branches larger than +-1 MiB", .{});
175 }
176 },
159177 .b, .bl => {
160 if (std.math.cast(i26, offset >> 2)) |_| {
178 if (std.math.cast(i26, @shrExact(offset, 2))) |_| {
161179 return BranchType.unconditional_branch_immediate;
162180 } else |_| {
163 return emit.fail("TODO support branches larger than +-128 MiB", .{});
181 return emit.fail("TODO support unconditional branches larger than +-128 MiB", .{});
164182 }
165183 },
166184 .b_cond => {
167 if (std.math.cast(i19, offset >> 2)) |_| {
185 if (std.math.cast(i19, @shrExact(offset, 2))) |_| {
168186 return BranchType.b_cond;
169187 } else |_| {
170188 return emit.fail("TODO support conditional branches larger than +-1 MiB", .{});
......@@ -179,8 +197,10 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
179197
180198 if (isBranch(tag)) {
181199 switch (emit.branch_types.get(inst).?) {
182 .unconditional_branch_immediate => return 4,
183 .b_cond => return 4,
200 .cbz,
201 .unconditional_branch_immediate,
202 .b_cond,
203 => return 4,
184204 }
185205 }
186206
......@@ -201,6 +221,12 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
201221 return 5 * 4;
202222 }
203223 },
224 .pop_regs, .push_regs => {
225 const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;
226 const number_of_regs = @popCount(u32, reg_list);
227 const number_of_insts = std.math.divCeil(u6, number_of_regs, 2) catch unreachable;
228 return number_of_insts * 4;
229 },
204230 .call_extern => return 4,
205231 .dbg_line,
206232 .dbg_epilogue_begin,
......@@ -212,7 +238,11 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
212238
213239fn isBranch(tag: Mir.Inst.Tag) bool {
214240 return switch (tag) {
215 .b, .bl, .b_cond => true,
241 .cbz,
242 .b,
243 .bl,
244 .b_cond,
245 => true,
216246 else => false,
217247 };
218248}
......@@ -221,6 +251,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
221251 const tag = emit.mir.instructions.items(.tag)[inst];
222252
223253 switch (tag) {
254 .cbz => return emit.mir.instructions.items(.data)[inst].r_inst.inst,
224255 .b, .bl => return emit.mir.instructions.items(.data)[inst].inst,
225256 .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst,
226257 else => unreachable,
......@@ -414,27 +445,30 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
414445
415446fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
416447 const tag = emit.mir.instructions.items(.tag)[inst];
417 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
418
419448 switch (tag) {
420 .add_immediate => try emit.writeInstruction(Instruction.add(
421 rr_imm12_sh.rd,
422 rr_imm12_sh.rn,
423 rr_imm12_sh.imm12,
424 rr_imm12_sh.sh == 1,
425 )),
426 .cmp_immediate => try emit.writeInstruction(Instruction.subs(
427 rr_imm12_sh.rd,
428 rr_imm12_sh.rn,
429 rr_imm12_sh.imm12,
430 rr_imm12_sh.sh == 1,
431 )),
432 .sub_immediate => try emit.writeInstruction(Instruction.sub(
433 rr_imm12_sh.rd,
434 rr_imm12_sh.rn,
435 rr_imm12_sh.imm12,
436 rr_imm12_sh.sh == 1,
437 )),
449 .add_immediate,
450 .sub_immediate,
451 => {
452 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
453 const rd = rr_imm12_sh.rd;
454 const rn = rr_imm12_sh.rn;
455 const imm12 = rr_imm12_sh.imm12;
456 const sh = rr_imm12_sh.sh == 1;
457
458 switch (tag) {
459 .add_immediate => try emit.writeInstruction(Instruction.add(rd, rn, imm12, sh)),
460 .sub_immediate => try emit.writeInstruction(Instruction.sub(rd, rn, imm12, sh)),
461 else => unreachable,
462 }
463 },
464 .cmp_immediate => {
465 const r_imm12_sh = emit.mir.instructions.items(.data)[inst].r_imm12_sh;
466 const rn = r_imm12_sh.rn;
467 const imm12 = r_imm12_sh.imm12;
468 const sh = r_imm12_sh.sh == 1;
469
470 try emit.writeInstruction(Instruction.subs(.xzr, rn, imm12, sh));
471 },
438472 else => unreachable,
439473 }
440474}
......@@ -481,6 +515,23 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
481515 }
482516}
483517
518fn mirCompareAndBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
519 const tag = emit.mir.instructions.items(.tag)[inst];
520 const r_inst = emit.mir.instructions.items(.data)[inst].r_inst;
521
522 const offset = @intCast(i64, emit.code_offset_mapping.get(r_inst.inst).?) - @intCast(i64, emit.code.items.len);
523 const branch_type = emit.branch_types.get(inst).?;
524 log.debug("mirCompareAndBranch: {} offset={}", .{ inst, offset });
525
526 switch (branch_type) {
527 .cbz => switch (tag) {
528 .cbz => try emit.writeInstruction(Instruction.cbz(r_inst.rt, @intCast(i21, offset))),
529 else => unreachable,
530 },
531 else => unreachable,
532 }
533}
534
484535fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
485536 const tag = emit.mir.instructions.items(.tag)[inst];
486537 const reg = emit.mir.instructions.items(.data)[inst].reg;
......@@ -565,30 +616,42 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
565616fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
566617 const tag = emit.mir.instructions.items(.tag)[inst];
567618 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
619 const rd = rrr_imm6_shift.rd;
620 const rn = rrr_imm6_shift.rn;
621 const rm = rrr_imm6_shift.rm;
622 const shift = rrr_imm6_shift.shift;
623 const imm6 = rrr_imm6_shift.imm6;
568624
569625 switch (tag) {
570 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(
571 rrr_imm6_shift.rd,
572 rrr_imm6_shift.rn,
573 rrr_imm6_shift.rm,
574 rrr_imm6_shift.shift,
575 rrr_imm6_shift.imm6,
576 )),
626 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),
627 .cmp_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(rd, rn, rm, shift, imm6)),
628 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),
577629 else => unreachable,
578630 }
579631}
580632
581633fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
582634 const tag = emit.mir.instructions.items(.tag)[inst];
583 const rrr_cond = emit.mir.instructions.items(.data)[inst].rrr_cond;
635 switch (tag) {
636 .cset => {
637 const r_cond = emit.mir.instructions.items(.data)[inst].r_cond;
638 try emit.writeInstruction(Instruction.csinc(r_cond.rd, .xzr, .xzr, r_cond.cond));
639 },
640 else => unreachable,
641 }
642}
643
644fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
645 const tag = emit.mir.instructions.items(.tag)[inst];
646 const rrr_imm6_logical_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_logical_shift;
647 const rd = rrr_imm6_logical_shift.rd;
648 const rn = rrr_imm6_logical_shift.rn;
649 const rm = rrr_imm6_logical_shift.rm;
650 const shift = rrr_imm6_logical_shift.shift;
651 const imm6 = rrr_imm6_logical_shift.imm6;
584652
585653 switch (tag) {
586 .cset => try emit.writeInstruction(Instruction.csinc(
587 rrr_cond.rd,
588 rrr_cond.rn,
589 rrr_cond.rm,
590 rrr_cond.cond,
591 )),
654 .eor_shifted_register => try emit.writeInstruction(Instruction.eor(rd, rn, rm, shift, imm6)),
592655 else => unreachable,
593656 }
594657}
......@@ -653,20 +716,14 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
653716fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {
654717 const tag = emit.mir.instructions.items(.tag)[inst];
655718 const load_store_register_pair = emit.mir.instructions.items(.data)[inst].load_store_register_pair;
719 const rt = load_store_register_pair.rt;
720 const rt2 = load_store_register_pair.rt2;
721 const rn = load_store_register_pair.rn;
722 const offset = load_store_register_pair.offset;
656723
657724 switch (tag) {
658 .stp => try emit.writeInstruction(Instruction.stp(
659 load_store_register_pair.rt,
660 load_store_register_pair.rt2,
661 load_store_register_pair.rn,
662 load_store_register_pair.offset,
663 )),
664 .ldp => try emit.writeInstruction(Instruction.ldp(
665 load_store_register_pair.rt,
666 load_store_register_pair.rt2,
667 load_store_register_pair.rn,
668 load_store_register_pair.offset,
669 )),
725 .stp => try emit.writeInstruction(Instruction.stp(rt, rt2, rn, offset)),
726 .ldp => try emit.writeInstruction(Instruction.ldp(rt, rt2, rn, offset)),
670727 else => unreachable,
671728 }
672729}
......@@ -782,11 +839,19 @@ fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
782839
783840fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
784841 const tag = emit.mir.instructions.items(.tag)[inst];
785 const rr = emit.mir.instructions.items(.data)[inst].rr;
786
787842 switch (tag) {
788 .mov_register => try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, Instruction.Shift.none)),
789 .mov_to_from_sp => try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false)),
843 .mov_register => {
844 const rr = emit.mir.instructions.items(.data)[inst].rr;
845 try emit.writeInstruction(Instruction.orr(rr.rd, .xzr, rr.rn, .lsl, 0));
846 },
847 .mov_to_from_sp => {
848 const rr = emit.mir.instructions.items(.data)[inst].rr;
849 try emit.writeInstruction(Instruction.add(rr.rd, rr.rn, 0, false));
850 },
851 .mvn => {
852 const rr_imm6_shift = emit.mir.instructions.items(.data)[inst].rr_imm6_shift;
853 try emit.writeInstruction(Instruction.orn(rr_imm6_shift.rd, .xzr, rr_imm6_shift.rm, .lsl, 0));
854 },
790855 else => unreachable,
791856 }
792857}
......@@ -802,6 +867,16 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
802867 }
803868}
804869
870fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
871 const tag = emit.mir.instructions.items(.tag)[inst];
872 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
873
874 switch (tag) {
875 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
876 else => unreachable,
877 }
878}
879
805880fn mirNop(emit: *Emit) !void {
806881 try emit.writeInstruction(Instruction.nop());
807882}
src/arch/aarch64/Mir.zig+59-6
......@@ -26,6 +26,8 @@ pub const Inst = struct {
2626 pub const Tag = enum(u16) {
2727 /// Add (immediate)
2828 add_immediate,
29 /// Add (shifted register)
30 add_shifted_register,
2931 /// Branch conditionally
3032 b_cond,
3133 /// Branch
......@@ -38,6 +40,8 @@ pub const Inst = struct {
3840 brk,
3941 /// Pseudo-instruction: Call extern
4042 call_extern,
43 /// Compare and Branch on Zero
44 cbz,
4145 /// Compare (immediate)
4246 cmp_immediate,
4347 /// Compare (shifted register)
......@@ -50,6 +54,8 @@ pub const Inst = struct {
5054 dbg_epilogue_begin,
5155 /// Pseudo-instruction: Update debug line
5256 dbg_line,
57 /// Bitwise Exclusive OR (shifted register)
58 eor_shifted_register,
5359 /// Pseudo-instruction: Load memory
5460 ///
5561 /// Payload is `LoadMemory`
......@@ -82,6 +88,10 @@ pub const Inst = struct {
8288 movk,
8389 /// Move wide with zero
8490 movz,
91 /// Multiply
92 mul,
93 /// Bitwise NOT
94 mvn,
8595 /// No Operation
8696 nop,
8797 /// Pseudo-instruction: Pop multiple registers
......@@ -112,6 +122,8 @@ pub const Inst = struct {
112122 strh_register,
113123 /// Subtract (immediate)
114124 sub_immediate,
125 /// Subtract (shifted register)
126 sub_shifted_register,
115127 /// Supervisor Call
116128 svc,
117129 };
......@@ -171,6 +183,20 @@ pub const Inst = struct {
171183 imm16: u16,
172184 hw: u2 = 0,
173185 },
186 /// A register and a condition
187 ///
188 /// Used by e.g. cset
189 r_cond: struct {
190 rd: Register,
191 cond: bits.Instruction.Condition,
192 },
193 /// A register and another instruction
194 ///
195 /// Used by e.g. cbz
196 r_inst: struct {
197 rt: Register,
198 inst: Index,
199 },
174200 /// Two registers
175201 ///
176202 /// Used by e.g. mov_register
......@@ -178,6 +204,14 @@ pub const Inst = struct {
178204 rd: Register,
179205 rn: Register,
180206 },
207 /// A register, an unsigned 12-bit immediate, and an optional shift
208 ///
209 /// Used by e.g. cmp_immediate
210 r_imm12_sh: struct {
211 rn: Register,
212 imm12: u12,
213 sh: u1 = 0,
214 },
181215 /// Two registers, an unsigned 12-bit immediate, and an optional shift
182216 ///
183217 /// Used by e.g. sub_immediate
......@@ -187,6 +221,23 @@ pub const Inst = struct {
187221 imm12: u12,
188222 sh: u1 = 0,
189223 },
224 /// Two registers and a shift (shift type and 6-bit amount)
225 ///
226 /// Used by e.g. mvn
227 rr_imm6_shift: struct {
228 rd: Register,
229 rm: Register,
230 imm6: u6,
231 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
232 },
233 /// Two registers
234 ///
235 /// Used by e.g. mul
236 rrr: struct {
237 rd: Register,
238 rn: Register,
239 rm: Register,
240 },
190241 /// Three registers and a shift (shift type and 6-bit amount)
191242 ///
192243 /// Used by e.g. cmp_shifted_register
......@@ -197,18 +248,20 @@ pub const Inst = struct {
197248 imm6: u6,
198249 shift: bits.Instruction.AddSubtractShiftedRegisterShift,
199250 },
200 /// Three registers and a condition
251 /// Three registers and a shift (logical instruction version)
252 /// (shift type and 6-bit amount)
201253 ///
202 /// Used by e.g. cset
203 rrr_cond: struct {
254 /// Used by e.g. eor_shifted_register
255 rrr_imm6_logical_shift: struct {
204256 rd: Register,
205257 rn: Register,
206258 rm: Register,
207 cond: bits.Instruction.Condition,
259 imm6: u6,
260 shift: bits.Instruction.LogicalShiftedRegisterShift,
208261 },
209262 /// Two registers and a LoadStoreOffsetImmediate
210263 ///
211 /// Used by e.g. str_register
264 /// Used by e.g. str_immediate
212265 load_store_register_immediate: struct {
213266 rt: Register,
214267 rn: Register,
......@@ -224,7 +277,7 @@ pub const Inst = struct {
224277 },
225278 /// A registers and a stack offset
226279 ///
227 /// Used by e.g. str_register
280 /// Used by e.g. str_stack
228281 load_store_stack: struct {
229282 rt: Register,
230283 offset: u32,
src/arch/aarch64/bits.zig+138-43
......@@ -332,23 +332,17 @@ pub const Instruction = union(enum) {
332332 op: u1,
333333 sf: u1,
334334 },
335
336 pub const Shift = struct {
337 shift: Type = .lsl,
338 amount: u6 = 0,
339
340 pub const Type = enum(u2) {
341 lsl,
342 lsr,
343 asr,
344 ror,
345 };
346
347 pub const none = Shift{
348 .shift = .lsl,
349 .amount = 0,
350 };
351 };
335 data_processing_3_source: packed struct {
336 rd: u5,
337 rn: u5,
338 ra: u5,
339 o0: u1,
340 rm: u5,
341 op31: u3,
342 fixed: u5 = 0b11011,
343 op54: u2,
344 sf: u1,
345 },
352346
353347 pub const Condition = enum(u4) {
354348 /// Integer: Equal
......@@ -470,6 +464,7 @@ pub const Instruction = union(enum) {
470464 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
471465 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
472466 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
467 .data_processing_3_source => |v| @bitCast(u32, v),
473468 };
474469 }
475470
......@@ -807,25 +802,28 @@ pub const Instruction = union(enum) {
807802 };
808803 }
809804
805 pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror };
806
810807 fn logicalShiftedRegister(
811808 opc: u2,
812809 n: u1,
813 shift: Shift,
814810 rd: Register,
815811 rn: Register,
816812 rm: Register,
813 shift: LogicalShiftedRegisterShift,
814 amount: u6,
817815 ) Instruction {
818816 switch (rd.size()) {
819817 32 => {
820 assert(shift.amount < 32);
818 assert(amount < 32);
821819 return Instruction{
822820 .logical_shifted_register = .{
823821 .rd = rd.id(),
824822 .rn = rn.id(),
825 .imm6 = shift.amount,
823 .imm6 = amount,
826824 .rm = rm.id(),
827825 .n = n,
828 .shift = @enumToInt(shift.shift),
826 .shift = @enumToInt(shift),
829827 .opc = opc,
830828 .sf = 0b0,
831829 },
......@@ -836,10 +834,10 @@ pub const Instruction = union(enum) {
836834 .logical_shifted_register = .{
837835 .rd = rd.id(),
838836 .rn = rn.id(),
839 .imm6 = shift.amount,
837 .imm6 = amount,
840838 .rm = rm.id(),
841839 .n = n,
842 .shift = @enumToInt(shift.shift),
840 .shift = @enumToInt(shift),
843841 .opc = opc,
844842 .sf = 0b1,
845843 },
......@@ -967,6 +965,33 @@ pub const Instruction = union(enum) {
967965 };
968966 }
969967
968 fn dataProcessing3Source(
969 op54: u2,
970 op31: u3,
971 o0: u1,
972 rd: Register,
973 rn: Register,
974 rm: Register,
975 ra: Register,
976 ) Instruction {
977 return Instruction{
978 .data_processing_3_source = .{
979 .rd = rd.id(),
980 .rn = rn.id(),
981 .ra = ra.id(),
982 .o0 = o0,
983 .rm = rm.id(),
984 .op31 = op31,
985 .op54 = op54,
986 .sf = switch (rd.size()) {
987 32 => 0b0,
988 64 => 0b1,
989 else => unreachable, // unexpected register size
990 },
991 },
992 };
993 }
994
970995 // Helper functions for assembly syntax functions
971996
972997 // Move wide (immediate)
......@@ -1120,36 +1145,84 @@ pub const Instruction = union(enum) {
11201145
11211146 // Logical (shifted register)
11221147
1123 pub fn @"and"(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1124 return logicalShiftedRegister(0b00, 0b0, shift, rd, rn, rm);
1148 pub fn @"and"(
1149 rd: Register,
1150 rn: Register,
1151 rm: Register,
1152 shift: LogicalShiftedRegisterShift,
1153 amount: u6,
1154 ) Instruction {
1155 return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
11251156 }
11261157
1127 pub fn bic(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1128 return logicalShiftedRegister(0b00, 0b1, shift, rd, rn, rm);
1158 pub fn bic(
1159 rd: Register,
1160 rn: Register,
1161 rm: Register,
1162 shift: LogicalShiftedRegisterShift,
1163 amount: u6,
1164 ) Instruction {
1165 return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
11291166 }
11301167
1131 pub fn orr(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1132 return logicalShiftedRegister(0b01, 0b0, shift, rd, rn, rm);
1168 pub fn orr(
1169 rd: Register,
1170 rn: Register,
1171 rm: Register,
1172 shift: LogicalShiftedRegisterShift,
1173 amount: u6,
1174 ) Instruction {
1175 return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
11331176 }
11341177
1135 pub fn orn(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1136 return logicalShiftedRegister(0b01, 0b1, shift, rd, rn, rm);
1178 pub fn orn(
1179 rd: Register,
1180 rn: Register,
1181 rm: Register,
1182 shift: LogicalShiftedRegisterShift,
1183 amount: u6,
1184 ) Instruction {
1185 return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
11371186 }
11381187
1139 pub fn eor(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1140 return logicalShiftedRegister(0b10, 0b0, shift, rd, rn, rm);
1188 pub fn eor(
1189 rd: Register,
1190 rn: Register,
1191 rm: Register,
1192 shift: LogicalShiftedRegisterShift,
1193 amount: u6,
1194 ) Instruction {
1195 return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
11411196 }
11421197
1143 pub fn eon(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1144 return logicalShiftedRegister(0b10, 0b1, shift, rd, rn, rm);
1198 pub fn eon(
1199 rd: Register,
1200 rn: Register,
1201 rm: Register,
1202 shift: LogicalShiftedRegisterShift,
1203 amount: u6,
1204 ) Instruction {
1205 return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
11451206 }
11461207
1147 pub fn ands(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1148 return logicalShiftedRegister(0b11, 0b0, shift, rd, rn, rm);
1208 pub fn ands(
1209 rd: Register,
1210 rn: Register,
1211 rm: Register,
1212 shift: LogicalShiftedRegisterShift,
1213 amount: u6,
1214 ) Instruction {
1215 return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
11491216 }
11501217
1151 pub fn bics(rd: Register, rn: Register, rm: Register, shift: Shift) Instruction {
1152 return logicalShiftedRegister(0b11, 0b1, shift, rd, rn, rm);
1218 pub fn bics(
1219 rd: Register,
1220 rn: Register,
1221 rm: Register,
1222 shift: LogicalShiftedRegisterShift,
1223 amount: u6,
1224 ) Instruction {
1225 return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount);
11531226 }
11541227
11551228 // Add/subtract (immediate)
......@@ -1245,6 +1318,24 @@ pub const Instruction = union(enum) {
12451318 pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
12461319 return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond);
12471320 }
1321
1322 // Data processing (3 source)
1323
1324 pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1325 return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra);
1326 }
1327
1328 pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1329 return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra);
1330 }
1331
1332 pub fn mul(rd: Register, rn: Register, rm: Register) Instruction {
1333 return madd(rd, rn, rm, .xzr);
1334 }
1335
1336 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
1337 return msub(rd, rn, rm, .xzr);
1338 }
12481339};
12491340
12501341test {
......@@ -1259,11 +1350,11 @@ test "serialize instructions" {
12591350
12601351 const testcases = [_]Testcase{
12611352 .{ // orr x0, xzr, x1
1262 .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none),
1353 .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0),
12631354 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
12641355 },
12651356 .{ // orn x0, xzr, x1
1266 .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none),
1357 .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0),
12671358 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
12681359 },
12691360 .{ // movz x1, #4
......@@ -1383,11 +1474,11 @@ test "serialize instructions" {
13831474 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
13841475 },
13851476 .{ // and x0, x4, x2
1386 .inst = Instruction.@"and"(.x0, .x4, .x2, .{}),
1477 .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0),
13871478 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
13881479 },
13891480 .{ // and x0, x4, x2, lsl #0x8
1390 .inst = Instruction.@"and"(.x0, .x4, .x2, .{ .shift = .lsl, .amount = 0x8 }),
1481 .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0x8),
13911482 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
13921483 },
13931484 .{ // add x0, x10, #10
......@@ -1414,6 +1505,10 @@ test "serialize instructions" {
14141505 .inst = Instruction.csinc(.x1, .x2, .x4, .eq),
14151506 .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001,
14161507 },
1508 .{ // mul x1, x4, x9
1509 .inst = Instruction.mul(.x1, .x4, .x9),
1510 .expected = 0b1_00_11011_000_01001_0_11111_00100_00001,
1511 },
14171512 };
14181513
14191514 for (testcases) |case| {
test/behavior.zig+1-1
......@@ -54,7 +54,7 @@ test {
5454 _ = @import("behavior/decltest.zig");
5555 }
5656
57 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
57 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_aarch64) {
5858 // Tests that pass (partly) for stage1, llvm backend, C backend, wasm backend.
5959 _ = @import("behavior/bitcast.zig");
6060 _ = @import("behavior/bugs/624.zig");
test/behavior/align.zig+18
......@@ -27,6 +27,7 @@ test "default alignment allows unspecified in type syntax" {
2727}
2828
2929test "implicitly decreasing pointer alignment" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3031 const a: u32 align(4) = 3;
3132 const b: u32 align(8) = 4;
3233 try expect(addUnaligned(&a, &b) == 7);
......@@ -37,6 +38,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
3738}
3839
3940test "@alignCast pointers" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4042 var x: u32 align(4) = 1;
4143 expectsOnly1(&x);
4244 try expect(x == 2);
......@@ -102,6 +104,7 @@ fn fnWithAlignedStack() i32 {
102104}
103105
104106test "implicitly decreasing slice alignment" {
107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
106109
107110 const a: u32 align(4) = 3;
......@@ -113,6 +116,7 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
113116}
114117
115118test "specifying alignment allows pointer cast" {
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
117121
118122 try testBytesAlign(0x33);
......@@ -124,6 +128,7 @@ fn testBytesAlign(b: u8) !void {
124128}
125129
126130test "@alignCast slices" {
131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127132 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
128133
129134 var array align(4) = [_]u32{ 1, 1 };
......@@ -139,6 +144,7 @@ fn sliceExpects4(slice: []align(4) u32) void {
139144}
140145
141146test "return error union with 128-bit integer" {
147 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
142148 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143149
144150 try expect(3 == try give());
......@@ -148,6 +154,7 @@ fn give() anyerror!u128 {
148154}
149155
150156test "page aligned array on stack" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
151158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
152159 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
153160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -173,6 +180,7 @@ fn noop1() align(1) void {}
173180fn noop4() align(4) void {}
174181
175182test "function alignment" {
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176184 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
177185 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
178186 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -189,6 +197,7 @@ test "function alignment" {
189197}
190198
191199test "implicitly decreasing fn alignment" {
200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
192201 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
193202 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
194203 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
......@@ -216,6 +225,7 @@ fn alignedBig() align(16) i32 {
216225}
217226
218227test "@alignCast functions" {
228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
219229 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
220230 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
221231 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -239,6 +249,7 @@ fn simple4() align(4) i32 {
239249}
240250
241251test "generic function with align param" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
242253 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
243254 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
244255 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -260,6 +271,7 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
260271}
261272
262273test "runtime known array index has best alignment possible" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
263275 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
264276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
265277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -302,6 +314,7 @@ fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
302314}
303315
304316test "alignment of function with c calling convention" {
317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
305318 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
306319
307320 var runtime_nothing = &nothing;
......@@ -318,6 +331,7 @@ const DefaultAligned = struct {
318331};
319332
320333test "read 128-bit field from default aligned struct in stack memory" {
334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
321335 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
322336 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
323337 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -337,6 +351,7 @@ var default_aligned_global = DefaultAligned{
337351};
338352
339353test "read 128-bit field from default aligned struct in global memory" {
354 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
340355 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
341356 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
342357 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
......@@ -348,6 +363,7 @@ test "read 128-bit field from default aligned struct in global memory" {
348363}
349364
350365test "struct field explicit alignment" {
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
351367 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
352368 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
353369 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
......@@ -369,6 +385,7 @@ test "struct field explicit alignment" {
369385}
370386
371387test "align(@alignOf(T)) T does not force resolution of T" {
388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
372389 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
373390 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
374391 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
......@@ -397,6 +414,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {
397414}
398415
399416test "align(N) on functions" {
417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
400418 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
401419 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
402420 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
test/behavior/alignof.zig+1
......@@ -11,6 +11,7 @@ const Foo = struct {
1111};
1212
1313test "@alignOf(T) before referencing T" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1415 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1617 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/array.zig+27
......@@ -6,6 +6,7 @@ const expect = testing.expect;
66const expectEqual = testing.expectEqual;
77
88test "array to slice" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1011
1112 const a: u32 align(4) = 3;
......@@ -20,6 +21,7 @@ test "array to slice" {
2021}
2122
2223test "arrays" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2325 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2426
2527 var array: [5]u32 = undefined;
......@@ -46,6 +48,7 @@ fn getArrayLen(a: []const u32) usize {
4648}
4749
4850test "array init with mult" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4952 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5053
5154 const a = 'a';
......@@ -57,6 +60,7 @@ test "array init with mult" {
5760}
5861
5962test "array literal with explicit type" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6064 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6165
6266 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
......@@ -86,6 +90,7 @@ const ArrayDotLenConstExpr = struct {
8690const some_array = [_]u8{ 0, 1, 2, 3 };
8791
8892test "array literal with specified size" {
93 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8994 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9095
9196 var array = [2]u8{ 1, 2 };
......@@ -94,6 +99,7 @@ test "array literal with specified size" {
9499}
95100
96101test "array len field" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
97103 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98104
99105 var arr = [4]u8{ 0, 0, 0, 0 };
......@@ -105,6 +111,7 @@ test "array len field" {
105111}
106112
107113test "array with sentinels" {
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
108115 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109116
110117 const S = struct {
......@@ -134,6 +141,7 @@ test "array with sentinels" {
134141}
135142
136143test "void arrays" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
137145 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138146
139147 var array: [4]void = undefined;
......@@ -144,6 +152,7 @@ test "void arrays" {
144152}
145153
146154test "nested arrays" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147156 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
148157
149158 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
......@@ -157,6 +166,7 @@ test "nested arrays" {
157166}
158167
159168test "implicit comptime in array type size" {
169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160170 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161171
162172 var arr: [plusOne(10)]bool = undefined;
......@@ -168,6 +178,7 @@ fn plusOne(x: u32) u32 {
168178}
169179
170180test "single-item pointer to array indexing and slicing" {
181 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
171182 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
172183
173184 try testSingleItemPtrArrayIndexSlice();
......@@ -193,6 +204,7 @@ fn doSomeMangling(array: *[4]u8) void {
193204}
194205
195206test "implicit cast zero sized array ptr to slice" {
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
196208 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
197209
198210 {
......@@ -208,6 +220,7 @@ test "implicit cast zero sized array ptr to slice" {
208220}
209221
210222test "anonymous list literal syntax" {
223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
211224 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
212225
213226 const S = struct {
......@@ -227,6 +240,7 @@ var s_array: [8]Sub = undefined;
227240const Sub = struct { b: u8 };
228241const Str = struct { a: []Sub };
229242test "set global var array via slice embedded in struct" {
243 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
230244 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
231245 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
232246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -243,6 +257,7 @@ test "set global var array via slice embedded in struct" {
243257}
244258
245259test "read/write through global variable array of struct fields initialized via array mult" {
260 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
246261 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
247262 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
248263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -264,6 +279,7 @@ test "read/write through global variable array of struct fields initialized via
264279}
265280
266281test "implicit cast single-item pointer" {
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267283 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
268284 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
269285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -284,6 +300,7 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
284300}
285301
286302test "comptime evaluating function that takes array by value" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
287304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
288305 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
289306 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -296,6 +313,7 @@ test "comptime evaluating function that takes array by value" {
296313}
297314
298315test "runtime initialize array elem and then implicit cast to slice" {
316 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299317 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
300318 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
301319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -306,6 +324,7 @@ test "runtime initialize array elem and then implicit cast to slice" {
306324}
307325
308326test "array literal as argument to function" {
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
309328 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
310329 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
311330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -334,6 +353,7 @@ test "array literal as argument to function" {
334353}
335354
336355test "double nested array to const slice cast in array literal" {
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337357 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
338358 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
339359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -395,6 +415,7 @@ test "double nested array to const slice cast in array literal" {
395415}
396416
397417test "anonymous literal in array" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
398419 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
399420 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
400421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -420,6 +441,7 @@ test "anonymous literal in array" {
420441}
421442
422443test "access the null element of a null terminated array" {
444 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
423445 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
424446 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
425447 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -437,6 +459,7 @@ test "access the null element of a null terminated array" {
437459}
438460
439461test "type deduction for array subscript expression" {
462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
440463 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
441464 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
442465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -455,6 +478,7 @@ test "type deduction for array subscript expression" {
455478}
456479
457480test "sentinel element count towards the ABI size calculation" {
481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
458482 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
459483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
460484 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -481,6 +505,7 @@ test "sentinel element count towards the ABI size calculation" {
481505}
482506
483507test "zero-sized array with recursive type definition" {
508 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
484509 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
485510 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
486511 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -505,6 +530,7 @@ test "zero-sized array with recursive type definition" {
505530}
506531
507532test "type coercion of anon struct literal to array" {
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
508534 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
509535 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
510536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -540,6 +566,7 @@ test "type coercion of anon struct literal to array" {
540566}
541567
542568test "type coercion of pointer to anon struct literal to pointer to array" {
569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
543570 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
544571 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
545572 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
test/behavior/basic.zig+32
......@@ -15,6 +15,7 @@ test "empty function with comments" {
1515}
1616
1717test "truncate" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1920
2021 try expect(testTruncate(0x10fd) == 0xfd);
......@@ -25,6 +26,7 @@ fn testTruncate(x: u32) u8 {
2526}
2627
2728test "truncate to non-power-of-two integers" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2830 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2931
3032 try testTrunc(u32, u1, 0b10101, 0b1);
......@@ -46,6 +48,7 @@ const g1: i32 = 1233 + 1;
4648var g2: i32 = 0;
4749
4850test "global variables" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4952 try expect(g2 == 0);
5053 g2 = g1;
5154 try expect(g2 == 1234);
......@@ -112,6 +115,7 @@ fn first4KeysOfHomeRow() []const u8 {
112115}
113116
114117test "return string from function" {
118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116120 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
117121
......@@ -119,12 +123,14 @@ test "return string from function" {
119123}
120124
121125test "hex escape" {
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
122127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
123128
124129 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
125130}
126131
127132test "multiline string" {
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
128134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
129135
130136 const s1 =
......@@ -137,6 +143,7 @@ test "multiline string" {
137143}
138144
139145test "multiline string comments at start" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
140147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
141148
142149 const s1 =
......@@ -149,6 +156,7 @@ test "multiline string comments at start" {
149156}
150157
151158test "multiline string comments at end" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
152160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
153161
154162 const s1 =
......@@ -161,6 +169,7 @@ test "multiline string comments at end" {
161169}
162170
163171test "multiline string comments in middle" {
172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
165174
166175 const s1 =
......@@ -173,6 +182,7 @@ test "multiline string comments in middle" {
173182}
174183
175184test "multiline string comments at multiple places" {
185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
177187
178188 const s1 =
......@@ -191,6 +201,7 @@ test "string concatenation" {
191201}
192202
193203test "array mult operator" {
204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194205 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
195206
196207 try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
......@@ -216,6 +227,7 @@ test "compile time global reinterpret" {
216227}
217228
218229test "cast undefined" {
230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
219231 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
220232
221233 const array: [100]u8 = undefined;
......@@ -227,6 +239,7 @@ fn testCastUndefined(x: []const u8) void {
227239}
228240
229241test "implicit cast after unreachable" {
242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
230243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
231244
232245 try expect(outer() == 1234);
......@@ -284,6 +297,7 @@ fn fB() []const u8 {
284297}
285298
286299test "call function pointer in struct" {
300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
287301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
288302 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
289303
......@@ -310,6 +324,7 @@ const FnPtrWrapper = struct {
310324};
311325
312326test "const ptr from var variable" {
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
313328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
314329
315330 var x: u64 = undefined;
......@@ -326,6 +341,7 @@ fn copy(src: *const u64, dst: *u64) void {
326341}
327342
328343test "call result of if else expression" {
344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
329345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
330346 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
331347 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -339,6 +355,7 @@ fn f2(x: bool) []const u8 {
339355}
340356
341357test "memcpy and memset intrinsics" {
358 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
342359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
343360 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
344361 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -361,6 +378,7 @@ fn testMemcpyMemset() !void {
361378}
362379
363380test "variable is allowed to be a pointer to an opaque type" {
381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
364382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
365383 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
366384 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -374,6 +392,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
374392}
375393
376394test "take address of parameter" {
395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
377396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
378397 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
379398
......@@ -400,6 +419,7 @@ fn testPointerToVoidReturnType2() *const void {
400419}
401420
402421test "array 2D const double ptr" {
422 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
403423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
404424 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
405425
......@@ -419,6 +439,7 @@ fn testArray2DConstDoublePtr(ptr: *const f32) !void {
419439}
420440
421441test "double implicit cast in same expression" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
422443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
423444 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
424445
......@@ -430,6 +451,7 @@ fn nine() u8 {
430451}
431452
432453test "struct inside function" {
454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
433455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
434456
435457 try testStructInFn();
......@@ -451,6 +473,7 @@ fn testStructInFn() !void {
451473}
452474
453475test "fn call returning scalar optional in equality expression" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
454477 try expect(getNull() == null);
455478}
456479
......@@ -459,6 +482,7 @@ fn getNull() ?*i32 {
459482}
460483
461484test "global variable assignment with optional unwrapping with var initialized to undefined" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
462486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
463487
464488 const S = struct {
......@@ -476,6 +500,7 @@ test "global variable assignment with optional unwrapping with var initialized t
476500var global_foo: *i32 = undefined;
477501
478502test "peer result location with typed parent, runtime condition, comptime prongs" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
479504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
480505 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
481506
......@@ -550,6 +575,7 @@ test "comptime cast fn to ptr" {
550575}
551576
552577test "equality compare fn ptrs" {
578 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
553579 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
554580
555581 var a = &emptyFn;
......@@ -557,6 +583,7 @@ test "equality compare fn ptrs" {
557583}
558584
559585test "self reference through fn ptr field" {
586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
560587 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
561588 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
562589
......@@ -576,6 +603,7 @@ test "self reference through fn ptr field" {
576603}
577604
578605test "global variable initialized to global variable array element" {
606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
579607 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
580608 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
581609
......@@ -593,6 +621,7 @@ var gdt = [_]GDTEntry{
593621var global_ptr = &gdt[0];
594622
595623test "global constant is loaded with a runtime-known index" {
624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
596625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
597626
598627 const S = struct {
......@@ -610,6 +639,7 @@ test "global constant is loaded with a runtime-known index" {
610639}
611640
612641test "multiline string literal is null terminated" {
642 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
613643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
614644 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
615645
......@@ -643,6 +673,7 @@ test "explicit cast optional pointers" {
643673}
644674
645675test "pointer comparison" {
676 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
646677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
647678 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
648679
......@@ -655,6 +686,7 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
655686}
656687
657688test "string concatenation" {
689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
658690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
659691 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
660692
test/behavior/bit_shifting.zig+1
......@@ -61,6 +61,7 @@ fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, compt
6161}
6262
6363test "sharded table" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6465 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6566 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6667 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/bugs/1381.zig+1
......@@ -12,6 +12,7 @@ const A = union(enum) {
1212};
1313
1414test "union that needs padding bytes inside an array" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1617 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1718 var as = [_]A{
test/behavior/bugs/1486.zig+2
......@@ -1,10 +1,12 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const builtin = @import("builtin");
34
45const ptr = &global;
56var global: usize = 123;
67
78test "constant pointer to global variable causes runtime load" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
810 global = 1234;
911 try expect(&global == ptr);
1012 try expect(ptr.* == 1234);
test/behavior/bugs/1735.zig+1
......@@ -42,6 +42,7 @@ const a = struct {
4242};
4343
4444test "initialization" {
45 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4546 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
4647 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4748 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/bugs/1741.zig+1
......@@ -2,6 +2,7 @@ const std = @import("std");
22const builtin = @import("builtin");
33
44test "fixed" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
78 const x: f32 align(128) = 12.34;
test/behavior/bugs/2006.zig+1
......@@ -6,6 +6,7 @@ const S = struct {
66 p: *S,
77};
88test "bug 2006" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1011 var a: S = undefined;
1112 a = S{ .p = undefined };
test/behavior/bugs/2578.zig+1
......@@ -12,6 +12,7 @@ fn bar(pointer: ?*anyopaque) void {
1212}
1313
1414test "fixed" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1617 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1718 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
test/behavior/bugs/3007.zig+1
......@@ -19,6 +19,7 @@ fn get_foo() Foo.FooError!*Foo {
1919}
2020
2121test "fixed" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2425 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
test/behavior/bugs/3112.zig+1
......@@ -12,6 +12,7 @@ fn prev(p: ?State) void {
1212}
1313
1414test "zig test crash" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1617 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
test/behavior/bugs/3367.zig+1
......@@ -10,6 +10,7 @@ const Mixin = struct {
1010};
1111
1212test "container member access usingnamespace decls" {
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1314 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1516 var foo = Foo{};
test/behavior/bugs/394.zig+1
......@@ -11,6 +11,7 @@ const expect = @import("std").testing.expect;
1111const builtin = @import("builtin");
1212
1313test "bug 394 fixed" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1617 const x = S{
test/behavior/bugs/656.zig+1
......@@ -11,6 +11,7 @@ const Value = struct {
1111};
1212
1313test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1617 try foo(false, true);
test/behavior/bugs/7250.zig+1
......@@ -14,6 +14,7 @@ threadlocal var g_uart0 = nrfx_uart_t{
1414};
1515
1616test "reference a global threadlocal variable" {
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1718 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1920 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/cast.zig+36
......@@ -18,6 +18,7 @@ test "integer literal to pointer cast" {
1818}
1919
2020test "peer type resolution: ?T and T" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2122 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2223
2324 try expect(peerTypeTAndOptionalT(true, false).? == 0);
......@@ -94,6 +95,7 @@ test "comptime_int @intToFloat" {
9495}
9596
9697test "@floatToInt" {
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9799 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99101
......@@ -116,6 +118,7 @@ fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
116118}
117119
118120test "implicitly cast indirect pointer to maybe-indirect pointer" {
121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
119122 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
120123
121124 const S = struct {
......@@ -174,6 +177,7 @@ test "@floatCast comptime_int and comptime_float" {
174177}
175178
176179test "coerce undefined to optional" {
180 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177181 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
178182
179183 try expect(MakeType(void).getNull() == null);
......@@ -193,6 +197,7 @@ fn MakeType(comptime T: type) type {
193197}
194198
195199test "implicit cast from *[N]T to [*c]T" {
200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
196201 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
197202
198203 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
......@@ -205,6 +210,7 @@ test "implicit cast from *[N]T to [*c]T" {
205210}
206211
207212test "*usize to *void" {
213 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208214 var i = @as(usize, 0);
209215 var v = @ptrCast(*void, &i);
210216 v.* = {};
......@@ -230,6 +236,7 @@ test "@intCast to u0 and use the result" {
230236}
231237
232238test "peer result null and comptime_int" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233240 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
234241
235242 const S = struct {
......@@ -253,6 +260,7 @@ test "peer result null and comptime_int" {
253260}
254261
255262test "*const ?[*]const T to [*c]const [*c]const T" {
263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
256264 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
257265
258266 var array = [_]u8{ 'o', 'k' };
......@@ -264,6 +272,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
264272}
265273
266274test "array coersion to undefined at runtime" {
275 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267276 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
268277
269278 @setRuntimeSafety(true);
......@@ -293,6 +302,7 @@ fn implicitIntLitToOptional() void {
293302}
294303
295304test "return u8 coercing into ?u32 return type" {
305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296306 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297307
298308 const S = struct {
......@@ -313,6 +323,7 @@ test "cast from ?[*]T to ??[*]T" {
313323}
314324
315325test "peer type unsigned int to signed" {
326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
316327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
317328 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
318329
......@@ -325,6 +336,7 @@ test "peer type unsigned int to signed" {
325336}
326337
327338test "expected [*c]const u8, found [*:0]const u8" {
339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
328340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
329341 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
330342
......@@ -384,6 +396,7 @@ fn castToOptionalTypeError(z: i32) !void {
384396}
385397
386398test "implicitly cast from [0]T to anyerror![]T" {
399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
387400 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
388401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
389402 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -455,6 +468,7 @@ fn testCastConstArrayRefToConstSlice() !void {
455468}
456469
457470test "peer type resolution: error and [N]T" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
458472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
459473 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
460474
......@@ -689,6 +703,7 @@ test "type coercion related to sentinel-termination" {
689703}
690704
691705test "peer type resolution implicit cast to return type" {
706 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
692707 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
693708 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
694709 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -710,6 +725,7 @@ test "peer type resolution implicit cast to return type" {
710725}
711726
712727test "peer type resolution implicit cast to variable type" {
728 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
713729 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
714730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
715731 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -806,6 +822,7 @@ test "comptime float casts" {
806822}
807823
808824test "pointer reinterpret const float to int" {
825 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
809826 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
810827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
811828 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -822,6 +839,7 @@ test "pointer reinterpret const float to int" {
822839}
823840
824841test "implicit cast from [*]T to ?*anyopaque" {
842 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
825843 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
826844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
827845 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -840,6 +858,7 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void {
840858}
841859
842860test "compile time int to ptr of function" {
861 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
843862 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
844863 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO
845864 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -857,6 +876,7 @@ fn foobar(func: PFN_void) !void {
857876}
858877
859878test "implicit ptr to *anyopaque" {
879 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
860880 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
861881 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
862882 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -871,6 +891,7 @@ test "implicit ptr to *anyopaque" {
871891}
872892
873893test "return null from fn() anyerror!?&T" {
894 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
874895 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
875896 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
876897
......@@ -887,6 +908,7 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
887908}
888909
889910test "peer type resolution: [0]u8 and []const u8" {
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
890912 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
891913 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892914 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -907,6 +929,7 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
907929}
908930
909931test "implicitly cast from [N]T to ?[]const T" {
932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910933 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
911934 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
912935 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -920,6 +943,7 @@ fn castToOptionalSlice() ?[]const u8 {
920943}
921944
922945test "cast u128 to f128 and back" {
946 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
923947 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
924948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
925949 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -941,6 +965,7 @@ fn cast128Float(x: u128) f128 {
941965}
942966
943967test "implicit cast from *[N]T to ?[*]T" {
968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
944969 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
945970 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
946971 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -956,6 +981,7 @@ test "implicit cast from *[N]T to ?[*]T" {
956981}
957982
958983test "implicit cast from *T to ?*anyopaque" {
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
959985 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
960986 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
961987 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -970,6 +996,7 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {
970996}
971997
972998test "implicit cast *[0]T to E![]const u8" {
999 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9731000 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
9741001 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9751002 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -987,6 +1014,7 @@ test "cast from array reference to fn: comptime fn ptr" {
9871014 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
9881015}
9891016test "cast from array reference to fn: runtime fn ptr" {
1017 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9901018 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
9911019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9921020 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -996,6 +1024,7 @@ test "cast from array reference to fn: runtime fn ptr" {
9961024}
9971025
9981026test "*const [N]null u8 to ?[]const u8" {
1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9991028 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10001029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10011030 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1034,6 +1063,7 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" {
10341063
10351064var global_struct: struct { f0: usize } = undefined;
10361065test "assignment to optional pointer result loc" {
1066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10371067 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10381068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10391069 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1043,6 +1073,7 @@ test "assignment to optional pointer result loc" {
10431073}
10441074
10451075test "cast between *[N]void and []void" {
1076 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10461077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10471078 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10481079
......@@ -1052,6 +1083,7 @@ test "cast between *[N]void and []void" {
10521083}
10531084
10541085test "peer resolve arrays of different size to const slice" {
1086 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10551087 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10561088 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10571089
......@@ -1065,6 +1097,7 @@ fn boolToStr(b: bool) []const u8 {
10651097}
10661098
10671099test "cast f16 to wider types" {
1100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10681101 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10691102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10701103 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1083,6 +1116,7 @@ test "cast f16 to wider types" {
10831116}
10841117
10851118test "cast f128 to narrower types" {
1119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10861120 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10871121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10881122 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1101,6 +1135,7 @@ test "cast f128 to narrower types" {
11011135}
11021136
11031137test "peer type resolution: unreachable, null, slice" {
1138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11041139 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11051140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11061141 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1119,6 +1154,7 @@ test "peer type resolution: unreachable, null, slice" {
11191154}
11201155
11211156test "cast i8 fn call peers to i32 result" {
1157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11221158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11231159 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11241160
test/behavior/fn_delegation.zig+1
......@@ -32,6 +32,7 @@ fn custom(comptime T: type, comptime num: u64) fn (T) u64 {
3232}
3333
3434test "fn delegation" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3637
3738 const foo = Foo{};
test/behavior/ir_block_deps.zig+1
......@@ -18,6 +18,7 @@ fn getErrInt() anyerror!i32 {
1818}
1919
2020test "ir block deps" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2223 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2324
test/behavior/optional.zig+10
......@@ -5,6 +5,7 @@ const expect = testing.expect;
55const expectEqual = testing.expectEqual;
66
77test "passing an optional integer as a parameter" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
910 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1011
......@@ -25,6 +26,7 @@ test "passing an optional integer as a parameter" {
2526pub const EmptyStruct = struct {};
2627
2728test "optional pointer to size zero struct" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2830 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2931 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3032
......@@ -34,6 +36,7 @@ test "optional pointer to size zero struct" {
3436}
3537
3638test "equality compare optional pointers" {
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3740 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3841 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3942
......@@ -58,6 +61,7 @@ fn testNullPtrsEql() !void {
5861}
5962
6063test "optional with void type" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6266 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6367
......@@ -69,6 +73,7 @@ test "optional with void type" {
6973}
7074
7175test "address of unwrap optional" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7378 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7479
......@@ -89,6 +94,7 @@ test "address of unwrap optional" {
8994}
9095
9196test "nested optional field in struct" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9399 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
94100
......@@ -105,6 +111,7 @@ test "nested optional field in struct" {
105111}
106112
107113test "equality compare optional with non-optional" {
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
108115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109116 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
110117
......@@ -142,6 +149,7 @@ fn test_cmp_optional_non_optional() !void {
142149}
143150
144151test "unwrap function call with optional pointer return value" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
145153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
146154 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147155
......@@ -163,6 +171,7 @@ test "unwrap function call with optional pointer return value" {
163171}
164172
165173test "nested orelse" {
174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
166175 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
167176 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
168177
......@@ -189,6 +198,7 @@ test "nested orelse" {
189198}
190199
191200test "self-referential struct through a slice of optional" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
192202 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
193203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194204 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/reflection.zig+1
......@@ -28,6 +28,7 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2828}
2929
3030test "reflection: @field" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3233 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3334
test/behavior/slice.zig+14
......@@ -27,6 +27,7 @@ comptime {
2727}
2828
2929test "slicing" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3031 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3132 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3233 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -68,6 +69,7 @@ test "comptime slice of undefined pointer of length 0" {
6869}
6970
7071test "implicitly cast array of size 0 to slice" {
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7173 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7375
......@@ -80,6 +82,7 @@ fn assertLenIsZero(msg: []const u8) !void {
8082}
8183
8284test "access len index of sentinel-terminated slice" {
85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8386 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8487
8588 const S = struct {
......@@ -129,6 +132,7 @@ test "slice of type" {
129132}
130133
131134test "generic malloc free" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
132136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
133137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
134138 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -187,6 +191,7 @@ test "comptime pointer cast array and then slice" {
187191}
188192
189193test "slicing zero length array" {
194 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190195 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
191196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
192197 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -202,6 +207,7 @@ test "slicing zero length array" {
202207const x = @intToPtr([*]i32, 0x1000)[0..0x500];
203208const y = x[0x100..];
204209test "compile time slice of pointer to hard coded address" {
210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
205211 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
206212 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
207213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -215,6 +221,7 @@ test "compile time slice of pointer to hard coded address" {
215221}
216222
217223test "slice string literal has correct type" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
218225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
219226 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
220227
......@@ -230,6 +237,7 @@ test "slice string literal has correct type" {
230237}
231238
232239test "result location zero sized array inside struct field implicit cast to slice" {
240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
234242
235243 const E = struct {
......@@ -240,6 +248,7 @@ test "result location zero sized array inside struct field implicit cast to slic
240248}
241249
242250test "runtime safety lets us slice from len..len" {
251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
243252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
244253 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
245254
......@@ -252,6 +261,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
252261}
253262
254263test "C pointer" {
264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
255265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
256266 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
257267
......@@ -262,6 +272,7 @@ test "C pointer" {
262272}
263273
264274test "C pointer slice access" {
275 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
265276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
266277 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
267278
......@@ -291,6 +302,7 @@ fn sliceSum(comptime q: []const u8) i32 {
291302}
292303
293304test "slice type with custom alignment" {
305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294306 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
295307 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
296308
......@@ -305,6 +317,7 @@ test "slice type with custom alignment" {
305317}
306318
307319test "obtaining a null terminated slice" {
320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
308321 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
309322 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
310323 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -350,6 +363,7 @@ test "empty array to slice" {
350363}
351364
352365test "@ptrCast slice to pointer" {
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
353367 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
354368 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
355369
test/behavior/struct.zig+28
......@@ -9,6 +9,7 @@ const maxInt = std.math.maxInt;
99top_level_field: i32,
1010
1111test "top level fields" {
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1314
1415 var instance = @This(){
......@@ -42,6 +43,7 @@ const StructWithFields = struct {
4243};
4344
4445test "non-packed struct has fields padded out to the required alignment" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4547 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4648
4749 const foo = StructWithFields{ .a = 5, .b = 1, .c = 10, .d = 2 };
......@@ -65,6 +67,7 @@ const SmallStruct = struct {
6567};
6668
6769test "lower unnamed constants" {
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6871 var foo = SmallStruct{ .a = 1, .b = 255 };
6972 try expect(foo.first() == 1);
7073 try expect(foo.second() == 255);
......@@ -83,6 +86,7 @@ const StructFoo = struct {
8386};
8487
8588test "structs" {
89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8690 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8791
8892 var foo: StructFoo = undefined;
......@@ -101,6 +105,7 @@ fn testMutation(foo: *StructFoo) void {
101105}
102106
103107test "struct byval assign" {
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
104109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
105110
106111 var foo1: StructFoo = undefined;
......@@ -134,6 +139,7 @@ fn returnEmptyStructInstance() StructWithNoFields {
134139}
135140
136141test "fn call of struct field" {
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
137143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138144
139145 const Foo = struct {
......@@ -165,12 +171,14 @@ const MemberFnTestFoo = struct {
165171};
166172
167173test "call member function directly" {
174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
168175 const instance = MemberFnTestFoo{ .x = 1234 };
169176 const result = MemberFnTestFoo.member(instance);
170177 try expect(result == 1234);
171178}
172179
173180test "store member function in variable" {
181 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174182 const instance = MemberFnTestFoo{ .x = 1234 };
175183 const memberFn = MemberFnTestFoo.member;
176184 const result = memberFn(instance);
......@@ -178,6 +186,7 @@ test "store member function in variable" {
178186}
179187
180188test "member functions" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
181190 const r = MemberFnRand{ .seed = 1234 };
182191 try expect(r.getSeed() == 1234);
183192}
......@@ -189,6 +198,7 @@ const MemberFnRand = struct {
189198};
190199
191200test "return struct byval from function" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
192202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
193203
194204 const bar = makeBar2(1234, 5678);
......@@ -206,6 +216,7 @@ fn makeBar2(x: i32, y: i32) Bar {
206216}
207217
208218test "call method with mutable reference to struct with no fields" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210221
211222 const S = struct {
......@@ -238,6 +249,7 @@ test "usingnamespace within struct scope" {
238249}
239250
240251test "struct field init with catch" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
241253 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
242254
243255 const S = struct {
......@@ -296,6 +308,7 @@ const Val = struct {
296308};
297309
298310test "struct point to self" {
311 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299312 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
300313 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
301314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -314,6 +327,7 @@ test "struct point to self" {
314327}
315328
316329test "void struct fields" {
330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
317331 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
318332 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
319333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -334,6 +348,7 @@ const VoidStructFieldsFoo = struct {
334348};
335349
336350test "return empty struct from fn" {
351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337352 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
338353 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
339354 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -347,6 +362,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 {
347362}
348363
349364test "pass slice of empty struct to fn" {
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
350366 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
351367 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
352368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -359,6 +375,7 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
359375}
360376
361377test "self-referencing struct via array member" {
378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362379 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
363380 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
364381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -389,6 +406,7 @@ const EmptyStruct = struct {
389406};
390407
391408test "align 1 field before self referential align 8 field as slice return type" {
409 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
392410 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
393411 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
394412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -413,6 +431,7 @@ const APackedStruct = packed struct {
413431};
414432
415433test "packed struct" {
434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
416435 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
417436 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
418437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -438,6 +457,7 @@ const Foo96Bits = packed struct {
438457};
439458
440459test "packed struct 24bits" {
460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441461 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
442462 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
443463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -484,6 +504,7 @@ test "packed struct 24bits" {
484504}
485505
486506test "runtime struct initialization of bitfield" {
507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
487508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
488509 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
489510 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -523,6 +544,7 @@ const Bitfields = packed struct {
523544};
524545
525546test "native bit field understands endianness" {
547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
526548 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
527549 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
528550 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -546,6 +568,7 @@ test "native bit field understands endianness" {
546568}
547569
548570test "implicit cast packed struct field to const ptr" {
571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
549572 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
550573 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
551574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -581,6 +604,7 @@ test "zero-bit field in packed struct" {
581604}
582605
583606test "packed struct with non-ABI-aligned field" {
607 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
584608 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
585609 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
586610 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -610,6 +634,7 @@ const bit_field_1 = BitField1{
610634};
611635
612636test "bit field access" {
637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
613638 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
614639 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
615640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -642,6 +667,7 @@ fn getC(data: *const BitField1) u2 {
642667}
643668
644669test "default struct initialization fields" {
670 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
645671 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
646672 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
647673 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -907,6 +933,7 @@ test "packed struct field passed to generic function" {
907933}
908934
909935test "anonymous struct literal syntax" {
936 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910937 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
911938 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
912939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -1100,6 +1127,7 @@ test "type coercion of pointer to anon struct literal to pointer to struct" {
11001127}
11011128
11021129test "packed struct with undefined initializers" {
1130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11031131 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11041132 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11051133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/truncate.zig+9
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "truncate u0 to larger integer allowed and has comptime known result" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
78
89 var x: u0 = 0;
......@@ -11,6 +12,7 @@ test "truncate u0 to larger integer allowed and has comptime known result" {
1112}
1213
1314test "truncate.u0.literal" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1517
1618 var z = @truncate(u0, 0);
......@@ -18,6 +20,7 @@ test "truncate.u0.literal" {
1820}
1921
2022test "truncate.u0.const" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2225
2326 const c0: usize = 0;
......@@ -26,6 +29,7 @@ test "truncate.u0.const" {
2629}
2730
2831test "truncate.u0.var" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3034
3135 var d: u8 = 2;
......@@ -34,6 +38,7 @@ test "truncate.u0.var" {
3438}
3539
3640test "truncate i0 to larger integer allowed and has comptime known result" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3742 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3843
3944 var x: i0 = 0;
......@@ -42,6 +47,7 @@ test "truncate i0 to larger integer allowed and has comptime known result" {
4247}
4348
4449test "truncate.i0.literal" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4652
4753 var z = @truncate(i0, 0);
......@@ -49,6 +55,7 @@ test "truncate.i0.literal" {
4955}
5056
5157test "truncate.i0.const" {
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5360
5461 const c0: isize = 0;
......@@ -57,6 +64,7 @@ test "truncate.i0.const" {
5764}
5865
5966test "truncate.i0.var" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6169
6270 var d: i8 = 2;
......@@ -65,6 +73,7 @@ test "truncate.i0.var" {
6573}
6674
6775test "truncate on comptime integer" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6877 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6978
7079 var x = @truncate(u16, 9999);
test/behavior/var_args.zig+3
......@@ -25,6 +25,7 @@ fn readFirstVarArg(args: anytype) void {
2525}
2626
2727test "send void arg to var args" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2829 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2930 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
3031 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -84,6 +85,7 @@ fn foo2(args: anytype) bool {
8485}
8586
8687test "array of var args functions" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8789 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8890 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8991 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -93,6 +95,7 @@ test "array of var args functions" {
9395}
9496
9597test "pass zero length array to var args param" {
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9699 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
97100 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
98101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/stage2/aarch64.zig+69-18
......@@ -17,15 +17,8 @@ pub fn addCases(ctx: *TestContext) !void {
1717 var case = ctx.exe("linux_aarch64 hello world", linux_aarch64);
1818 // Regular old hello world
1919 case.addCompareOutput(
20 \\pub export fn _start() noreturn {
20 \\pub fn main() void {
2121 \\ print();
22 \\ exit();
23 \\}
24 \\
25 \\fn doNothing() void {}
26 \\
27 \\fn answer() u64 {
28 \\ return 0x1234abcd1234abcd;
2922 \\}
3023 \\
3124 \\fn print() void {
......@@ -38,16 +31,6 @@ pub fn addCases(ctx: *TestContext) !void {
3831 \\ : "memory", "cc"
3932 \\ );
4033 \\}
41 \\
42 \\fn exit() noreturn {
43 \\ asm volatile ("svc #0"
44 \\ :
45 \\ : [number] "{x8}" (93),
46 \\ [arg1] "{x0}" (0)
47 \\ : "memory", "cc"
48 \\ );
49 \\ unreachable;
50 \\}
5134 ,
5235 "Hello, World!\n",
5336 );
......@@ -102,6 +85,74 @@ pub fn addCases(ctx: *TestContext) !void {
10285 ,
10386 "Hello, World!\n",
10487 );
88
89 case.addCompareOutput(
90 \\pub fn main() void {
91 \\ foo(true);
92 \\}
93 \\
94 \\fn foo(x: bool) void {
95 \\ if (x) {
96 \\ print();
97 \\ }
98 \\}
99 \\
100 \\fn print() void {
101 \\ asm volatile ("svc #0"
102 \\ :
103 \\ : [number] "{x8}" (64),
104 \\ [arg1] "{x0}" (1),
105 \\ [arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
106 \\ [arg3] "{x2}" ("Hello, World!\n".len),
107 \\ : "memory", "cc"
108 \\ );
109 \\}
110 ,
111 "Hello, World!\n",
112 );
113 }
114
115 {
116 var case = ctx.exe("large add function", linux_aarch64);
117
118 case.addCompareOutput(
119 \\pub fn main() void {
120 \\ assert(add(3, 4) == 791);
121 \\}
122 \\
123 \\fn add(a: u32, b: u32) u32 {
124 \\ const x: u32 = blk: {
125 \\ const c = a + b; // 7
126 \\ const d = a + c; // 10
127 \\ const e = d + b; // 14
128 \\ const f = d + e; // 24
129 \\ const g = e + f; // 38
130 \\ const h = f + g; // 62
131 \\ const i = g + h; // 100
132 \\ const j = i + d; // 110
133 \\ const k = i + j; // 210
134 \\ const l = k + c; // 217
135 \\ const m = l + d; // 227
136 \\ const n = m + e; // 241
137 \\ const o = n + f; // 265
138 \\ const p = o + g; // 303
139 \\ const q = p + h; // 365
140 \\ const r = q + i; // 465
141 \\ const s = r + j; // 575
142 \\ const t = s + k; // 785
143 \\ break :blk t;
144 \\ };
145 \\ const y = x + a; // 788
146 \\ const z = y + a; // 791
147 \\ return z;
148 \\}
149 \\
150 \\fn assert(ok: bool) void {
151 \\ if (!ok) unreachable;
152 \\}
153 ,
154 "",
155 );
105156 }
106157
107158 // macOS tests