| author | |
| committer | |
| log | be98f30a2d647075564e02791813ddfb599f6cd7 |
| tree | 7cb73181d19a46ef8c1fbf671ce85a17fe0c9644 |
| parent | dc6553d93eb856a1593d43f0d1ea387c74fa7b44 |
| parent | 6c195db03a502074952181261807cf9a8e140d8d |
| signature |
stage2 AArch64: get zig test working; enable behavior tests33 files changed, 1477 insertions(+), 359 deletions(-)
ci/zinc/linux_test.sh+3-2| ... | ... | @@ -7,8 +7,9 @@ ZIG=$DEBUG_STAGING/bin/zig |
| 7 | 7 | $ZIG test test/behavior.zig -fno-stage1 -I test -fLLVM |
| 8 | 8 | $ZIG test test/behavior.zig -fno-stage1 -I test -fLLVM -target aarch64-linux --test-cmd qemu-aarch64 --test-cmd-bin |
| 9 | 9 | $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 | |
| 12 | 13 | $ZIG test test/behavior.zig -fno-stage1 -I test |
| 13 | 14 | |
| 14 | 15 | $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 { |
| 511 | 511 | |
| 512 | 512 | switch (air_tags[inst]) { |
| 513 | 513 | // zig fmt: off |
| 514 | .add, .ptr_add => try self.airAdd(inst), | |
| 514 | .add, .ptr_add => try self.airBinOp(inst), | |
| 515 | 515 | .addwrap => try self.airAddWrap(inst), |
| 516 | 516 | .add_sat => try self.airAddSat(inst), |
| 517 | .sub, .ptr_sub => try self.airSub(inst), | |
| 517 | .sub, .ptr_sub => try self.airBinOp(inst), | |
| 518 | 518 | .subwrap => try self.airSubWrap(inst), |
| 519 | 519 | .sub_sat => try self.airSubSat(inst), |
| 520 | 520 | .mul => try self.airMul(inst), |
| ... | ... | @@ -894,6 +894,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 894 | 894 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 895 | 895 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 896 | 896 | const operand = try self.resolveInst(ty_op.operand); |
| 897 | const operand_ty = self.air.typeOf(ty_op.operand); | |
| 897 | 898 | switch (operand) { |
| 898 | 899 | .dead => unreachable, |
| 899 | 900 | .unreach => unreachable, |
| ... | ... | @@ -923,12 +924,19 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 923 | 924 | }; |
| 924 | 925 | break :result r; |
| 925 | 926 | }, |
| 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 | }, | |
| 927 | 937 | } |
| 928 | ||
| 929 | return self.fail("TODO implement NOT for {}", .{self.target.cpu.arch}); | |
| 930 | 938 | }; |
| 931 | _ = result; | |
| 939 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | |
| 932 | 940 | } |
| 933 | 941 | |
| 934 | 942 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -950,9 +958,306 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 950 | 958 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 951 | 959 | } |
| 952 | 960 | |
| 953 | fn 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. | |
| 969 | fn 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. | |
| 1079 | fn 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. | |
| 1164 | fn 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 | ||
| 1252 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { | |
| 1253 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 954 | 1254 | 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); | |
| 956 | 1261 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 957 | 1262 | } |
| 958 | 1263 | |
| ... | ... | @@ -968,12 +1273,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 968 | 1273 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 969 | 1274 | } |
| 970 | 1275 | |
| 971 | fn 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 | ||
| 977 | 1276 | fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 978 | 1277 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 979 | 1278 | 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 { |
| 1098 | 1397 | |
| 1099 | 1398 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1100 | 1399 | 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 | }; | |
| 1102 | 1408 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1103 | 1409 | } |
| 1104 | 1410 | |
| 1105 | 1411 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1106 | 1412 | 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 | }; | |
| 1108 | 1420 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1109 | 1421 | } |
| 1110 | 1422 | |
| ... | ... | @@ -1146,7 +1458,14 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1146 | 1458 | /// E to E!T |
| 1147 | 1459 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1148 | 1460 | 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 | }; | |
| 1150 | 1469 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1151 | 1470 | } |
| 1152 | 1471 | |
| ... | ... | @@ -1158,7 +1477,20 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1158 | 1477 | |
| 1159 | 1478 | fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 1160 | 1479 | 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 | }; | |
| 1162 | 1494 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1163 | 1495 | } |
| 1164 | 1496 | |
| ... | ... | @@ -1177,10 +1509,114 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1177 | 1509 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1178 | 1510 | const is_volatile = false; // TODO |
| 1179 | 1511 | 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 | }; | |
| 1181 | 1569 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1182 | 1570 | } |
| 1183 | 1571 | |
| 1572 | fn 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 | ||
| 1184 | 1620 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1185 | 1621 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1186 | 1622 | 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 |
| 1295 | 1731 | .embedded_in_code => { |
| 1296 | 1732 | return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); |
| 1297 | 1733 | }, |
| 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 | } | |
| 1300 | 1802 | }, |
| 1301 | 1803 | .memory, |
| 1302 | 1804 | .stack_offset, |
| ... | ... | @@ -1311,6 +1813,84 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1311 | 1813 | } |
| 1312 | 1814 | } |
| 1313 | 1815 | |
| 1816 | fn 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 | ||
| 1314 | 1894 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1315 | 1895 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1316 | 1896 | const elem_ty = self.air.typeOfIndex(inst); |
| ... | ... | @@ -1337,11 +1917,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1337 | 1917 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1338 | 1918 | } |
| 1339 | 1919 | |
| 1340 | fn 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); | |
| 1920 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | |
| 1345 | 1921 | switch (ptr) { |
| 1346 | 1922 | .none => unreachable, |
| 1347 | 1923 | .undef => unreachable, |
| ... | ... | @@ -1350,13 +1926,13 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1350 | 1926 | .compare_flags_unsigned => unreachable, |
| 1351 | 1927 | .compare_flags_signed => unreachable, |
| 1352 | 1928 | .immediate => |imm| { |
| 1353 | try self.setRegOrMem(elem_ty, .{ .memory = imm }, value); | |
| 1929 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | |
| 1354 | 1930 | }, |
| 1355 | 1931 | .ptr_stack_offset => |off| { |
| 1356 | try self.genSetStack(elem_ty, off, value); | |
| 1932 | try self.genSetStack(value_ty, off, value); | |
| 1357 | 1933 | }, |
| 1358 | 1934 | .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); | |
| 1360 | 1936 | }, |
| 1361 | 1937 | .embedded_in_code => { |
| 1362 | 1938 | return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); |
| ... | ... | @@ -1364,33 +1940,55 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { |
| 1364 | 1940 | .register => { |
| 1365 | 1941 | return self.fail("TODO implement storing to MCValue.register", .{}); |
| 1366 | 1942 | }, |
| 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); | |
| 1372 | 1948 | }, |
| 1373 | 1949 | } |
| 1950 | } | |
| 1951 | ||
| 1952 | fn 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 | ||
| 1374 | 1961 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1375 | 1962 | } |
| 1376 | 1963 | |
| 1377 | 1964 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1378 | 1965 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1379 | 1966 | 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 }); | |
| 1381 | 1969 | } |
| 1382 | 1970 | |
| 1383 | 1971 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 1384 | 1972 | 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 }); | |
| 1386 | 1975 | } |
| 1387 | fn 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 | ||
| 1977 | fn 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 | }; | |
| 1394 | 1992 | } |
| 1395 | 1993 | |
| 1396 | 1994 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1487,49 +2085,55 @@ fn airFence(self: *Self) !void { |
| 1487 | 2085 | |
| 1488 | 2086 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1489 | 2087 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1490 | const fn_ty = self.air.typeOf(pl_op.operand); | |
| 1491 | 2088 | const callee = pl_op.operand; |
| 1492 | 2089 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1493 | 2090 | 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 | }; | |
| 1494 | 2098 | |
| 1495 | 2099 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 1496 | 2100 | defer info.deinit(self); |
| 1497 | 2101 | |
| 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 | }, | |
| 1530 | 2130 | } |
| 2131 | } | |
| 1531 | 2132 | |
| 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) { | |
| 1533 | 2137 | if (func_value.castTag(.function)) |func_payload| { |
| 1534 | 2138 | const func = func_payload.data; |
| 1535 | 2139 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| ... | ... | @@ -1553,45 +2157,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1553 | 2157 | } else { |
| 1554 | 2158 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1555 | 2159 | } |
| 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| { | |
| 1595 | 2161 | if (func_value.castTag(.function)) |func_payload| { |
| 1596 | 2162 | const func = func_payload.data; |
| 1597 | 2163 | // 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 { |
| 1627 | 2193 | } else { |
| 1628 | 2194 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1629 | 2195 | } |
| 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| { | |
| 1665 | 2197 | if (func_value.castTag(.function)) |func_payload| { |
| 1666 | 2198 | try p9.seeDecl(func_payload.data.owner_decl); |
| 1667 | 2199 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| ... | ... | @@ -1681,10 +2213,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1681 | 2213 | } else { |
| 1682 | 2214 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1683 | 2215 | } |
| 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 | } | |
| 1688 | 2227 | |
| 1689 | 2228 | const result: MCValue = result: { |
| 1690 | 2229 | switch (info.return_value) { |
| ... | ... | @@ -1741,12 +2280,23 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1741 | 2280 | |
| 1742 | 2281 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1743 | 2282 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2283 | ||
| 1744 | 2284 | if (self.liveness.isUnused(inst)) |
| 1745 | 2285 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2286 | ||
| 1746 | 2287 | 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 | }; | |
| 1750 | 2300 | |
| 1751 | 2301 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1752 | 2302 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1812,8 +2362,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1812 | 2362 | .immediate => |imm| { |
| 1813 | 2363 | _ = try self.addInst(.{ |
| 1814 | 2364 | .tag = .cmp_immediate, |
| 1815 | .data = .{ .rr_imm12_sh = .{ | |
| 1816 | .rd = .xzr, | |
| 2365 | .data = .{ .r_imm12_sh = .{ | |
| 1817 | 2366 | .rn = lhs_mcv.register, |
| 1818 | 2367 | .imm12 = @intCast(u12, imm), |
| 1819 | 2368 | } }, |
| ... | ... | @@ -1822,9 +2371,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1822 | 2371 | else => unreachable, |
| 1823 | 2372 | } |
| 1824 | 2373 | |
| 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 }, | |
| 1828 | 2377 | }; |
| 1829 | 2378 | }; |
| 1830 | 2379 | 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 { |
| 1876 | 2425 | }, |
| 1877 | 2426 | }, |
| 1878 | 2427 | }), |
| 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 | }, | |
| 1880 | 2444 | }; |
| 1881 | 2445 | |
| 1882 | 2446 | // 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 { |
| 2008 | 2572 | return self.fail("TODO call isNull and invert the result", .{}); |
| 2009 | 2573 | } |
| 2010 | 2574 | |
| 2011 | fn isErr(self: *Self, operand: MCValue) !MCValue { | |
| 2575 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | |
| 2012 | 2576 | _ = 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 | } | |
| 2016 | 2605 | } |
| 2017 | 2606 | |
| 2018 | fn 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", .{}); | |
| 2607 | fn 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 | } | |
| 2023 | 2620 | } |
| 2024 | 2621 | |
| 2025 | 2622 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2080,7 +2677,8 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2080 | 2677 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2081 | 2678 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2082 | 2679 | 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); | |
| 2084 | 2682 | }; |
| 2085 | 2683 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2086 | 2684 | } |
| ... | ... | @@ -2089,6 +2687,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2089 | 2687 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2090 | 2688 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2091 | 2689 | const operand_ptr = try self.resolveInst(un_op); |
| 2690 | const ptr_ty = self.air.typeOf(un_op); | |
| 2092 | 2691 | const operand: MCValue = blk: { |
| 2093 | 2692 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2094 | 2693 | // 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 { |
| 2098 | 2697 | } |
| 2099 | 2698 | }; |
| 2100 | 2699 | 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); | |
| 2102 | 2701 | }; |
| 2103 | 2702 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2104 | 2703 | } |
| ... | ... | @@ -2107,7 +2706,8 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2107 | 2706 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2108 | 2707 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2109 | 2708 | 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); | |
| 2111 | 2711 | }; |
| 2112 | 2712 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2113 | 2713 | } |
| ... | ... | @@ -2116,6 +2716,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2116 | 2716 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2117 | 2717 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2118 | 2718 | const operand_ptr = try self.resolveInst(un_op); |
| 2719 | const ptr_ty = self.air.typeOf(un_op); | |
| 2119 | 2720 | const operand: MCValue = blk: { |
| 2120 | 2721 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 2121 | 2722 | // 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 { |
| 2125 | 2726 | } |
| 2126 | 2727 | }; |
| 2127 | 2728 | 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); | |
| 2129 | 2730 | }; |
| 2130 | 2731 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2131 | 2732 | } |
| ... | ... | @@ -2184,8 +2785,9 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 2184 | 2785 | fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 2185 | 2786 | const tag = self.mir_instructions.items(.tag)[inst]; |
| 2186 | 2787 | 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), | |
| 2189 | 2791 | else => unreachable, |
| 2190 | 2792 | } |
| 2191 | 2793 | } |
| ... | ... | @@ -2212,7 +2814,16 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 2212 | 2814 | const operand_mcv = try self.resolveInst(operand); |
| 2213 | 2815 | const block_mcv = block_data.mcv; |
| 2214 | 2816 | 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 | }; | |
| 2216 | 2827 | } else { |
| 2217 | 2828 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); |
| 2218 | 2829 | } |
| ... | ... | @@ -2412,8 +3023,61 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 2412 | 3023 | if (stack_offset == off) |
| 2413 | 3024 | return; // Copy stack variable to itself; nothing to do. |
| 2414 | 3025 | |
| 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 | } | |
| 2417 | 3081 | }, |
| 2418 | 3082 | } |
| 2419 | 3083 | } |
| ... | ... | @@ -2445,11 +3109,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2445 | 3109 | |
| 2446 | 3110 | _ = try self.addInst(.{ |
| 2447 | 3111 | .tag = .cset, |
| 2448 | .data = .{ .rrr_cond = .{ | |
| 3112 | .data = .{ .r_cond = .{ | |
| 2449 | 3113 | .rd = reg, |
| 2450 | .rn = .xzr, | |
| 2451 | .rm = .xzr, | |
| 2452 | .cond = condition, | |
| 3114 | .cond = condition.negate(), | |
| 2453 | 3115 | } }, |
| 2454 | 3116 | }); |
| 2455 | 3117 | }, |
| ... | ... | @@ -2533,7 +3195,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2533 | 3195 | } }, |
| 2534 | 3196 | }); |
| 2535 | 3197 | }, |
| 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, | |
| 2537 | 3200 | } |
| 2538 | 3201 | }, |
| 2539 | 3202 | else => return self.fail("TODO implement genSetReg for aarch64 {}", .{mcv}), |
| ... | ... | @@ -2713,27 +3376,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 2713 | 3376 | } |
| 2714 | 3377 | } |
| 2715 | 3378 | |
| 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. | |
| 2721 | fn 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 | ||
| 2737 | 3379 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue { |
| 2738 | 3380 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 2739 | 3381 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| ... | ... | @@ -2847,31 +3489,32 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2847 | 3489 | } |
| 2848 | 3490 | }, |
| 2849 | 3491 | .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 }; | |
| 2863 | 3497 | }, |
| 2864 | 3498 | .ErrorUnion => { |
| 2865 | 3499 | const error_type = typed_value.ty.errorUnionSet(); |
| 2866 | 3500 | const payload_type = typed_value.ty.errorUnionPayload(); |
| 2867 | const sub_val = typed_value.val.castTag(.eu_payload).?.data; | |
| 2868 | 3501 | |
| 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 | } | |
| 2873 | 3507 | |
| 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 | } | |
| 2875 | 3518 | }, |
| 2876 | 3519 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), |
| 2877 | 3520 | } |
| ... | ... | @@ -3015,13 +3658,18 @@ fn parseRegName(name: []const u8) ?Register { |
| 3015 | 3658 | } |
| 3016 | 3659 | |
| 3017 | 3660 | fn 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 | } | |
| 3021 | 3670 | } |
| 3022 | 3671 | |
| 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. | |
| 3025 | 3673 | fn toCanonicalReg(reg: Register) Register { |
| 3026 | return reg; | |
| 3674 | return reg.to64(); | |
| 3027 | 3675 | } |
src/arch/aarch64/Emit.zig+131-56| ... | ... | @@ -50,11 +50,13 @@ const InnerError = error{ |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | 52 | const BranchType = enum { |
| 53 | cbz, | |
| 53 | 54 | b_cond, |
| 54 | 55 | unconditional_branch_immediate, |
| 55 | 56 | |
| 56 | 57 | fn default(tag: Mir.Inst.Tag) BranchType { |
| 57 | 58 | return switch (tag) { |
| 59 | .cbz => .cbz, | |
| 58 | 60 | .b, .bl => .unconditional_branch_immediate, |
| 59 | 61 | .b_cond => .b_cond, |
| 60 | 62 | else => unreachable, |
| ... | ... | @@ -83,6 +85,8 @@ pub fn emitMir( |
| 83 | 85 | .b => try emit.mirBranch(inst), |
| 84 | 86 | .bl => try emit.mirBranch(inst), |
| 85 | 87 | |
| 88 | .cbz => try emit.mirCompareAndBranch(inst), | |
| 89 | ||
| 86 | 90 | .blr => try emit.mirUnconditionalBranchRegister(inst), |
| 87 | 91 | .ret => try emit.mirUnconditionalBranchRegister(inst), |
| 88 | 92 | |
| ... | ... | @@ -91,7 +95,9 @@ pub fn emitMir( |
| 91 | 95 | |
| 92 | 96 | .call_extern => try emit.mirCallExtern(inst), |
| 93 | 97 | |
| 98 | .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), | |
| 94 | 99 | .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), |
| 100 | .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst), | |
| 95 | 101 | |
| 96 | 102 | .cset => try emit.mirConditionalSelect(inst), |
| 97 | 103 | |
| ... | ... | @@ -100,6 +106,8 @@ pub fn emitMir( |
| 100 | 106 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| 101 | 107 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), |
| 102 | 108 | |
| 109 | .eor_shifted_register => try emit.mirLogicalShiftedRegister(inst), | |
| 110 | ||
| 103 | 111 | .load_memory => try emit.mirLoadMemory(inst), |
| 104 | 112 | |
| 105 | 113 | .ldp => try emit.mirLoadStoreRegisterPair(inst), |
| ... | ... | @@ -128,10 +136,13 @@ pub fn emitMir( |
| 128 | 136 | |
| 129 | 137 | .mov_register => try emit.mirMoveRegister(inst), |
| 130 | 138 | .mov_to_from_sp => try emit.mirMoveRegister(inst), |
| 139 | .mvn => try emit.mirMoveRegister(inst), | |
| 131 | 140 | |
| 132 | 141 | .movk => try emit.mirMoveWideImmediate(inst), |
| 133 | 142 | .movz => try emit.mirMoveWideImmediate(inst), |
| 134 | 143 | |
| 144 | .mul => try emit.mirDataProcessing3Source(inst), | |
| 145 | ||
| 135 | 146 | .nop => try emit.mirNop(), |
| 136 | 147 | |
| 137 | 148 | .push_regs => try emit.mirPushPopRegs(inst), |
| ... | ... | @@ -156,15 +167,22 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 156 | 167 | assert(offset & 0b11 == 0); |
| 157 | 168 | |
| 158 | 169 | 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 | }, | |
| 159 | 177 | .b, .bl => { |
| 160 | if (std.math.cast(i26, offset >> 2)) |_| { | |
| 178 | if (std.math.cast(i26, @shrExact(offset, 2))) |_| { | |
| 161 | 179 | return BranchType.unconditional_branch_immediate; |
| 162 | 180 | } else |_| { |
| 163 | return emit.fail("TODO support branches larger than +-128 MiB", .{}); | |
| 181 | return emit.fail("TODO support unconditional branches larger than +-128 MiB", .{}); | |
| 164 | 182 | } |
| 165 | 183 | }, |
| 166 | 184 | .b_cond => { |
| 167 | if (std.math.cast(i19, offset >> 2)) |_| { | |
| 185 | if (std.math.cast(i19, @shrExact(offset, 2))) |_| { | |
| 168 | 186 | return BranchType.b_cond; |
| 169 | 187 | } else |_| { |
| 170 | 188 | return emit.fail("TODO support conditional branches larger than +-1 MiB", .{}); |
| ... | ... | @@ -179,8 +197,10 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 179 | 197 | |
| 180 | 198 | if (isBranch(tag)) { |
| 181 | 199 | 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, | |
| 184 | 204 | } |
| 185 | 205 | } |
| 186 | 206 | |
| ... | ... | @@ -201,6 +221,12 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 201 | 221 | return 5 * 4; |
| 202 | 222 | } |
| 203 | 223 | }, |
| 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 | }, | |
| 204 | 230 | .call_extern => return 4, |
| 205 | 231 | .dbg_line, |
| 206 | 232 | .dbg_epilogue_begin, |
| ... | ... | @@ -212,7 +238,11 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { |
| 212 | 238 | |
| 213 | 239 | fn isBranch(tag: Mir.Inst.Tag) bool { |
| 214 | 240 | return switch (tag) { |
| 215 | .b, .bl, .b_cond => true, | |
| 241 | .cbz, | |
| 242 | .b, | |
| 243 | .bl, | |
| 244 | .b_cond, | |
| 245 | => true, | |
| 216 | 246 | else => false, |
| 217 | 247 | }; |
| 218 | 248 | } |
| ... | ... | @@ -221,6 +251,7 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 221 | 251 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 222 | 252 | |
| 223 | 253 | switch (tag) { |
| 254 | .cbz => return emit.mir.instructions.items(.data)[inst].r_inst.inst, | |
| 224 | 255 | .b, .bl => return emit.mir.instructions.items(.data)[inst].inst, |
| 225 | 256 | .b_cond => return emit.mir.instructions.items(.data)[inst].inst_cond.inst, |
| 226 | 257 | else => unreachable, |
| ... | ... | @@ -414,27 +445,30 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 414 | 445 | |
| 415 | 446 | fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 416 | 447 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 417 | const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh; | |
| 418 | ||
| 419 | 448 | 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 | }, | |
| 438 | 472 | else => unreachable, |
| 439 | 473 | } |
| 440 | 474 | } |
| ... | ... | @@ -481,6 +515,23 @@ fn mirBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 481 | 515 | } |
| 482 | 516 | } |
| 483 | 517 | |
| 518 | fn 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 | ||
| 484 | 535 | fn mirUnconditionalBranchRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 485 | 536 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 486 | 537 | const reg = emit.mir.instructions.items(.data)[inst].reg; |
| ... | ... | @@ -565,30 +616,42 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 565 | 616 | fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 566 | 617 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 567 | 618 | 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; | |
| 568 | 624 | |
| 569 | 625 | 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)), | |
| 577 | 629 | else => unreachable, |
| 578 | 630 | } |
| 579 | 631 | } |
| 580 | 632 | |
| 581 | 633 | fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 582 | 634 | 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 | ||
| 644 | fn 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; | |
| 584 | 652 | |
| 585 | 653 | 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)), | |
| 592 | 655 | else => unreachable, |
| 593 | 656 | } |
| 594 | 657 | } |
| ... | ... | @@ -653,20 +716,14 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 653 | 716 | fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 654 | 717 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 655 | 718 | 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; | |
| 656 | 723 | |
| 657 | 724 | 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)), | |
| 670 | 727 | else => unreachable, |
| 671 | 728 | } |
| 672 | 729 | } |
| ... | ... | @@ -782,11 +839,19 @@ fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 782 | 839 | |
| 783 | 840 | fn mirMoveRegister(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 784 | 841 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 785 | const rr = emit.mir.instructions.items(.data)[inst].rr; | |
| 786 | ||
| 787 | 842 | 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 | }, | |
| 790 | 855 | else => unreachable, |
| 791 | 856 | } |
| 792 | 857 | } |
| ... | ... | @@ -802,6 +867,16 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 802 | 867 | } |
| 803 | 868 | } |
| 804 | 869 | |
| 870 | fn 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 | ||
| 805 | 880 | fn mirNop(emit: *Emit) !void { |
| 806 | 881 | try emit.writeInstruction(Instruction.nop()); |
| 807 | 882 | } |
src/arch/aarch64/Mir.zig+59-6| ... | ... | @@ -26,6 +26,8 @@ pub const Inst = struct { |
| 26 | 26 | pub const Tag = enum(u16) { |
| 27 | 27 | /// Add (immediate) |
| 28 | 28 | add_immediate, |
| 29 | /// Add (shifted register) | |
| 30 | add_shifted_register, | |
| 29 | 31 | /// Branch conditionally |
| 30 | 32 | b_cond, |
| 31 | 33 | /// Branch |
| ... | ... | @@ -38,6 +40,8 @@ pub const Inst = struct { |
| 38 | 40 | brk, |
| 39 | 41 | /// Pseudo-instruction: Call extern |
| 40 | 42 | call_extern, |
| 43 | /// Compare and Branch on Zero | |
| 44 | cbz, | |
| 41 | 45 | /// Compare (immediate) |
| 42 | 46 | cmp_immediate, |
| 43 | 47 | /// Compare (shifted register) |
| ... | ... | @@ -50,6 +54,8 @@ pub const Inst = struct { |
| 50 | 54 | dbg_epilogue_begin, |
| 51 | 55 | /// Pseudo-instruction: Update debug line |
| 52 | 56 | dbg_line, |
| 57 | /// Bitwise Exclusive OR (shifted register) | |
| 58 | eor_shifted_register, | |
| 53 | 59 | /// Pseudo-instruction: Load memory |
| 54 | 60 | /// |
| 55 | 61 | /// Payload is `LoadMemory` |
| ... | ... | @@ -82,6 +88,10 @@ pub const Inst = struct { |
| 82 | 88 | movk, |
| 83 | 89 | /// Move wide with zero |
| 84 | 90 | movz, |
| 91 | /// Multiply | |
| 92 | mul, | |
| 93 | /// Bitwise NOT | |
| 94 | mvn, | |
| 85 | 95 | /// No Operation |
| 86 | 96 | nop, |
| 87 | 97 | /// Pseudo-instruction: Pop multiple registers |
| ... | ... | @@ -112,6 +122,8 @@ pub const Inst = struct { |
| 112 | 122 | strh_register, |
| 113 | 123 | /// Subtract (immediate) |
| 114 | 124 | sub_immediate, |
| 125 | /// Subtract (shifted register) | |
| 126 | sub_shifted_register, | |
| 115 | 127 | /// Supervisor Call |
| 116 | 128 | svc, |
| 117 | 129 | }; |
| ... | ... | @@ -171,6 +183,20 @@ pub const Inst = struct { |
| 171 | 183 | imm16: u16, |
| 172 | 184 | hw: u2 = 0, |
| 173 | 185 | }, |
| 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 | }, | |
| 174 | 200 | /// Two registers |
| 175 | 201 | /// |
| 176 | 202 | /// Used by e.g. mov_register |
| ... | ... | @@ -178,6 +204,14 @@ pub const Inst = struct { |
| 178 | 204 | rd: Register, |
| 179 | 205 | rn: Register, |
| 180 | 206 | }, |
| 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 | }, | |
| 181 | 215 | /// Two registers, an unsigned 12-bit immediate, and an optional shift |
| 182 | 216 | /// |
| 183 | 217 | /// Used by e.g. sub_immediate |
| ... | ... | @@ -187,6 +221,23 @@ pub const Inst = struct { |
| 187 | 221 | imm12: u12, |
| 188 | 222 | sh: u1 = 0, |
| 189 | 223 | }, |
| 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 | }, | |
| 190 | 241 | /// Three registers and a shift (shift type and 6-bit amount) |
| 191 | 242 | /// |
| 192 | 243 | /// Used by e.g. cmp_shifted_register |
| ... | ... | @@ -197,18 +248,20 @@ pub const Inst = struct { |
| 197 | 248 | imm6: u6, |
| 198 | 249 | shift: bits.Instruction.AddSubtractShiftedRegisterShift, |
| 199 | 250 | }, |
| 200 | /// Three registers and a condition | |
| 251 | /// Three registers and a shift (logical instruction version) | |
| 252 | /// (shift type and 6-bit amount) | |
| 201 | 253 | /// |
| 202 | /// Used by e.g. cset | |
| 203 | rrr_cond: struct { | |
| 254 | /// Used by e.g. eor_shifted_register | |
| 255 | rrr_imm6_logical_shift: struct { | |
| 204 | 256 | rd: Register, |
| 205 | 257 | rn: Register, |
| 206 | 258 | rm: Register, |
| 207 | cond: bits.Instruction.Condition, | |
| 259 | imm6: u6, | |
| 260 | shift: bits.Instruction.LogicalShiftedRegisterShift, | |
| 208 | 261 | }, |
| 209 | 262 | /// Two registers and a LoadStoreOffsetImmediate |
| 210 | 263 | /// |
| 211 | /// Used by e.g. str_register | |
| 264 | /// Used by e.g. str_immediate | |
| 212 | 265 | load_store_register_immediate: struct { |
| 213 | 266 | rt: Register, |
| 214 | 267 | rn: Register, |
| ... | ... | @@ -224,7 +277,7 @@ pub const Inst = struct { |
| 224 | 277 | }, |
| 225 | 278 | /// A registers and a stack offset |
| 226 | 279 | /// |
| 227 | /// Used by e.g. str_register | |
| 280 | /// Used by e.g. str_stack | |
| 228 | 281 | load_store_stack: struct { |
| 229 | 282 | rt: Register, |
| 230 | 283 | offset: u32, |
src/arch/aarch64/bits.zig+138-43| ... | ... | @@ -332,23 +332,17 @@ pub const Instruction = union(enum) { |
| 332 | 332 | op: u1, |
| 333 | 333 | sf: u1, |
| 334 | 334 | }, |
| 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 | }, | |
| 352 | 346 | |
| 353 | 347 | pub const Condition = enum(u4) { |
| 354 | 348 | /// Integer: Equal |
| ... | ... | @@ -470,6 +464,7 @@ pub const Instruction = union(enum) { |
| 470 | 464 | .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), |
| 471 | 465 | .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), |
| 472 | 466 | .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), | |
| 473 | 468 | }; |
| 474 | 469 | } |
| 475 | 470 | |
| ... | ... | @@ -807,25 +802,28 @@ pub const Instruction = union(enum) { |
| 807 | 802 | }; |
| 808 | 803 | } |
| 809 | 804 | |
| 805 | pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror }; | |
| 806 | ||
| 810 | 807 | fn logicalShiftedRegister( |
| 811 | 808 | opc: u2, |
| 812 | 809 | n: u1, |
| 813 | shift: Shift, | |
| 814 | 810 | rd: Register, |
| 815 | 811 | rn: Register, |
| 816 | 812 | rm: Register, |
| 813 | shift: LogicalShiftedRegisterShift, | |
| 814 | amount: u6, | |
| 817 | 815 | ) Instruction { |
| 818 | 816 | switch (rd.size()) { |
| 819 | 817 | 32 => { |
| 820 | assert(shift.amount < 32); | |
| 818 | assert(amount < 32); | |
| 821 | 819 | return Instruction{ |
| 822 | 820 | .logical_shifted_register = .{ |
| 823 | 821 | .rd = rd.id(), |
| 824 | 822 | .rn = rn.id(), |
| 825 | .imm6 = shift.amount, | |
| 823 | .imm6 = amount, | |
| 826 | 824 | .rm = rm.id(), |
| 827 | 825 | .n = n, |
| 828 | .shift = @enumToInt(shift.shift), | |
| 826 | .shift = @enumToInt(shift), | |
| 829 | 827 | .opc = opc, |
| 830 | 828 | .sf = 0b0, |
| 831 | 829 | }, |
| ... | ... | @@ -836,10 +834,10 @@ pub const Instruction = union(enum) { |
| 836 | 834 | .logical_shifted_register = .{ |
| 837 | 835 | .rd = rd.id(), |
| 838 | 836 | .rn = rn.id(), |
| 839 | .imm6 = shift.amount, | |
| 837 | .imm6 = amount, | |
| 840 | 838 | .rm = rm.id(), |
| 841 | 839 | .n = n, |
| 842 | .shift = @enumToInt(shift.shift), | |
| 840 | .shift = @enumToInt(shift), | |
| 843 | 841 | .opc = opc, |
| 844 | 842 | .sf = 0b1, |
| 845 | 843 | }, |
| ... | ... | @@ -967,6 +965,33 @@ pub const Instruction = union(enum) { |
| 967 | 965 | }; |
| 968 | 966 | } |
| 969 | 967 | |
| 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 | ||
| 970 | 995 | // Helper functions for assembly syntax functions |
| 971 | 996 | |
| 972 | 997 | // Move wide (immediate) |
| ... | ... | @@ -1120,36 +1145,84 @@ pub const Instruction = union(enum) { |
| 1120 | 1145 | |
| 1121 | 1146 | // Logical (shifted register) |
| 1122 | 1147 | |
| 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); | |
| 1125 | 1156 | } |
| 1126 | 1157 | |
| 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); | |
| 1129 | 1166 | } |
| 1130 | 1167 | |
| 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); | |
| 1133 | 1176 | } |
| 1134 | 1177 | |
| 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); | |
| 1137 | 1186 | } |
| 1138 | 1187 | |
| 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); | |
| 1141 | 1196 | } |
| 1142 | 1197 | |
| 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); | |
| 1145 | 1206 | } |
| 1146 | 1207 | |
| 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); | |
| 1149 | 1216 | } |
| 1150 | 1217 | |
| 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); | |
| 1153 | 1226 | } |
| 1154 | 1227 | |
| 1155 | 1228 | // Add/subtract (immediate) |
| ... | ... | @@ -1245,6 +1318,24 @@ pub const Instruction = union(enum) { |
| 1245 | 1318 | pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { |
| 1246 | 1319 | return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond); |
| 1247 | 1320 | } |
| 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 | } | |
| 1248 | 1339 | }; |
| 1249 | 1340 | |
| 1250 | 1341 | test { |
| ... | ... | @@ -1259,11 +1350,11 @@ test "serialize instructions" { |
| 1259 | 1350 | |
| 1260 | 1351 | const testcases = [_]Testcase{ |
| 1261 | 1352 | .{ // orr x0, xzr, x1 |
| 1262 | .inst = Instruction.orr(.x0, .xzr, .x1, Instruction.Shift.none), | |
| 1353 | .inst = Instruction.orr(.x0, .xzr, .x1, .lsl, 0), | |
| 1263 | 1354 | .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, |
| 1264 | 1355 | }, |
| 1265 | 1356 | .{ // orn x0, xzr, x1 |
| 1266 | .inst = Instruction.orn(.x0, .xzr, .x1, Instruction.Shift.none), | |
| 1357 | .inst = Instruction.orn(.x0, .xzr, .x1, .lsl, 0), | |
| 1267 | 1358 | .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, |
| 1268 | 1359 | }, |
| 1269 | 1360 | .{ // movz x1, #4 |
| ... | ... | @@ -1383,11 +1474,11 @@ test "serialize instructions" { |
| 1383 | 1474 | .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, |
| 1384 | 1475 | }, |
| 1385 | 1476 | .{ // and x0, x4, x2 |
| 1386 | .inst = Instruction.@"and"(.x0, .x4, .x2, .{}), | |
| 1477 | .inst = Instruction.@"and"(.x0, .x4, .x2, .lsl, 0), | |
| 1387 | 1478 | .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, |
| 1388 | 1479 | }, |
| 1389 | 1480 | .{ // 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), | |
| 1391 | 1482 | .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, |
| 1392 | 1483 | }, |
| 1393 | 1484 | .{ // add x0, x10, #10 |
| ... | ... | @@ -1414,6 +1505,10 @@ test "serialize instructions" { |
| 1414 | 1505 | .inst = Instruction.csinc(.x1, .x2, .x4, .eq), |
| 1415 | 1506 | .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001, |
| 1416 | 1507 | }, |
| 1508 | .{ // mul x1, x4, x9 | |
| 1509 | .inst = Instruction.mul(.x1, .x4, .x9), | |
| 1510 | .expected = 0b1_00_11011_000_01001_0_11111_00100_00001, | |
| 1511 | }, | |
| 1417 | 1512 | }; |
| 1418 | 1513 | |
| 1419 | 1514 | for (testcases) |case| { |
test/behavior.zig+1-1| ... | ... | @@ -54,7 +54,7 @@ test { |
| 54 | 54 | _ = @import("behavior/decltest.zig"); |
| 55 | 55 | } |
| 56 | 56 | |
| 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) { | |
| 58 | 58 | // Tests that pass (partly) for stage1, llvm backend, C backend, wasm backend. |
| 59 | 59 | _ = @import("behavior/bitcast.zig"); |
| 60 | 60 | _ = @import("behavior/bugs/624.zig"); |
test/behavior/align.zig+18| ... | ... | @@ -27,6 +27,7 @@ test "default alignment allows unspecified in type syntax" { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | test "implicitly decreasing pointer alignment" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 31 | const a: u32 align(4) = 3; |
| 31 | 32 | const b: u32 align(8) = 4; |
| 32 | 33 | try expect(addUnaligned(&a, &b) == 7); |
| ... | ... | @@ -37,6 +38,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { |
| 37 | 38 | } |
| 38 | 39 | |
| 39 | 40 | test "@alignCast pointers" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 40 | 42 | var x: u32 align(4) = 1; |
| 41 | 43 | expectsOnly1(&x); |
| 42 | 44 | try expect(x == 2); |
| ... | ... | @@ -102,6 +104,7 @@ fn fnWithAlignedStack() i32 { |
| 102 | 104 | } |
| 103 | 105 | |
| 104 | 106 | test "implicitly decreasing slice alignment" { |
| 107 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 105 | 108 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 106 | 109 | |
| 107 | 110 | const a: u32 align(4) = 3; |
| ... | ... | @@ -113,6 +116,7 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { |
| 113 | 116 | } |
| 114 | 117 | |
| 115 | 118 | test "specifying alignment allows pointer cast" { |
| 119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 116 | 120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 117 | 121 | |
| 118 | 122 | try testBytesAlign(0x33); |
| ... | ... | @@ -124,6 +128,7 @@ fn testBytesAlign(b: u8) !void { |
| 124 | 128 | } |
| 125 | 129 | |
| 126 | 130 | test "@alignCast slices" { |
| 131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 127 | 132 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 128 | 133 | |
| 129 | 134 | var array align(4) = [_]u32{ 1, 1 }; |
| ... | ... | @@ -139,6 +144,7 @@ fn sliceExpects4(slice: []align(4) u32) void { |
| 139 | 144 | } |
| 140 | 145 | |
| 141 | 146 | test "return error union with 128-bit integer" { |
| 147 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 142 | 148 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 143 | 149 | |
| 144 | 150 | try expect(3 == try give()); |
| ... | ... | @@ -148,6 +154,7 @@ fn give() anyerror!u128 { |
| 148 | 154 | } |
| 149 | 155 | |
| 150 | 156 | test "page aligned array on stack" { |
| 157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 151 | 158 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 152 | 159 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 153 | 160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| ... | ... | @@ -173,6 +180,7 @@ fn noop1() align(1) void {} |
| 173 | 180 | fn noop4() align(4) void {} |
| 174 | 181 | |
| 175 | 182 | test "function alignment" { |
| 183 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 176 | 184 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 177 | 185 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 178 | 186 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| ... | ... | @@ -189,6 +197,7 @@ test "function alignment" { |
| 189 | 197 | } |
| 190 | 198 | |
| 191 | 199 | test "implicitly decreasing fn alignment" { |
| 200 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 192 | 201 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 193 | 202 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 194 | 203 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| ... | ... | @@ -216,6 +225,7 @@ fn alignedBig() align(16) i32 { |
| 216 | 225 | } |
| 217 | 226 | |
| 218 | 227 | test "@alignCast functions" { |
| 228 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 219 | 229 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 220 | 230 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 221 | 231 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -239,6 +249,7 @@ fn simple4() align(4) i32 { |
| 239 | 249 | } |
| 240 | 250 | |
| 241 | 251 | test "generic function with align param" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 242 | 253 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 243 | 254 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 244 | 255 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -260,6 +271,7 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { |
| 260 | 271 | } |
| 261 | 272 | |
| 262 | 273 | test "runtime known array index has best alignment possible" { |
| 274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 263 | 275 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 264 | 276 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 265 | 277 | 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 { |
| 302 | 314 | } |
| 303 | 315 | |
| 304 | 316 | test "alignment of function with c calling convention" { |
| 317 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 305 | 318 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 306 | 319 | |
| 307 | 320 | var runtime_nothing = &nothing; |
| ... | ... | @@ -318,6 +331,7 @@ const DefaultAligned = struct { |
| 318 | 331 | }; |
| 319 | 332 | |
| 320 | 333 | test "read 128-bit field from default aligned struct in stack memory" { |
| 334 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 321 | 335 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 322 | 336 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 323 | 337 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| ... | ... | @@ -337,6 +351,7 @@ var default_aligned_global = DefaultAligned{ |
| 337 | 351 | }; |
| 338 | 352 | |
| 339 | 353 | test "read 128-bit field from default aligned struct in global memory" { |
| 354 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 340 | 355 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 341 | 356 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 342 | 357 | 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" { |
| 348 | 363 | } |
| 349 | 364 | |
| 350 | 365 | test "struct field explicit alignment" { |
| 366 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 351 | 367 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 352 | 368 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 353 | 369 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| ... | ... | @@ -369,6 +385,7 @@ test "struct field explicit alignment" { |
| 369 | 385 | } |
| 370 | 386 | |
| 371 | 387 | test "align(@alignOf(T)) T does not force resolution of T" { |
| 388 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 372 | 389 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 373 | 390 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 374 | 391 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| ... | ... | @@ -397,6 +414,7 @@ test "align(@alignOf(T)) T does not force resolution of T" { |
| 397 | 414 | } |
| 398 | 415 | |
| 399 | 416 | test "align(N) on functions" { |
| 417 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 400 | 418 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 401 | 419 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 402 | 420 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
test/behavior/alignof.zig+1| ... | ... | @@ -11,6 +11,7 @@ const Foo = struct { |
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | 13 | test "@alignOf(T) before referencing T" { |
| 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 14 | 15 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 15 | 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 16 | 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
test/behavior/array.zig+27| ... | ... | @@ -6,6 +6,7 @@ const expect = testing.expect; |
| 6 | 6 | const expectEqual = testing.expectEqual; |
| 7 | 7 | |
| 8 | 8 | test "array to slice" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 10 | 11 | |
| 11 | 12 | const a: u32 align(4) = 3; |
| ... | ... | @@ -20,6 +21,7 @@ test "array to slice" { |
| 20 | 21 | } |
| 21 | 22 | |
| 22 | 23 | test "arrays" { |
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 23 | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 24 | 26 | |
| 25 | 27 | var array: [5]u32 = undefined; |
| ... | ... | @@ -46,6 +48,7 @@ fn getArrayLen(a: []const u32) usize { |
| 46 | 48 | } |
| 47 | 49 | |
| 48 | 50 | test "array init with mult" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 49 | 52 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 50 | 53 | |
| 51 | 54 | const a = 'a'; |
| ... | ... | @@ -57,6 +60,7 @@ test "array init with mult" { |
| 57 | 60 | } |
| 58 | 61 | |
| 59 | 62 | test "array literal with explicit type" { |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 60 | 64 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 61 | 65 | |
| 62 | 66 | const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; |
| ... | ... | @@ -86,6 +90,7 @@ const ArrayDotLenConstExpr = struct { |
| 86 | 90 | const some_array = [_]u8{ 0, 1, 2, 3 }; |
| 87 | 91 | |
| 88 | 92 | test "array literal with specified size" { |
| 93 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 89 | 94 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 90 | 95 | |
| 91 | 96 | var array = [2]u8{ 1, 2 }; |
| ... | ... | @@ -94,6 +99,7 @@ test "array literal with specified size" { |
| 94 | 99 | } |
| 95 | 100 | |
| 96 | 101 | test "array len field" { |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 97 | 103 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 98 | 104 | |
| 99 | 105 | var arr = [4]u8{ 0, 0, 0, 0 }; |
| ... | ... | @@ -105,6 +111,7 @@ test "array len field" { |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | 113 | test "array with sentinels" { |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 108 | 115 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 109 | 116 | |
| 110 | 117 | const S = struct { |
| ... | ... | @@ -134,6 +141,7 @@ test "array with sentinels" { |
| 134 | 141 | } |
| 135 | 142 | |
| 136 | 143 | test "void arrays" { |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 137 | 145 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | 146 | |
| 139 | 147 | var array: [4]void = undefined; |
| ... | ... | @@ -144,6 +152,7 @@ test "void arrays" { |
| 144 | 152 | } |
| 145 | 153 | |
| 146 | 154 | test "nested arrays" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 147 | 156 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 148 | 157 | |
| 149 | 158 | const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" }; |
| ... | ... | @@ -157,6 +166,7 @@ test "nested arrays" { |
| 157 | 166 | } |
| 158 | 167 | |
| 159 | 168 | test "implicit comptime in array type size" { |
| 169 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 160 | 170 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 161 | 171 | |
| 162 | 172 | var arr: [plusOne(10)]bool = undefined; |
| ... | ... | @@ -168,6 +178,7 @@ fn plusOne(x: u32) u32 { |
| 168 | 178 | } |
| 169 | 179 | |
| 170 | 180 | test "single-item pointer to array indexing and slicing" { |
| 181 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 171 | 182 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 172 | 183 | |
| 173 | 184 | try testSingleItemPtrArrayIndexSlice(); |
| ... | ... | @@ -193,6 +204,7 @@ fn doSomeMangling(array: *[4]u8) void { |
| 193 | 204 | } |
| 194 | 205 | |
| 195 | 206 | test "implicit cast zero sized array ptr to slice" { |
| 207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 196 | 208 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 197 | 209 | |
| 198 | 210 | { |
| ... | ... | @@ -208,6 +220,7 @@ test "implicit cast zero sized array ptr to slice" { |
| 208 | 220 | } |
| 209 | 221 | |
| 210 | 222 | test "anonymous list literal syntax" { |
| 223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 211 | 224 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 212 | 225 | |
| 213 | 226 | const S = struct { |
| ... | ... | @@ -227,6 +240,7 @@ var s_array: [8]Sub = undefined; |
| 227 | 240 | const Sub = struct { b: u8 }; |
| 228 | 241 | const Str = struct { a: []Sub }; |
| 229 | 242 | test "set global var array via slice embedded in struct" { |
| 243 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 230 | 244 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 231 | 245 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 232 | 246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -243,6 +257,7 @@ test "set global var array via slice embedded in struct" { |
| 243 | 257 | } |
| 244 | 258 | |
| 245 | 259 | test "read/write through global variable array of struct fields initialized via array mult" { |
| 260 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 246 | 261 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 247 | 262 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 248 | 263 | 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 |
| 264 | 279 | } |
| 265 | 280 | |
| 266 | 281 | test "implicit cast single-item pointer" { |
| 282 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 267 | 283 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 268 | 284 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 269 | 285 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -284,6 +300,7 @@ fn testArrayByValAtComptime(b: [2]u8) u8 { |
| 284 | 300 | } |
| 285 | 301 | |
| 286 | 302 | test "comptime evaluating function that takes array by value" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 287 | 304 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 288 | 305 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 289 | 306 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -296,6 +313,7 @@ test "comptime evaluating function that takes array by value" { |
| 296 | 313 | } |
| 297 | 314 | |
| 298 | 315 | test "runtime initialize array elem and then implicit cast to slice" { |
| 316 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 317 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 300 | 318 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 301 | 319 | 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" { |
| 306 | 324 | } |
| 307 | 325 | |
| 308 | 326 | test "array literal as argument to function" { |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 309 | 328 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 310 | 329 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 311 | 330 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -334,6 +353,7 @@ test "array literal as argument to function" { |
| 334 | 353 | } |
| 335 | 354 | |
| 336 | 355 | test "double nested array to const slice cast in array literal" { |
| 356 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 357 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 338 | 358 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 339 | 359 | 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" { |
| 395 | 415 | } |
| 396 | 416 | |
| 397 | 417 | test "anonymous literal in array" { |
| 418 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 398 | 419 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 399 | 420 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 400 | 421 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -420,6 +441,7 @@ test "anonymous literal in array" { |
| 420 | 441 | } |
| 421 | 442 | |
| 422 | 443 | test "access the null element of a null terminated array" { |
| 444 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 423 | 445 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 424 | 446 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 425 | 447 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -437,6 +459,7 @@ test "access the null element of a null terminated array" { |
| 437 | 459 | } |
| 438 | 460 | |
| 439 | 461 | test "type deduction for array subscript expression" { |
| 462 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 440 | 463 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 441 | 464 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 442 | 465 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -455,6 +478,7 @@ test "type deduction for array subscript expression" { |
| 455 | 478 | } |
| 456 | 479 | |
| 457 | 480 | test "sentinel element count towards the ABI size calculation" { |
| 481 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 458 | 482 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO |
| 459 | 483 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 460 | 484 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -481,6 +505,7 @@ test "sentinel element count towards the ABI size calculation" { |
| 481 | 505 | } |
| 482 | 506 | |
| 483 | 507 | test "zero-sized array with recursive type definition" { |
| 508 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 484 | 509 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO |
| 485 | 510 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 486 | 511 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -505,6 +530,7 @@ test "zero-sized array with recursive type definition" { |
| 505 | 530 | } |
| 506 | 531 | |
| 507 | 532 | test "type coercion of anon struct literal to array" { |
| 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 508 | 534 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 509 | 535 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 510 | 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -540,6 +566,7 @@ test "type coercion of anon struct literal to array" { |
| 540 | 566 | } |
| 541 | 567 | |
| 542 | 568 | test "type coercion of pointer to anon struct literal to pointer to array" { |
| 569 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 543 | 570 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO |
| 544 | 571 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 545 | 572 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
test/behavior/basic.zig+32| ... | ... | @@ -15,6 +15,7 @@ test "empty function with comments" { |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | test "truncate" { |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 18 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 19 | 20 | |
| 20 | 21 | try expect(testTruncate(0x10fd) == 0xfd); |
| ... | ... | @@ -25,6 +26,7 @@ fn testTruncate(x: u32) u8 { |
| 25 | 26 | } |
| 26 | 27 | |
| 27 | 28 | test "truncate to non-power-of-two integers" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 29 | 31 | |
| 30 | 32 | try testTrunc(u32, u1, 0b10101, 0b1); |
| ... | ... | @@ -46,6 +48,7 @@ const g1: i32 = 1233 + 1; |
| 46 | 48 | var g2: i32 = 0; |
| 47 | 49 | |
| 48 | 50 | test "global variables" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 49 | 52 | try expect(g2 == 0); |
| 50 | 53 | g2 = g1; |
| 51 | 54 | try expect(g2 == 1234); |
| ... | ... | @@ -112,6 +115,7 @@ fn first4KeysOfHomeRow() []const u8 { |
| 112 | 115 | } |
| 113 | 116 | |
| 114 | 117 | test "return string from function" { |
| 118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 115 | 119 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 116 | 120 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 117 | 121 | |
| ... | ... | @@ -119,12 +123,14 @@ test "return string from function" { |
| 119 | 123 | } |
| 120 | 124 | |
| 121 | 125 | test "hex escape" { |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 122 | 127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 123 | 128 | |
| 124 | 129 | try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); |
| 125 | 130 | } |
| 126 | 131 | |
| 127 | 132 | test "multiline string" { |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 128 | 134 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 129 | 135 | |
| 130 | 136 | const s1 = |
| ... | ... | @@ -137,6 +143,7 @@ test "multiline string" { |
| 137 | 143 | } |
| 138 | 144 | |
| 139 | 145 | test "multiline string comments at start" { |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 140 | 147 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 141 | 148 | |
| 142 | 149 | const s1 = |
| ... | ... | @@ -149,6 +156,7 @@ test "multiline string comments at start" { |
| 149 | 156 | } |
| 150 | 157 | |
| 151 | 158 | test "multiline string comments at end" { |
| 159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 152 | 160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 153 | 161 | |
| 154 | 162 | const s1 = |
| ... | ... | @@ -161,6 +169,7 @@ test "multiline string comments at end" { |
| 161 | 169 | } |
| 162 | 170 | |
| 163 | 171 | test "multiline string comments in middle" { |
| 172 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 173 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 165 | 174 | |
| 166 | 175 | const s1 = |
| ... | ... | @@ -173,6 +182,7 @@ test "multiline string comments in middle" { |
| 173 | 182 | } |
| 174 | 183 | |
| 175 | 184 | test "multiline string comments at multiple places" { |
| 185 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 176 | 186 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 177 | 187 | |
| 178 | 188 | const s1 = |
| ... | ... | @@ -191,6 +201,7 @@ test "string concatenation" { |
| 191 | 201 | } |
| 192 | 202 | |
| 193 | 203 | test "array mult operator" { |
| 204 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 194 | 205 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 195 | 206 | |
| 196 | 207 | try expect(mem.eql(u8, "ab" ** 5, "ababababab")); |
| ... | ... | @@ -216,6 +227,7 @@ test "compile time global reinterpret" { |
| 216 | 227 | } |
| 217 | 228 | |
| 218 | 229 | test "cast undefined" { |
| 230 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 219 | 231 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 220 | 232 | |
| 221 | 233 | const array: [100]u8 = undefined; |
| ... | ... | @@ -227,6 +239,7 @@ fn testCastUndefined(x: []const u8) void { |
| 227 | 239 | } |
| 228 | 240 | |
| 229 | 241 | test "implicit cast after unreachable" { |
| 242 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 230 | 243 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 231 | 244 | |
| 232 | 245 | try expect(outer() == 1234); |
| ... | ... | @@ -284,6 +297,7 @@ fn fB() []const u8 { |
| 284 | 297 | } |
| 285 | 298 | |
| 286 | 299 | test "call function pointer in struct" { |
| 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 287 | 301 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 288 | 302 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 289 | 303 | |
| ... | ... | @@ -310,6 +324,7 @@ const FnPtrWrapper = struct { |
| 310 | 324 | }; |
| 311 | 325 | |
| 312 | 326 | test "const ptr from var variable" { |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 313 | 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 314 | 329 | |
| 315 | 330 | var x: u64 = undefined; |
| ... | ... | @@ -326,6 +341,7 @@ fn copy(src: *const u64, dst: *u64) void { |
| 326 | 341 | } |
| 327 | 342 | |
| 328 | 343 | test "call result of if else expression" { |
| 344 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 329 | 345 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 330 | 346 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 331 | 347 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -339,6 +355,7 @@ fn f2(x: bool) []const u8 { |
| 339 | 355 | } |
| 340 | 356 | |
| 341 | 357 | test "memcpy and memset intrinsics" { |
| 358 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 342 | 359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 343 | 360 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 344 | 361 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -361,6 +378,7 @@ fn testMemcpyMemset() !void { |
| 361 | 378 | } |
| 362 | 379 | |
| 363 | 380 | test "variable is allowed to be a pointer to an opaque type" { |
| 381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 364 | 382 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 365 | 383 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 366 | 384 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -374,6 +392,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { |
| 374 | 392 | } |
| 375 | 393 | |
| 376 | 394 | test "take address of parameter" { |
| 395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 377 | 396 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 378 | 397 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 379 | 398 | |
| ... | ... | @@ -400,6 +419,7 @@ fn testPointerToVoidReturnType2() *const void { |
| 400 | 419 | } |
| 401 | 420 | |
| 402 | 421 | test "array 2D const double ptr" { |
| 422 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 403 | 423 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 404 | 424 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 405 | 425 | |
| ... | ... | @@ -419,6 +439,7 @@ fn testArray2DConstDoublePtr(ptr: *const f32) !void { |
| 419 | 439 | } |
| 420 | 440 | |
| 421 | 441 | test "double implicit cast in same expression" { |
| 442 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 422 | 443 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 423 | 444 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 424 | 445 | |
| ... | ... | @@ -430,6 +451,7 @@ fn nine() u8 { |
| 430 | 451 | } |
| 431 | 452 | |
| 432 | 453 | test "struct inside function" { |
| 454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 433 | 455 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 434 | 456 | |
| 435 | 457 | try testStructInFn(); |
| ... | ... | @@ -451,6 +473,7 @@ fn testStructInFn() !void { |
| 451 | 473 | } |
| 452 | 474 | |
| 453 | 475 | test "fn call returning scalar optional in equality expression" { |
| 476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 454 | 477 | try expect(getNull() == null); |
| 455 | 478 | } |
| 456 | 479 | |
| ... | ... | @@ -459,6 +482,7 @@ fn getNull() ?*i32 { |
| 459 | 482 | } |
| 460 | 483 | |
| 461 | 484 | test "global variable assignment with optional unwrapping with var initialized to undefined" { |
| 485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 462 | 486 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 463 | 487 | |
| 464 | 488 | const S = struct { |
| ... | ... | @@ -476,6 +500,7 @@ test "global variable assignment with optional unwrapping with var initialized t |
| 476 | 500 | var global_foo: *i32 = undefined; |
| 477 | 501 | |
| 478 | 502 | test "peer result location with typed parent, runtime condition, comptime prongs" { |
| 503 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 479 | 504 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 480 | 505 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 481 | 506 | |
| ... | ... | @@ -550,6 +575,7 @@ test "comptime cast fn to ptr" { |
| 550 | 575 | } |
| 551 | 576 | |
| 552 | 577 | test "equality compare fn ptrs" { |
| 578 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 553 | 579 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 554 | 580 | |
| 555 | 581 | var a = &emptyFn; |
| ... | ... | @@ -557,6 +583,7 @@ test "equality compare fn ptrs" { |
| 557 | 583 | } |
| 558 | 584 | |
| 559 | 585 | test "self reference through fn ptr field" { |
| 586 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 560 | 587 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 561 | 588 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 562 | 589 | |
| ... | ... | @@ -576,6 +603,7 @@ test "self reference through fn ptr field" { |
| 576 | 603 | } |
| 577 | 604 | |
| 578 | 605 | test "global variable initialized to global variable array element" { |
| 606 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 579 | 607 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 580 | 608 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 581 | 609 | |
| ... | ... | @@ -593,6 +621,7 @@ var gdt = [_]GDTEntry{ |
| 593 | 621 | var global_ptr = &gdt[0]; |
| 594 | 622 | |
| 595 | 623 | test "global constant is loaded with a runtime-known index" { |
| 624 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 596 | 625 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 597 | 626 | |
| 598 | 627 | const S = struct { |
| ... | ... | @@ -610,6 +639,7 @@ test "global constant is loaded with a runtime-known index" { |
| 610 | 639 | } |
| 611 | 640 | |
| 612 | 641 | test "multiline string literal is null terminated" { |
| 642 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 613 | 643 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 614 | 644 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 615 | 645 | |
| ... | ... | @@ -643,6 +673,7 @@ test "explicit cast optional pointers" { |
| 643 | 673 | } |
| 644 | 674 | |
| 645 | 675 | test "pointer comparison" { |
| 676 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 646 | 677 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 647 | 678 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 648 | 679 | |
| ... | ... | @@ -655,6 +686,7 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool { |
| 655 | 686 | } |
| 656 | 687 | |
| 657 | 688 | test "string concatenation" { |
| 689 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 658 | 690 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 659 | 691 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 660 | 692 |
test/behavior/bit_shifting.zig+1| ... | ... | @@ -61,6 +61,7 @@ fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, compt |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | 63 | test "sharded table" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 64 | 65 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 65 | 66 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 66 | 67 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
test/behavior/bugs/1381.zig+1| ... | ... | @@ -12,6 +12,7 @@ const A = union(enum) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "union that needs padding bytes inside an array" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 16 | 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 17 | 18 | var as = [_]A{ |
test/behavior/bugs/1486.zig+2| ... | ... | @@ -1,10 +1,12 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | |
| 3 | 4 | |
| 4 | 5 | const ptr = &global; |
| 5 | 6 | var global: usize = 123; |
| 6 | 7 | |
| 7 | 8 | test "constant pointer to global variable causes runtime load" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 10 | global = 1234; |
| 9 | 11 | try expect(&global == ptr); |
| 10 | 12 | try expect(ptr.* == 1234); |
test/behavior/bugs/1735.zig+1| ... | ... | @@ -42,6 +42,7 @@ const a = struct { |
| 42 | 42 | }; |
| 43 | 43 | |
| 44 | 44 | test "initialization" { |
| 45 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 45 | 46 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 46 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 47 | 48 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
test/behavior/bugs/1741.zig+1| ... | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | test "fixed" { |
| 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 5 | 6 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 6 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 7 | 8 | const x: f32 align(128) = 12.34; |
test/behavior/bugs/2006.zig+1| ... | ... | @@ -6,6 +6,7 @@ const S = struct { |
| 6 | 6 | p: *S, |
| 7 | 7 | }; |
| 8 | 8 | test "bug 2006" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 10 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 10 | 11 | var a: S = undefined; |
| 11 | 12 | a = S{ .p = undefined }; |
test/behavior/bugs/2578.zig+1| ... | ... | @@ -12,6 +12,7 @@ fn bar(pointer: ?*anyopaque) void { |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | test "fixed" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 16 | 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 17 | 18 | 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 { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | test "fixed" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 22 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | 24 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 24 | 25 | 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 { |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | test "zig test crash" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 16 | 17 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 17 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
test/behavior/bugs/3367.zig+1| ... | ... | @@ -10,6 +10,7 @@ const Mixin = struct { |
| 10 | 10 | }; |
| 11 | 11 | |
| 12 | 12 | test "container member access usingnamespace decls" { |
| 13 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 13 | 14 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 14 | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 15 | 16 | var foo = Foo{}; |
test/behavior/bugs/394.zig+1| ... | ... | @@ -11,6 +11,7 @@ const expect = @import("std").testing.expect; |
| 11 | 11 | const builtin = @import("builtin"); |
| 12 | 12 | |
| 13 | 13 | test "bug 394 fixed" { |
| 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 14 | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 15 | 16 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 16 | 17 | const x = S{ |
test/behavior/bugs/656.zig+1| ... | ... | @@ -11,6 +11,7 @@ const Value = struct { |
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | 13 | test "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; | |
| 14 | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 15 | 16 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 16 | 17 | try foo(false, true); |
test/behavior/bugs/7250.zig+1| ... | ... | @@ -14,6 +14,7 @@ threadlocal var g_uart0 = nrfx_uart_t{ |
| 14 | 14 | }; |
| 15 | 15 | |
| 16 | 16 | test "reference a global threadlocal variable" { |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 17 | 18 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 18 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 19 | 20 | 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" { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "peer type resolution: ?T and T" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 22 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 22 | 23 | |
| 23 | 24 | try expect(peerTypeTAndOptionalT(true, false).? == 0); |
| ... | ... | @@ -94,6 +95,7 @@ test "comptime_int @intToFloat" { |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | 97 | test "@floatToInt" { |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 97 | 99 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 98 | 100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 99 | 101 | |
| ... | ... | @@ -116,6 +118,7 @@ fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void { |
| 116 | 118 | } |
| 117 | 119 | |
| 118 | 120 | test "implicitly cast indirect pointer to maybe-indirect pointer" { |
| 121 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 119 | 122 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 120 | 123 | |
| 121 | 124 | const S = struct { |
| ... | ... | @@ -174,6 +177,7 @@ test "@floatCast comptime_int and comptime_float" { |
| 174 | 177 | } |
| 175 | 178 | |
| 176 | 179 | test "coerce undefined to optional" { |
| 180 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 181 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 178 | 182 | |
| 179 | 183 | try expect(MakeType(void).getNull() == null); |
| ... | ... | @@ -193,6 +197,7 @@ fn MakeType(comptime T: type) type { |
| 193 | 197 | } |
| 194 | 198 | |
| 195 | 199 | test "implicit cast from *[N]T to [*c]T" { |
| 200 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 196 | 201 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 197 | 202 | |
| 198 | 203 | var x: [4]u16 = [4]u16{ 0, 1, 2, 3 }; |
| ... | ... | @@ -205,6 +210,7 @@ test "implicit cast from *[N]T to [*c]T" { |
| 205 | 210 | } |
| 206 | 211 | |
| 207 | 212 | test "*usize to *void" { |
| 213 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 208 | 214 | var i = @as(usize, 0); |
| 209 | 215 | var v = @ptrCast(*void, &i); |
| 210 | 216 | v.* = {}; |
| ... | ... | @@ -230,6 +236,7 @@ test "@intCast to u0 and use the result" { |
| 230 | 236 | } |
| 231 | 237 | |
| 232 | 238 | test "peer result null and comptime_int" { |
| 239 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 233 | 240 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 234 | 241 | |
| 235 | 242 | const S = struct { |
| ... | ... | @@ -253,6 +260,7 @@ test "peer result null and comptime_int" { |
| 253 | 260 | } |
| 254 | 261 | |
| 255 | 262 | test "*const ?[*]const T to [*c]const [*c]const T" { |
| 263 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 256 | 264 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 257 | 265 | |
| 258 | 266 | var array = [_]u8{ 'o', 'k' }; |
| ... | ... | @@ -264,6 +272,7 @@ test "*const ?[*]const T to [*c]const [*c]const T" { |
| 264 | 272 | } |
| 265 | 273 | |
| 266 | 274 | test "array coersion to undefined at runtime" { |
| 275 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 267 | 276 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 268 | 277 | |
| 269 | 278 | @setRuntimeSafety(true); |
| ... | ... | @@ -293,6 +302,7 @@ fn implicitIntLitToOptional() void { |
| 293 | 302 | } |
| 294 | 303 | |
| 295 | 304 | test "return u8 coercing into ?u32 return type" { |
| 305 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 296 | 306 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 297 | 307 | |
| 298 | 308 | const S = struct { |
| ... | ... | @@ -313,6 +323,7 @@ test "cast from ?[*]T to ??[*]T" { |
| 313 | 323 | } |
| 314 | 324 | |
| 315 | 325 | test "peer type unsigned int to signed" { |
| 326 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 316 | 327 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 317 | 328 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 318 | 329 | |
| ... | ... | @@ -325,6 +336,7 @@ test "peer type unsigned int to signed" { |
| 325 | 336 | } |
| 326 | 337 | |
| 327 | 338 | test "expected [*c]const u8, found [*:0]const u8" { |
| 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 328 | 340 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 329 | 341 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 330 | 342 | |
| ... | ... | @@ -384,6 +396,7 @@ fn castToOptionalTypeError(z: i32) !void { |
| 384 | 396 | } |
| 385 | 397 | |
| 386 | 398 | test "implicitly cast from [0]T to anyerror![]T" { |
| 399 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 387 | 400 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 388 | 401 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 389 | 402 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -455,6 +468,7 @@ fn testCastConstArrayRefToConstSlice() !void { |
| 455 | 468 | } |
| 456 | 469 | |
| 457 | 470 | test "peer type resolution: error and [N]T" { |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 458 | 472 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 459 | 473 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 460 | 474 | |
| ... | ... | @@ -689,6 +703,7 @@ test "type coercion related to sentinel-termination" { |
| 689 | 703 | } |
| 690 | 704 | |
| 691 | 705 | test "peer type resolution implicit cast to return type" { |
| 706 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 692 | 707 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 693 | 708 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 694 | 709 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -710,6 +725,7 @@ test "peer type resolution implicit cast to return type" { |
| 710 | 725 | } |
| 711 | 726 | |
| 712 | 727 | test "peer type resolution implicit cast to variable type" { |
| 728 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 713 | 729 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 714 | 730 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 715 | 731 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -806,6 +822,7 @@ test "comptime float casts" { |
| 806 | 822 | } |
| 807 | 823 | |
| 808 | 824 | test "pointer reinterpret const float to int" { |
| 825 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 809 | 826 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 810 | 827 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 811 | 828 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -822,6 +839,7 @@ test "pointer reinterpret const float to int" { |
| 822 | 839 | } |
| 823 | 840 | |
| 824 | 841 | test "implicit cast from [*]T to ?*anyopaque" { |
| 842 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 825 | 843 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 826 | 844 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 827 | 845 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -840,6 +858,7 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void { |
| 840 | 858 | } |
| 841 | 859 | |
| 842 | 860 | test "compile time int to ptr of function" { |
| 861 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 843 | 862 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 844 | 863 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) return error.SkipZigTest; // TODO |
| 845 | 864 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -857,6 +876,7 @@ fn foobar(func: PFN_void) !void { |
| 857 | 876 | } |
| 858 | 877 | |
| 859 | 878 | test "implicit ptr to *anyopaque" { |
| 879 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 860 | 880 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 861 | 881 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 862 | 882 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -871,6 +891,7 @@ test "implicit ptr to *anyopaque" { |
| 871 | 891 | } |
| 872 | 892 | |
| 873 | 893 | test "return null from fn() anyerror!?&T" { |
| 894 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 874 | 895 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 875 | 896 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 876 | 897 | |
| ... | ... | @@ -887,6 +908,7 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { |
| 887 | 908 | } |
| 888 | 909 | |
| 889 | 910 | test "peer type resolution: [0]u8 and []const u8" { |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 890 | 912 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 891 | 913 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 892 | 914 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -907,6 +929,7 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { |
| 907 | 929 | } |
| 908 | 930 | |
| 909 | 931 | test "implicitly cast from [N]T to ?[]const T" { |
| 932 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 910 | 933 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 911 | 934 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 912 | 935 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -920,6 +943,7 @@ fn castToOptionalSlice() ?[]const u8 { |
| 920 | 943 | } |
| 921 | 944 | |
| 922 | 945 | test "cast u128 to f128 and back" { |
| 946 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 923 | 947 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 924 | 948 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 925 | 949 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -941,6 +965,7 @@ fn cast128Float(x: u128) f128 { |
| 941 | 965 | } |
| 942 | 966 | |
| 943 | 967 | test "implicit cast from *[N]T to ?[*]T" { |
| 968 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 944 | 969 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 945 | 970 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 946 | 971 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -956,6 +981,7 @@ test "implicit cast from *[N]T to ?[*]T" { |
| 956 | 981 | } |
| 957 | 982 | |
| 958 | 983 | test "implicit cast from *T to ?*anyopaque" { |
| 984 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 959 | 985 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 960 | 986 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 961 | 987 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -970,6 +996,7 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { |
| 970 | 996 | } |
| 971 | 997 | |
| 972 | 998 | test "implicit cast *[0]T to E![]const u8" { |
| 999 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 973 | 1000 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 974 | 1001 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 975 | 1002 | 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" { |
| 987 | 1014 | try expect(@ptrToInt(f) == @ptrToInt(&global_array)); |
| 988 | 1015 | } |
| 989 | 1016 | test "cast from array reference to fn: runtime fn ptr" { |
| 1017 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 990 | 1018 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 991 | 1019 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 992 | 1020 | 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" { |
| 996 | 1024 | } |
| 997 | 1025 | |
| 998 | 1026 | test "*const [N]null u8 to ?[]const u8" { |
| 1027 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 999 | 1028 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1000 | 1029 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1001 | 1030 | 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" { |
| 1034 | 1063 | |
| 1035 | 1064 | var global_struct: struct { f0: usize } = undefined; |
| 1036 | 1065 | test "assignment to optional pointer result loc" { |
| 1066 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1037 | 1067 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1038 | 1068 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1039 | 1069 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1043,6 +1073,7 @@ test "assignment to optional pointer result loc" { |
| 1043 | 1073 | } |
| 1044 | 1074 | |
| 1045 | 1075 | test "cast between *[N]void and []void" { |
| 1076 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1046 | 1077 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1047 | 1078 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1048 | 1079 | |
| ... | ... | @@ -1052,6 +1083,7 @@ test "cast between *[N]void and []void" { |
| 1052 | 1083 | } |
| 1053 | 1084 | |
| 1054 | 1085 | test "peer resolve arrays of different size to const slice" { |
| 1086 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1055 | 1087 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1056 | 1088 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1057 | 1089 | |
| ... | ... | @@ -1065,6 +1097,7 @@ fn boolToStr(b: bool) []const u8 { |
| 1065 | 1097 | } |
| 1066 | 1098 | |
| 1067 | 1099 | test "cast f16 to wider types" { |
| 1100 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1068 | 1101 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1069 | 1102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1070 | 1103 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1083,6 +1116,7 @@ test "cast f16 to wider types" { |
| 1083 | 1116 | } |
| 1084 | 1117 | |
| 1085 | 1118 | test "cast f128 to narrower types" { |
| 1119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1086 | 1120 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1087 | 1121 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1088 | 1122 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1101,6 +1135,7 @@ test "cast f128 to narrower types" { |
| 1101 | 1135 | } |
| 1102 | 1136 | |
| 1103 | 1137 | test "peer type resolution: unreachable, null, slice" { |
| 1138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1104 | 1139 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1105 | 1140 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1106 | 1141 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1119,6 +1154,7 @@ test "peer type resolution: unreachable, null, slice" { |
| 1119 | 1154 | } |
| 1120 | 1155 | |
| 1121 | 1156 | test "cast i8 fn call peers to i32 result" { |
| 1157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1122 | 1158 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1123 | 1159 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1124 | 1160 |
test/behavior/fn_delegation.zig+1| ... | ... | @@ -32,6 +32,7 @@ fn custom(comptime T: type, comptime num: u64) fn (T) u64 { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | test "fn delegation" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 35 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 36 | 37 | |
| 37 | 38 | const foo = Foo{}; |
test/behavior/ir_block_deps.zig+1| ... | ... | @@ -18,6 +18,7 @@ fn getErrInt() anyerror!i32 { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "ir block deps" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 22 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 22 | 23 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 23 | 24 |
test/behavior/optional.zig+10| ... | ... | @@ -5,6 +5,7 @@ const expect = testing.expect; |
| 5 | 5 | const expectEqual = testing.expectEqual; |
| 6 | 6 | |
| 7 | 7 | test "passing an optional integer as a parameter" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 10 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 10 | 11 | |
| ... | ... | @@ -25,6 +26,7 @@ test "passing an optional integer as a parameter" { |
| 25 | 26 | pub const EmptyStruct = struct {}; |
| 26 | 27 | |
| 27 | 28 | test "optional pointer to size zero struct" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 29 | 31 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 30 | 32 | |
| ... | ... | @@ -34,6 +36,7 @@ test "optional pointer to size zero struct" { |
| 34 | 36 | } |
| 35 | 37 | |
| 36 | 38 | test "equality compare optional pointers" { |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 37 | 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 38 | 41 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 39 | 42 | |
| ... | ... | @@ -58,6 +61,7 @@ fn testNullPtrsEql() !void { |
| 58 | 61 | } |
| 59 | 62 | |
| 60 | 63 | test "optional with void type" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 61 | 65 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 62 | 66 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 63 | 67 | |
| ... | ... | @@ -69,6 +73,7 @@ test "optional with void type" { |
| 69 | 73 | } |
| 70 | 74 | |
| 71 | 75 | test "address of unwrap optional" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 72 | 77 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 78 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 74 | 79 | |
| ... | ... | @@ -89,6 +94,7 @@ test "address of unwrap optional" { |
| 89 | 94 | } |
| 90 | 95 | |
| 91 | 96 | test "nested optional field in struct" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 92 | 98 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 93 | 99 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 94 | 100 | |
| ... | ... | @@ -105,6 +111,7 @@ test "nested optional field in struct" { |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | 113 | test "equality compare optional with non-optional" { |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 108 | 115 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 109 | 116 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 110 | 117 | |
| ... | ... | @@ -142,6 +149,7 @@ fn test_cmp_optional_non_optional() !void { |
| 142 | 149 | } |
| 143 | 150 | |
| 144 | 151 | test "unwrap function call with optional pointer return value" { |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 145 | 153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 146 | 154 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 147 | 155 | |
| ... | ... | @@ -163,6 +171,7 @@ test "unwrap function call with optional pointer return value" { |
| 163 | 171 | } |
| 164 | 172 | |
| 165 | 173 | test "nested orelse" { |
| 174 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 166 | 175 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 167 | 176 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 168 | 177 | |
| ... | ... | @@ -189,6 +198,7 @@ test "nested orelse" { |
| 189 | 198 | } |
| 190 | 199 | |
| 191 | 200 | test "self-referential struct through a slice of optional" { |
| 201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 192 | 202 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 193 | 203 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 194 | 204 | 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 { |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | test "reflection: @field" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 32 | 33 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 33 | 34 |
test/behavior/slice.zig+14| ... | ... | @@ -27,6 +27,7 @@ comptime { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | test "slicing" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 31 | 32 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 32 | 33 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -68,6 +69,7 @@ test "comptime slice of undefined pointer of length 0" { |
| 68 | 69 | } |
| 69 | 70 | |
| 70 | 71 | test "implicitly cast array of size 0 to slice" { |
| 72 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 71 | 73 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 72 | 74 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 73 | 75 | |
| ... | ... | @@ -80,6 +82,7 @@ fn assertLenIsZero(msg: []const u8) !void { |
| 80 | 82 | } |
| 81 | 83 | |
| 82 | 84 | test "access len index of sentinel-terminated slice" { |
| 85 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 83 | 86 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 84 | 87 | |
| 85 | 88 | const S = struct { |
| ... | ... | @@ -129,6 +132,7 @@ test "slice of type" { |
| 129 | 132 | } |
| 130 | 133 | |
| 131 | 134 | test "generic malloc free" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 132 | 136 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 133 | 137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 134 | 138 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| ... | ... | @@ -187,6 +191,7 @@ test "comptime pointer cast array and then slice" { |
| 187 | 191 | } |
| 188 | 192 | |
| 189 | 193 | test "slicing zero length array" { |
| 194 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 190 | 195 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 191 | 196 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 192 | 197 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| ... | ... | @@ -202,6 +207,7 @@ test "slicing zero length array" { |
| 202 | 207 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; |
| 203 | 208 | const y = x[0x100..]; |
| 204 | 209 | test "compile time slice of pointer to hard coded address" { |
| 210 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 205 | 211 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 206 | 212 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 207 | 213 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| ... | ... | @@ -215,6 +221,7 @@ test "compile time slice of pointer to hard coded address" { |
| 215 | 221 | } |
| 216 | 222 | |
| 217 | 223 | test "slice string literal has correct type" { |
| 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 218 | 225 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 219 | 226 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 220 | 227 | |
| ... | ... | @@ -230,6 +237,7 @@ test "slice string literal has correct type" { |
| 230 | 237 | } |
| 231 | 238 | |
| 232 | 239 | test "result location zero sized array inside struct field implicit cast to slice" { |
| 240 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 233 | 241 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 234 | 242 | |
| 235 | 243 | const E = struct { |
| ... | ... | @@ -240,6 +248,7 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 240 | 248 | } |
| 241 | 249 | |
| 242 | 250 | test "runtime safety lets us slice from len..len" { |
| 251 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 243 | 252 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 244 | 253 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 245 | 254 | |
| ... | ... | @@ -252,6 +261,7 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { |
| 252 | 261 | } |
| 253 | 262 | |
| 254 | 263 | test "C pointer" { |
| 264 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 255 | 265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 256 | 266 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 257 | 267 | |
| ... | ... | @@ -262,6 +272,7 @@ test "C pointer" { |
| 262 | 272 | } |
| 263 | 273 | |
| 264 | 274 | test "C pointer slice access" { |
| 275 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 265 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 266 | 277 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 267 | 278 | |
| ... | ... | @@ -291,6 +302,7 @@ fn sliceSum(comptime q: []const u8) i32 { |
| 291 | 302 | } |
| 292 | 303 | |
| 293 | 304 | test "slice type with custom alignment" { |
| 305 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 294 | 306 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 295 | 307 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 296 | 308 | |
| ... | ... | @@ -305,6 +317,7 @@ test "slice type with custom alignment" { |
| 305 | 317 | } |
| 306 | 318 | |
| 307 | 319 | test "obtaining a null terminated slice" { |
| 320 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 308 | 321 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 309 | 322 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 310 | 323 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -350,6 +363,7 @@ test "empty array to slice" { |
| 350 | 363 | } |
| 351 | 364 | |
| 352 | 365 | test "@ptrCast slice to pointer" { |
| 366 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 353 | 367 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 354 | 368 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 355 | 369 |
test/behavior/struct.zig+28| ... | ... | @@ -9,6 +9,7 @@ const maxInt = std.math.maxInt; |
| 9 | 9 | top_level_field: i32, |
| 10 | 10 | |
| 11 | 11 | test "top level fields" { |
| 12 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 12 | 13 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 13 | 14 | |
| 14 | 15 | var instance = @This(){ |
| ... | ... | @@ -42,6 +43,7 @@ const StructWithFields = struct { |
| 42 | 43 | }; |
| 43 | 44 | |
| 44 | 45 | test "non-packed struct has fields padded out to the required alignment" { |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 45 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 46 | 48 | |
| 47 | 49 | const foo = StructWithFields{ .a = 5, .b = 1, .c = 10, .d = 2 }; |
| ... | ... | @@ -65,6 +67,7 @@ const SmallStruct = struct { |
| 65 | 67 | }; |
| 66 | 68 | |
| 67 | 69 | test "lower unnamed constants" { |
| 70 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 68 | 71 | var foo = SmallStruct{ .a = 1, .b = 255 }; |
| 69 | 72 | try expect(foo.first() == 1); |
| 70 | 73 | try expect(foo.second() == 255); |
| ... | ... | @@ -83,6 +86,7 @@ const StructFoo = struct { |
| 83 | 86 | }; |
| 84 | 87 | |
| 85 | 88 | test "structs" { |
| 89 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 86 | 90 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 87 | 91 | |
| 88 | 92 | var foo: StructFoo = undefined; |
| ... | ... | @@ -101,6 +105,7 @@ fn testMutation(foo: *StructFoo) void { |
| 101 | 105 | } |
| 102 | 106 | |
| 103 | 107 | test "struct byval assign" { |
| 108 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 104 | 109 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 105 | 110 | |
| 106 | 111 | var foo1: StructFoo = undefined; |
| ... | ... | @@ -134,6 +139,7 @@ fn returnEmptyStructInstance() StructWithNoFields { |
| 134 | 139 | } |
| 135 | 140 | |
| 136 | 141 | test "fn call of struct field" { |
| 142 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 137 | 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | 144 | |
| 139 | 145 | const Foo = struct { |
| ... | ... | @@ -165,12 +171,14 @@ const MemberFnTestFoo = struct { |
| 165 | 171 | }; |
| 166 | 172 | |
| 167 | 173 | test "call member function directly" { |
| 174 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 168 | 175 | const instance = MemberFnTestFoo{ .x = 1234 }; |
| 169 | 176 | const result = MemberFnTestFoo.member(instance); |
| 170 | 177 | try expect(result == 1234); |
| 171 | 178 | } |
| 172 | 179 | |
| 173 | 180 | test "store member function in variable" { |
| 181 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 174 | 182 | const instance = MemberFnTestFoo{ .x = 1234 }; |
| 175 | 183 | const memberFn = MemberFnTestFoo.member; |
| 176 | 184 | const result = memberFn(instance); |
| ... | ... | @@ -178,6 +186,7 @@ test "store member function in variable" { |
| 178 | 186 | } |
| 179 | 187 | |
| 180 | 188 | test "member functions" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 181 | 190 | const r = MemberFnRand{ .seed = 1234 }; |
| 182 | 191 | try expect(r.getSeed() == 1234); |
| 183 | 192 | } |
| ... | ... | @@ -189,6 +198,7 @@ const MemberFnRand = struct { |
| 189 | 198 | }; |
| 190 | 199 | |
| 191 | 200 | test "return struct byval from function" { |
| 201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 192 | 202 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 193 | 203 | |
| 194 | 204 | const bar = makeBar2(1234, 5678); |
| ... | ... | @@ -206,6 +216,7 @@ fn makeBar2(x: i32, y: i32) Bar { |
| 206 | 216 | } |
| 207 | 217 | |
| 208 | 218 | test "call method with mutable reference to struct with no fields" { |
| 219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 209 | 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 210 | 221 | |
| 211 | 222 | const S = struct { |
| ... | ... | @@ -238,6 +249,7 @@ test "usingnamespace within struct scope" { |
| 238 | 249 | } |
| 239 | 250 | |
| 240 | 251 | test "struct field init with catch" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 241 | 253 | if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 242 | 254 | |
| 243 | 255 | const S = struct { |
| ... | ... | @@ -296,6 +308,7 @@ const Val = struct { |
| 296 | 308 | }; |
| 297 | 309 | |
| 298 | 310 | test "struct point to self" { |
| 311 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 312 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 300 | 313 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 301 | 314 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -314,6 +327,7 @@ test "struct point to self" { |
| 314 | 327 | } |
| 315 | 328 | |
| 316 | 329 | test "void struct fields" { |
| 330 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 317 | 331 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 318 | 332 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 319 | 333 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -334,6 +348,7 @@ const VoidStructFieldsFoo = struct { |
| 334 | 348 | }; |
| 335 | 349 | |
| 336 | 350 | test "return empty struct from fn" { |
| 351 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 352 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 338 | 353 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 339 | 354 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -347,6 +362,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 { |
| 347 | 362 | } |
| 348 | 363 | |
| 349 | 364 | test "pass slice of empty struct to fn" { |
| 365 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 350 | 366 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 351 | 367 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 352 | 368 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -359,6 +375,7 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { |
| 359 | 375 | } |
| 360 | 376 | |
| 361 | 377 | test "self-referencing struct via array member" { |
| 378 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 362 | 379 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 363 | 380 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 364 | 381 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -389,6 +406,7 @@ const EmptyStruct = struct { |
| 389 | 406 | }; |
| 390 | 407 | |
| 391 | 408 | test "align 1 field before self referential align 8 field as slice return type" { |
| 409 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 392 | 410 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 393 | 411 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 394 | 412 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -413,6 +431,7 @@ const APackedStruct = packed struct { |
| 413 | 431 | }; |
| 414 | 432 | |
| 415 | 433 | test "packed struct" { |
| 434 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 416 | 435 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 417 | 436 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 418 | 437 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -438,6 +457,7 @@ const Foo96Bits = packed struct { |
| 438 | 457 | }; |
| 439 | 458 | |
| 440 | 459 | test "packed struct 24bits" { |
| 460 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 441 | 461 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 442 | 462 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 443 | 463 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -484,6 +504,7 @@ test "packed struct 24bits" { |
| 484 | 504 | } |
| 485 | 505 | |
| 486 | 506 | test "runtime struct initialization of bitfield" { |
| 507 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 487 | 508 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 488 | 509 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 489 | 510 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -523,6 +544,7 @@ const Bitfields = packed struct { |
| 523 | 544 | }; |
| 524 | 545 | |
| 525 | 546 | test "native bit field understands endianness" { |
| 547 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 526 | 548 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 527 | 549 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 528 | 550 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -546,6 +568,7 @@ test "native bit field understands endianness" { |
| 546 | 568 | } |
| 547 | 569 | |
| 548 | 570 | test "implicit cast packed struct field to const ptr" { |
| 571 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 549 | 572 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 550 | 573 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 551 | 574 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -581,6 +604,7 @@ test "zero-bit field in packed struct" { |
| 581 | 604 | } |
| 582 | 605 | |
| 583 | 606 | test "packed struct with non-ABI-aligned field" { |
| 607 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 584 | 608 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 585 | 609 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 586 | 610 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -610,6 +634,7 @@ const bit_field_1 = BitField1{ |
| 610 | 634 | }; |
| 611 | 635 | |
| 612 | 636 | test "bit field access" { |
| 637 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 613 | 638 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 614 | 639 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 615 | 640 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -642,6 +667,7 @@ fn getC(data: *const BitField1) u2 { |
| 642 | 667 | } |
| 643 | 668 | |
| 644 | 669 | test "default struct initialization fields" { |
| 670 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 645 | 671 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 646 | 672 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 647 | 673 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -907,6 +933,7 @@ test "packed struct field passed to generic function" { |
| 907 | 933 | } |
| 908 | 934 | |
| 909 | 935 | test "anonymous struct literal syntax" { |
| 936 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 910 | 937 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 911 | 938 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 912 | 939 | 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" { |
| 1100 | 1127 | } |
| 1101 | 1128 | |
| 1102 | 1129 | test "packed struct with undefined initializers" { |
| 1130 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1103 | 1131 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1104 | 1132 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1105 | 1133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
test/behavior/truncate.zig+9| ... | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "truncate u0 to larger integer allowed and has comptime known result" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 6 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 7 | 8 | |
| 8 | 9 | var x: u0 = 0; |
| ... | ... | @@ -11,6 +12,7 @@ test "truncate u0 to larger integer allowed and has comptime known result" { |
| 11 | 12 | } |
| 12 | 13 | |
| 13 | 14 | test "truncate.u0.literal" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 14 | 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 15 | 17 | |
| 16 | 18 | var z = @truncate(u0, 0); |
| ... | ... | @@ -18,6 +20,7 @@ test "truncate.u0.literal" { |
| 18 | 20 | } |
| 19 | 21 | |
| 20 | 22 | test "truncate.u0.const" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 22 | 25 | |
| 23 | 26 | const c0: usize = 0; |
| ... | ... | @@ -26,6 +29,7 @@ test "truncate.u0.const" { |
| 26 | 29 | } |
| 27 | 30 | |
| 28 | 31 | test "truncate.u0.var" { |
| 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 29 | 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 30 | 34 | |
| 31 | 35 | var d: u8 = 2; |
| ... | ... | @@ -34,6 +38,7 @@ test "truncate.u0.var" { |
| 34 | 38 | } |
| 35 | 39 | |
| 36 | 40 | test "truncate i0 to larger integer allowed and has comptime known result" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 37 | 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 38 | 43 | |
| 39 | 44 | var x: i0 = 0; |
| ... | ... | @@ -42,6 +47,7 @@ test "truncate i0 to larger integer allowed and has comptime known result" { |
| 42 | 47 | } |
| 43 | 48 | |
| 44 | 49 | test "truncate.i0.literal" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 45 | 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 46 | 52 | |
| 47 | 53 | var z = @truncate(i0, 0); |
| ... | ... | @@ -49,6 +55,7 @@ test "truncate.i0.literal" { |
| 49 | 55 | } |
| 50 | 56 | |
| 51 | 57 | test "truncate.i0.const" { |
| 58 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 52 | 59 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 53 | 60 | |
| 54 | 61 | const c0: isize = 0; |
| ... | ... | @@ -57,6 +64,7 @@ test "truncate.i0.const" { |
| 57 | 64 | } |
| 58 | 65 | |
| 59 | 66 | test "truncate.i0.var" { |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 60 | 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 61 | 69 | |
| 62 | 70 | var d: i8 = 2; |
| ... | ... | @@ -65,6 +73,7 @@ test "truncate.i0.var" { |
| 65 | 73 | } |
| 66 | 74 | |
| 67 | 75 | test "truncate on comptime integer" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 68 | 77 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 69 | 78 | |
| 70 | 79 | var x = @truncate(u16, 9999); |
test/behavior/var_args.zig+3| ... | ... | @@ -25,6 +25,7 @@ fn readFirstVarArg(args: anytype) void { |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | test "send void arg to var args" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | 29 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 29 | 30 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 30 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -84,6 +85,7 @@ fn foo2(args: anytype) bool { |
| 84 | 85 | } |
| 85 | 86 | |
| 86 | 87 | test "array of var args functions" { |
| 88 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 87 | 89 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 88 | 90 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 89 | 91 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -93,6 +95,7 @@ test "array of var args functions" { |
| 93 | 95 | } |
| 94 | 96 | |
| 95 | 97 | test "pass zero length array to var args param" { |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 96 | 99 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 97 | 100 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 98 | 101 | 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 { |
| 17 | 17 | var case = ctx.exe("linux_aarch64 hello world", linux_aarch64); |
| 18 | 18 | // Regular old hello world |
| 19 | 19 | case.addCompareOutput( |
| 20 | \\pub export fn _start() noreturn { | |
| 20 | \\pub fn main() void { | |
| 21 | 21 | \\ print(); |
| 22 | \\ exit(); | |
| 23 | \\} | |
| 24 | \\ | |
| 25 | \\fn doNothing() void {} | |
| 26 | \\ | |
| 27 | \\fn answer() u64 { | |
| 28 | \\ return 0x1234abcd1234abcd; | |
| 29 | 22 | \\} |
| 30 | 23 | \\ |
| 31 | 24 | \\fn print() void { |
| ... | ... | @@ -38,16 +31,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 38 | 31 | \\ : "memory", "cc" |
| 39 | 32 | \\ ); |
| 40 | 33 | \\} |
| 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 | \\} | |
| 51 | 34 | , |
| 52 | 35 | "Hello, World!\n", |
| 53 | 36 | ); |
| ... | ... | @@ -102,6 +85,74 @@ pub fn addCases(ctx: *TestContext) !void { |
| 102 | 85 | , |
| 103 | 86 | "Hello, World!\n", |
| 104 | 87 | ); |
| 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 | ); | |
| 105 | 156 | } |
| 106 | 157 | |
| 107 | 158 | // macOS tests |