authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-27 01:43:37-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:24:39-07:00
log4fd8900337f363c87b916e3a96004f8f35845549
tree8366bb95ee83b325ba0f2e687d7cd16f39709743
parenta9ef0169432a6709ca59588050be703ab1a10357
signaturelock-open Commit is signed but in an unrecognized format.

riscv: rewrite "binOp"

Reorganize how the binOp and genBinOp functions work. I've spent quite a while here reading exactly through the spec and so many tests are enabled because of several critical issues the old design had. There are some regressions that will take a long time to figure out individually so I will ignore them for now, and pray they get fixed by themselves. When we're closer to 100% passing is when I will start diving into them one-by-one.

38 files changed, 1255 insertions(+), 1113 deletions(-)

src/arch/riscv64/CodeGen.zig+985-915
......@@ -22,6 +22,8 @@ const DW = std.dwarf;
2222const leb128 = std.leb;
2323const log = std.log.scoped(.riscv_codegen);
2424const tracking_log = std.log.scoped(.tracking);
25const verbose_tracking_log = std.log.scoped(.verbose_tracking);
26const wip_mir_log = std.log.scoped(.wip_mir);
2527const build_options = @import("build_options");
2628const codegen = @import("../../codegen.zig");
2729const Alignment = InternPool.Alignment;
......@@ -32,6 +34,8 @@ const DebugInfoOutput = codegen.DebugInfoOutput;
3234
3335const bits = @import("bits.zig");
3436const abi = @import("abi.zig");
37const Lower = @import("Lower.zig");
38
3539const Register = bits.Register;
3640const Immediate = bits.Immediate;
3741const Memory = bits.Memory;
......@@ -158,6 +162,14 @@ const MCValue = union(enum) {
158162 };
159163 }
160164
165 fn isRegister(mcv: MCValue) bool {
166 return switch (mcv) {
167 .register => true,
168 .register_offset => |reg_off| return reg_off.off == 0,
169 else => false,
170 };
171 }
172
161173 fn isMutable(mcv: MCValue) bool {
162174 return switch (mcv) {
163175 .none => unreachable,
......@@ -289,6 +301,7 @@ const Branch = struct {
289301
290302const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking);
291303const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking);
304
292305const InstTracking = struct {
293306 long: MCValue,
294307 short: MCValue,
......@@ -317,33 +330,37 @@ const InstTracking = struct {
317330 }, .short = result };
318331 }
319332
320 fn getReg(func: InstTracking) ?Register {
321 return func.short.getReg();
333 fn getReg(inst_tracking: InstTracking) ?Register {
334 return inst_tracking.short.getReg();
322335 }
323336
324 fn getRegs(func: *const InstTracking) []const Register {
325 return func.short.getRegs();
337 fn getRegs(inst_tracking: *const InstTracking) []const Register {
338 return inst_tracking.short.getRegs();
326339 }
327340
328 fn spill(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
329 if (std.meta.eql(func.long, func.short)) return; // Already spilled
341 fn spill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
342 if (std.meta.eql(inst_tracking.long, inst_tracking.short)) return; // Already spilled
330343 // Allocate or reuse frame index
331 switch (func.long) {
332 .none => func.long = try function.allocRegOrMem(inst, false),
344 switch (inst_tracking.long) {
345 .none => inst_tracking.long = try function.allocRegOrMem(
346 function.typeOfIndex(inst),
347 inst,
348 false,
349 ),
333350 .load_frame => {},
334 .reserved_frame => |index| func.long = .{ .load_frame = .{ .index = index } },
351 .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } },
335352 else => unreachable,
336353 }
337 tracking_log.debug("spill %{d} from {} to {}", .{ inst, func.short, func.long });
338 try function.genCopy(function.typeOfIndex(inst), func.long, func.short);
354 tracking_log.debug("spill %{d} from {} to {}", .{ inst, inst_tracking.short, inst_tracking.long });
355 try function.genCopy(function.typeOfIndex(inst), inst_tracking.long, inst_tracking.short);
339356 }
340357
341 fn reuseFrame(func: *InstTracking) void {
342 switch (func.long) {
343 .reserved_frame => |index| func.long = .{ .load_frame = .{ .index = index } },
358 fn reuseFrame(inst_tracking: *InstTracking) void {
359 switch (inst_tracking.long) {
360 .reserved_frame => |index| inst_tracking.long = .{ .load_frame = .{ .index = index } },
344361 else => {},
345362 }
346 func.short = switch (func.long) {
363 inst_tracking.short = switch (inst_tracking.long) {
347364 .none,
348365 .unreach,
349366 .undef,
......@@ -353,7 +370,7 @@ const InstTracking = struct {
353370 .lea_frame,
354371 .load_symbol,
355372 .lea_symbol,
356 => func.long,
373 => inst_tracking.long,
357374 .dead,
358375 .register,
359376 .register_pair,
......@@ -365,14 +382,14 @@ const InstTracking = struct {
365382 };
366383 }
367384
368 fn trackSpill(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
369 try function.freeValue(func.short);
370 func.reuseFrame();
371 tracking_log.debug("%{d} => {} (spilled)", .{ inst, func.* });
385 fn trackSpill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
386 try function.freeValue(inst_tracking.short);
387 inst_tracking.reuseFrame();
388 tracking_log.debug("%{d} => {} (spilled)", .{ inst, inst_tracking.* });
372389 }
373390
374 fn verifyMaterialize(func: InstTracking, target: InstTracking) void {
375 switch (func.long) {
391 fn verifyMaterialize(inst_tracking: InstTracking, target: InstTracking) void {
392 switch (inst_tracking.long) {
376393 .none,
377394 .unreach,
378395 .undef,
......@@ -381,7 +398,7 @@ const InstTracking = struct {
381398 .lea_frame,
382399 .load_symbol,
383400 .lea_symbol,
384 => assert(std.meta.eql(func.long, target.long)),
401 => assert(std.meta.eql(inst_tracking.long, target.long)),
385402 .load_frame,
386403 .reserved_frame,
387404 => switch (target.long) {
......@@ -402,73 +419,73 @@ const InstTracking = struct {
402419 }
403420
404421 fn materialize(
405 func: *InstTracking,
422 inst_tracking: *InstTracking,
406423 function: *Func,
407424 inst: Air.Inst.Index,
408425 target: InstTracking,
409426 ) !void {
410 func.verifyMaterialize(target);
411 try func.materializeUnsafe(function, inst, target);
427 inst_tracking.verifyMaterialize(target);
428 try inst_tracking.materializeUnsafe(function, inst, target);
412429 }
413430
414431 fn materializeUnsafe(
415 func: InstTracking,
432 inst_tracking: InstTracking,
416433 function: *Func,
417434 inst: Air.Inst.Index,
418435 target: InstTracking,
419436 ) !void {
420437 const ty = function.typeOfIndex(inst);
421 if ((func.long == .none or func.long == .reserved_frame) and target.long == .load_frame)
422 try function.genCopy(ty, target.long, func.short);
423 try function.genCopy(ty, target.short, func.short);
438 if ((inst_tracking.long == .none or inst_tracking.long == .reserved_frame) and target.long == .load_frame)
439 try function.genCopy(ty, target.long, inst_tracking.short);
440 try function.genCopy(ty, target.short, inst_tracking.short);
424441 }
425442
426 fn trackMaterialize(func: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void {
427 func.verifyMaterialize(target);
443 fn trackMaterialize(inst_tracking: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void {
444 inst_tracking.verifyMaterialize(target);
428445 // Don't clobber reserved frame indices
429 func.long = if (target.long == .none) switch (func.long) {
446 inst_tracking.long = if (target.long == .none) switch (inst_tracking.long) {
430447 .load_frame => |addr| .{ .reserved_frame = addr.index },
431 .reserved_frame => func.long,
448 .reserved_frame => inst_tracking.long,
432449 else => target.long,
433450 } else target.long;
434 func.short = target.short;
435 tracking_log.debug("%{d} => {} (materialize)", .{ inst, func.* });
451 inst_tracking.short = target.short;
452 tracking_log.debug("%{d} => {} (materialize)", .{ inst, inst_tracking.* });
436453 }
437454
438 fn resurrect(func: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void {
439 switch (func.short) {
455 fn resurrect(inst_tracking: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void {
456 switch (inst_tracking.short) {
440457 .dead => |die_generation| if (die_generation >= scope_generation) {
441 func.reuseFrame();
442 tracking_log.debug("%{d} => {} (resurrect)", .{ inst, func.* });
458 inst_tracking.reuseFrame();
459 tracking_log.debug("%{d} => {} (resurrect)", .{ inst, inst_tracking.* });
443460 },
444461 else => {},
445462 }
446463 }
447464
448 fn die(func: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
449 if (func.short == .dead) return;
450 try function.freeValue(func.short);
451 func.short = .{ .dead = function.scope_generation };
452 tracking_log.debug("%{d} => {} (death)", .{ inst, func.* });
465 fn die(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
466 if (inst_tracking.short == .dead) return;
467 try function.freeValue(inst_tracking.short);
468 inst_tracking.short = .{ .dead = function.scope_generation };
469 tracking_log.debug("%{d} => {} (death)", .{ inst, inst_tracking.* });
453470 }
454471
455472 fn reuse(
456 func: *InstTracking,
473 inst_tracking: *InstTracking,
457474 function: *Func,
458475 new_inst: ?Air.Inst.Index,
459476 old_inst: Air.Inst.Index,
460477 ) void {
461 func.short = .{ .dead = function.scope_generation };
478 inst_tracking.short = .{ .dead = function.scope_generation };
462479 if (new_inst) |inst|
463 tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, func.*, old_inst })
480 tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, inst_tracking.*, old_inst })
464481 else
465 tracking_log.debug("tmp => {} (reuse %{d})", .{ func.*, old_inst });
482 tracking_log.debug("tmp => {} (reuse %{d})", .{ inst_tracking.*, old_inst });
466483 }
467484
468 fn liveOut(func: *InstTracking, function: *Func, inst: Air.Inst.Index) void {
469 for (func.getRegs()) |reg| {
485 fn liveOut(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) void {
486 for (inst_tracking.getRegs()) |reg| {
470487 if (function.register_manager.isRegFree(reg)) {
471 tracking_log.debug("%{d} => {} (live-out)", .{ inst, func.* });
488 tracking_log.debug("%{d} => {} (live-out)", .{ inst, inst_tracking.* });
472489 continue;
473490 }
474491
......@@ -495,18 +512,18 @@ const InstTracking = struct {
495512 // Perform side-effects of freeValue manually.
496513 function.register_manager.freeReg(reg);
497514
498 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, func.*, tracked_inst });
515 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst });
499516 }
500517 }
501518
502519 pub fn format(
503 func: InstTracking,
520 inst_tracking: InstTracking,
504521 comptime _: []const u8,
505522 _: std.fmt.FormatOptions,
506523 writer: anytype,
507524 ) @TypeOf(writer).Error!void {
508 if (!std.meta.eql(func.long, func.short)) try writer.print("|{}| ", .{func.long});
509 try writer.print("{}", .{func.short});
525 if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try writer.print("|{}| ", .{inst_tracking.long});
526 try writer.print("{}", .{inst_tracking.short});
510527 }
511528};
512529
......@@ -741,6 +758,8 @@ pub fn generate(
741758 function.mir_extra.deinit(gpa);
742759 }
743760
761 wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
762
744763 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
745764 function.frame_allocs.set(
746765 @intFromEnum(FrameIndex.stack_frame),
......@@ -846,13 +865,133 @@ pub fn generate(
846865 }
847866}
848867
868const FormatWipMirData = struct {
869 func: *Func,
870 inst: Mir.Inst.Index,
871};
872fn formatWipMir(
873 data: FormatWipMirData,
874 comptime _: []const u8,
875 _: std.fmt.FormatOptions,
876 writer: anytype,
877) @TypeOf(writer).Error!void {
878 const comp = data.func.bin_file.comp;
879 const mod = comp.root_mod;
880 var lower = Lower{
881 .bin_file = data.func.bin_file,
882 .allocator = data.func.gpa,
883 .mir = .{
884 .instructions = data.func.mir_instructions.slice(),
885 .extra = data.func.mir_extra.items,
886 .frame_locs = data.func.frame_locs.slice(),
887 },
888 .cc = .Unspecified,
889 .src_loc = data.func.src_loc,
890 .output_mode = comp.config.output_mode,
891 .link_mode = comp.config.link_mode,
892 .pic = mod.pic,
893 };
894 var first = true;
895 for ((lower.lowerMir(data.inst) catch |err| switch (err) {
896 error.LowerFail => {
897 defer {
898 lower.err_msg.?.deinit(data.func.gpa);
899 lower.err_msg = null;
900 }
901 try writer.writeAll(lower.err_msg.?.msg);
902 return;
903 },
904 error.OutOfMemory, error.InvalidInstruction => |e| {
905 try writer.writeAll(switch (e) {
906 error.OutOfMemory => "Out of memory",
907 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
908 });
909 return;
910 },
911 else => |e| return e,
912 }).insts) |lowered_inst| {
913 if (!first) try writer.writeAll("\ndebug(wip_mir): ");
914 try writer.print(" | {}", .{lowered_inst});
915 first = false;
916 }
917}
918fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
919 return .{ .data = .{ .func = func, .inst = inst } };
920}
921
922const FormatDeclData = struct {
923 mod: *Module,
924 decl_index: InternPool.DeclIndex,
925};
926fn formatDecl(
927 data: FormatDeclData,
928 comptime _: []const u8,
929 _: std.fmt.FormatOptions,
930 writer: anytype,
931) @TypeOf(writer).Error!void {
932 try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer);
933}
934fn fmtDecl(func: *Func, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) {
935 return .{ .data = .{
936 .mod = func.bin_file.comp.module.?,
937 .decl_index = decl_index,
938 } };
939}
940
941const FormatAirData = struct {
942 func: *Func,
943 inst: Air.Inst.Index,
944};
945fn formatAir(
946 data: FormatAirData,
947 comptime _: []const u8,
948 _: std.fmt.FormatOptions,
949 writer: anytype,
950) @TypeOf(writer).Error!void {
951 @import("../../print_air.zig").dumpInst(
952 data.inst,
953 data.func.bin_file.comp.module.?,
954 data.func.air,
955 data.func.liveness,
956 );
957}
958fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
959 return .{ .data = .{ .func = func, .inst = inst } };
960}
961
962const FormatTrackingData = struct {
963 func: *Func,
964};
965fn formatTracking(
966 data: FormatTrackingData,
967 comptime _: []const u8,
968 _: std.fmt.FormatOptions,
969 writer: anytype,
970) @TypeOf(writer).Error!void {
971 var it = data.func.inst_tracking.iterator();
972 while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
973}
974fn fmtTracking(func: *Func) std.fmt.Formatter(formatTracking) {
975 return .{ .data = .{ .func = func } };
976}
977
849978fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
850979 const gpa = func.gpa;
851
852980 try func.mir_instructions.ensureUnusedCapacity(gpa, 1);
853
854981 const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len);
855982 func.mir_instructions.appendAssumeCapacity(inst);
983 if (inst.tag != .pseudo or switch (inst.ops) {
984 else => true,
985 .pseudo_dbg_prologue_end,
986 .pseudo_dbg_line_column,
987 .pseudo_dbg_epilogue_begin,
988 .pseudo_store_rm,
989 .pseudo_load_rm,
990 .pseudo_lea_rm,
991 .pseudo_mv,
992 .pseudo_dead,
993 => false,
994 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)}) else wip_mir_log.debug(" | uses-mem", .{});
856995 return result_index;
857996}
858997
......@@ -979,7 +1118,7 @@ fn gen(func: *Func) !void {
9791118 .r = .ra,
9801119 .m = .{
9811120 .base = .{ .frame = .ret_addr },
982 .mod = .{ .rm = .{ .size = .dword } },
1121 .mod = .{ .size = .dword, .unsigned = false },
9831122 },
9841123 } },
9851124 });
......@@ -990,7 +1129,7 @@ fn gen(func: *Func) !void {
9901129 .r = .ra,
9911130 .m = .{
9921131 .base = .{ .frame = .ret_addr },
993 .mod = .{ .rm = .{ .size = .dword } },
1132 .mod = .{ .size = .dword, .unsigned = false },
9941133 },
9951134 } },
9961135 });
......@@ -1001,7 +1140,7 @@ fn gen(func: *Func) !void {
10011140 .r = .s0,
10021141 .m = .{
10031142 .base = .{ .frame = .base_ptr },
1004 .mod = .{ .rm = .{ .size = .dword } },
1143 .mod = .{ .size = .dword, .unsigned = false },
10051144 },
10061145 } },
10071146 });
......@@ -1012,7 +1151,7 @@ fn gen(func: *Func) !void {
10121151 .r = .s0,
10131152 .m = .{
10141153 .base = .{ .frame = .base_ptr },
1015 .mod = .{ .rm = .{ .size = .dword } },
1154 .mod = .{ .size = .dword, .unsigned = false },
10161155 },
10171156 } },
10181157 });
......@@ -1072,36 +1211,47 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
10721211
10731212 for (body) |inst| {
10741213 if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue;
1214 wip_mir_log.debug("{}", .{func.fmtAir(inst)});
1215 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
10751216
10761217 const old_air_bookkeeping = func.air_bookkeeping;
10771218 try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1);
1078 switch (air_tags[@intFromEnum(inst)]) {
1219 const tag: Air.Inst.Tag = air_tags[@intFromEnum(inst)];
1220 switch (tag) {
10791221 // zig fmt: off
1080 .ptr_add => try func.airPtrArithmetic(inst, .ptr_add),
1081 .ptr_sub => try func.airPtrArithmetic(inst, .ptr_sub),
1222 .add,
1223 .add_wrap,
1224 .sub,
1225 .sub_wrap,
10821226
1083 .add => try func.airBinOp(inst, .add),
1084 .sub => try func.airBinOp(inst, .sub),
1227 .mul,
1228 .mul_wrap,
1229 .div_trunc,
10851230
1086 .add_safe,
1087 .sub_safe,
1088 .mul_safe,
1089 => return func.fail("TODO implement safety_checked_instructions", .{}),
1231 .shl, .shl_exact,
1232 .shr, .shr_exact,
10901233
1091 .add_wrap => try func.airAddWrap(inst),
1092 .add_sat => try func.airAddSat(inst),
1093 .sub_wrap => try func.airSubWrap(inst),
1094 .sub_sat => try func.airSubSat(inst),
1095 .mul => try func.airMul(inst),
1096 .mul_wrap => try func.airMulWrap(inst),
1097 .mul_sat => try func.airMulSat(inst),
1098 .rem => try func.airRem(inst),
1099 .mod => try func.airMod(inst),
1100 .shl, .shl_exact => try func.airShl(inst),
1101 .shl_sat => try func.airShlSat(inst),
1102 .min => try func.airMinMax(inst, .min),
1103 .max => try func.airMinMax(inst, .max),
1104 .slice => try func.airSlice(inst),
1234 .bool_and,
1235 .bool_or,
1236 .bit_and,
1237 .bit_or,
1238
1239 .xor,
1240
1241 .min,
1242 .max,
1243 => try func.airBinOp(inst, tag),
1244
1245
1246 .ptr_add,
1247 .ptr_sub => try func.airPtrArithmetic(inst, tag),
1248
1249 .rem,
1250 .mod,
1251 .div_float,
1252 .div_floor,
1253 .div_exact,
1254 => return func.fail("TODO: {s}", .{@tagName(tag)}),
11051255
11061256 .sqrt,
11071257 .sin,
......@@ -1124,24 +1274,33 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
11241274 .mul_with_overflow => try func.airMulWithOverflow(inst),
11251275 .shl_with_overflow => try func.airShlWithOverflow(inst),
11261276
1127 .div_float, .div_trunc, .div_floor, .div_exact => try func.airDiv(inst),
11281277
1129 .cmp_lt => try func.airCmp(inst),
1130 .cmp_lte => try func.airCmp(inst),
1131 .cmp_eq => try func.airCmp(inst),
1132 .cmp_gte => try func.airCmp(inst),
1133 .cmp_gt => try func.airCmp(inst),
1134 .cmp_neq => try func.airCmp(inst),
1278 .add_sat => try func.airAddSat(inst),
1279 .sub_sat => try func.airSubSat(inst),
1280 .mul_sat => try func.airMulSat(inst),
1281 .shl_sat => try func.airShlSat(inst),
1282
1283 .add_safe,
1284 .sub_safe,
1285 .mul_safe,
1286 => return func.fail("TODO implement safety_checked_instructions", .{}),
1287
1288 .cmp_lt,
1289 .cmp_lte,
1290 .cmp_eq,
1291 .cmp_gte,
1292 .cmp_gt,
1293 .cmp_neq,
1294 => try func.airCmp(inst, tag),
11351295
11361296 .cmp_vector => try func.airCmpVector(inst),
11371297 .cmp_lt_errors_len => try func.airCmpLtErrorsLen(inst),
11381298
1139 .bool_and => try func.airBoolOp(inst),
1140 .bool_or => try func.airBoolOp(inst),
1141 .bit_and => try func.airBitAnd(inst),
1142 .bit_or => try func.airBitOr(inst),
1143 .xor => try func.airXor(inst),
1144 .shr, .shr_exact => try func.airShr(inst),
1299 .slice => try func.airSlice(inst),
1300 .array_to_slice => try func.airArrayToSlice(inst),
1301
1302 .slice_ptr => try func.airSlicePtr(inst),
1303 .slice_len => try func.airSliceLen(inst),
11451304
11461305 .alloc => try func.airAlloc(inst),
11471306 .ret_ptr => try func.airRetPtr(inst),
......@@ -1181,7 +1340,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
11811340 .store_safe => try func.airStore(inst, true),
11821341 .struct_field_ptr=> try func.airStructFieldPtr(inst),
11831342 .struct_field_val=> try func.airStructFieldVal(inst),
1184 .array_to_slice => try func.airArrayToSlice(inst),
11851343 .float_from_int => try func.airFloatFromInt(inst),
11861344 .int_from_float => try func.airIntFromFloat(inst),
11871345 .cmpxchg_strong => try func.airCmpxchg(inst),
......@@ -1229,7 +1387,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
12291387 .atomic_store_monotonic => try func.airAtomicStore(inst, .monotonic),
12301388 .atomic_store_release => try func.airAtomicStore(inst, .release),
12311389 .atomic_store_seq_cst => try func.airAtomicStore(inst, .seq_cst),
1232
12331390 .struct_field_ptr_index_0 => try func.airStructFieldPtrIndex(inst, 0),
12341391 .struct_field_ptr_index_1 => try func.airStructFieldPtrIndex(inst, 1),
12351392 .struct_field_ptr_index_2 => try func.airStructFieldPtrIndex(inst, 2),
......@@ -1238,15 +1395,15 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
12381395 .field_parent_ptr => try func.airFieldParentPtr(inst),
12391396
12401397 .switch_br => try func.airSwitchBr(inst),
1241 .slice_ptr => try func.airSlicePtr(inst),
1242 .slice_len => try func.airSliceLen(inst),
12431398
12441399 .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst),
12451400 .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst),
12461401
12471402 .array_elem_val => try func.airArrayElemVal(inst),
1403
12481404 .slice_elem_val => try func.airSliceElemVal(inst),
12491405 .slice_elem_ptr => try func.airSliceElemPtr(inst),
1406
12501407 .ptr_elem_val => try func.airPtrElemVal(inst),
12511408 .ptr_elem_ptr => try func.airPtrElemPtr(inst),
12521409
......@@ -1330,6 +1487,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13301487 }
13311488 }
13321489 }
1490 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
13331491}
13341492
13351493fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void {
......@@ -1563,7 +1721,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
15631721 .i_type = .{
15641722 .rd = reg,
15651723 .rs1 = reg,
1566 .imm12 = Immediate.s(shift),
1724 .imm12 = Immediate.u(shift),
15671725 },
15681726 },
15691727 });
......@@ -1574,25 +1732,49 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
15741732 .i_type = .{
15751733 .rd = reg,
15761734 .rs1 = reg,
1577 .imm12 = Immediate.s(shift),
1735 .imm12 = Immediate.u(shift),
15781736 },
15791737 },
15801738 });
15811739 },
15821740 .unsigned => {
15831741 const mask = ~@as(u64, 0) >> shift;
1584 const tmp_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = mask });
1585 _ = try func.addInst(.{
1586 .tag = .@"and",
1587 .ops = .rrr,
1588 .data = .{
1589 .r_type = .{
1590 .rd = reg,
1591 .rs1 = reg,
1592 .rs2 = tmp_reg,
1742 if (mask < 256) {
1743 _ = try func.addInst(.{
1744 .tag = .andi,
1745 .ops = .rri,
1746 .data = .{
1747 .i_type = .{
1748 .rd = reg,
1749 .rs1 = reg,
1750 .imm12 = Immediate.u(@intCast(mask)),
1751 },
15931752 },
1594 },
1595 });
1753 });
1754 } else {
1755 _ = try func.addInst(.{
1756 .tag = .slli,
1757 .ops = .rri,
1758 .data = .{
1759 .i_type = .{
1760 .rd = reg,
1761 .rs1 = reg,
1762 .imm12 = Immediate.u(shift),
1763 },
1764 },
1765 });
1766 _ = try func.addInst(.{
1767 .tag = .srli,
1768 .ops = .rri,
1769 .data = .{
1770 .i_type = .{
1771 .rd = reg,
1772 .rs1 = reg,
1773 .imm12 = Immediate.u(shift),
1774 },
1775 },
1776 });
1777 }
15961778 },
15971779 }
15981780}
......@@ -1673,9 +1855,8 @@ fn regTempClassForType(func: *Func, ty: Type) RegisterManager.RegisterBitSet {
16731855 };
16741856}
16751857
1676fn allocRegOrMem(func: *Func, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
1858fn allocRegOrMem(func: *Func, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
16771859 const zcu = func.bin_file.comp.module.?;
1678 const elem_ty = func.typeOfIndex(inst);
16791860
16801861 const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse {
16811862 return func.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)});
......@@ -1714,66 +1895,15 @@ fn allocReg(func: *Func, reg_class: abi.RegisterClass) !struct { Register, Regis
17141895 return .{ reg, lock };
17151896}
17161897
1717const PromoteOptions = struct {
1718 /// zeroes out the register before loading in the operand
1719 ///
1720 /// if the operand is already a register, it will truncate with 0
1721 zero: bool = false,
1722};
1723
17241898/// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already
17251899/// a register, in which case it will return a possible lock to that register.
1726fn promoteReg(func: *Func, ty: Type, operand: MCValue, options: PromoteOptions) !struct { Register, ?RegisterLock } {
1727 const zcu = func.bin_file.comp.module.?;
1728 const bit_size = ty.bitSize(zcu);
1729
1900fn promoteReg(func: *Func, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } {
17301901 if (operand == .register) {
17311902 const op_reg = operand.register;
1732 if (options.zero and op_reg.class() == .int) {
1733 // we make sure to emit the truncate manually because binOp will call this function
1734 // and it could cause an infinite loop
1735
1736 _ = try func.addInst(.{
1737 .tag = .slli,
1738 .ops = .rri,
1739 .data = .{
1740 .i_type = .{
1741 .imm12 = Immediate.u(64 - bit_size),
1742 .rd = op_reg,
1743 .rs1 = op_reg,
1744 },
1745 },
1746 });
1747
1748 _ = try func.addInst(.{
1749 .tag = .srli,
1750 .ops = .rri,
1751 .data = .{
1752 .i_type = .{
1753 .imm12 = Immediate.u(64 - bit_size),
1754 .rd = op_reg,
1755 .rs1 = op_reg,
1756 },
1757 },
1758 });
1759 }
1760
17611903 return .{ op_reg, func.register_manager.lockReg(operand.register) };
17621904 }
17631905
17641906 const reg, const lock = try func.allocReg(func.typeRegClass(ty));
1765
1766 if (options.zero and reg.class() == .int) {
1767 _ = try func.addInst(.{
1768 .tag = .pseudo,
1769 .ops = .pseudo_mv,
1770 .data = .{ .rr = .{
1771 .rd = reg,
1772 .rs = .zero,
1773 } },
1774 });
1775 }
1776
17771907 try func.genSetReg(ty, reg, operand);
17781908 return .{ reg, lock };
17791909}
......@@ -1793,14 +1923,19 @@ fn elemOffset(func: *Func, index_ty: Type, index: MCValue, elem_size: u64) !Regi
17931923 const lock = func.register_manager.lockRegAssumeUnused(reg);
17941924 defer func.register_manager.unlockReg(lock);
17951925
1796 const result = try func.binOp(
1926 const result_reg, const result_lock = try func.allocReg(.int);
1927 defer func.register_manager.unlockReg(result_lock);
1928
1929 try func.genBinOp(
17971930 .mul,
17981931 .{ .register = reg },
17991932 index_ty,
18001933 .{ .immediate = elem_size },
18011934 index_ty,
1935 result_reg,
18021936 );
1803 break :blk result.register;
1937
1938 break :blk result_reg;
18041939 },
18051940 }
18061941 };
......@@ -1892,7 +2027,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void {
18922027 math.divCeil(u16, dst_int_info.bits, 64) catch unreachable ==
18932028 math.divCeil(u32, src_storage_bits, 64) catch unreachable and
18942029 func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
1895 const dst_mcv = try func.allocRegOrMem(inst, true);
2030 const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
18962031 try func.genCopy(min_ty, dst_mcv, src_mcv);
18972032 break :dst dst_mcv;
18982033 };
......@@ -1904,7 +2039,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void {
19042039 break :result null; // TODO
19052040
19062041 break :result dst_mcv;
1907 } orelse return func.fail("TODO implement airIntCast from {} to {}", .{
2042 } orelse return func.fail("TODO: implement airIntCast from {} to {}", .{
19082043 src_ty.fmt(zcu), dst_ty.fmt(zcu),
19092044 });
19102045
......@@ -1948,7 +2083,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
19482083 if (func.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register)
19492084 operand.register
19502085 else
1951 (try func.allocRegOrMem(inst, true)).register;
2086 (try func.allocRegOrMem(func.typeOfIndex(inst), inst, true)).register;
19522087
19532088 _ = try func.addInst(.{
19542089 .tag = .pseudo,
......@@ -1970,106 +2105,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
19702105 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
19712106}
19722107
1973fn airMinMax(
1974 func: *Func,
1975 inst: Air.Inst.Index,
1976 comptime tag: enum {
1977 max,
1978 min,
1979 },
1980) !void {
1981 const zcu = func.bin_file.comp.module.?;
1982 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1983
1984 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
1985 const lhs = try func.resolveInst(bin_op.lhs);
1986 const rhs = try func.resolveInst(bin_op.rhs);
1987 const lhs_ty = func.typeOf(bin_op.lhs);
1988 const rhs_ty = func.typeOf(bin_op.rhs);
1989
1990 const int_info = lhs_ty.intInfo(zcu);
1991
1992 if (int_info.bits > 64) return func.fail("TODO: > 64 bit @min", .{});
1993
1994 const lhs_reg, const lhs_lock = blk: {
1995 if (lhs == .register) break :blk .{ lhs.register, func.register_manager.lockReg(lhs.register) };
1996
1997 const lhs_reg, const lhs_lock = try func.allocReg(.int);
1998 try func.genSetReg(lhs_ty, lhs_reg, lhs);
1999 break :blk .{ lhs_reg, lhs_lock };
2000 };
2001 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2002
2003 const rhs_reg, const rhs_lock = blk: {
2004 if (rhs == .register) break :blk .{ rhs.register, func.register_manager.lockReg(rhs.register) };
2005
2006 const rhs_reg, const rhs_lock = try func.allocReg(.int);
2007 try func.genSetReg(rhs_ty, rhs_reg, rhs);
2008 break :blk .{ rhs_reg, rhs_lock };
2009 };
2010 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2011
2012 const mask_reg, const mask_lock = try func.allocReg(.int);
2013 defer func.register_manager.unlockReg(mask_lock);
2014
2015 const result_reg, const result_lock = try func.allocReg(.int);
2016 defer func.register_manager.unlockReg(result_lock);
2017
2018 _ = try func.addInst(.{
2019 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2020 .ops = .rrr,
2021 .data = .{ .r_type = .{
2022 .rd = mask_reg,
2023 .rs1 = lhs_reg,
2024 .rs2 = rhs_reg,
2025 } },
2026 });
2027
2028 _ = try func.addInst(.{
2029 .tag = .sub,
2030 .ops = .rrr,
2031 .data = .{ .r_type = .{
2032 .rd = mask_reg,
2033 .rs1 = .zero,
2034 .rs2 = mask_reg,
2035 } },
2036 });
2037
2038 _ = try func.addInst(.{
2039 .tag = .xor,
2040 .ops = .rrr,
2041 .data = .{ .r_type = .{
2042 .rd = result_reg,
2043 .rs1 = lhs_reg,
2044 .rs2 = rhs_reg,
2045 } },
2046 });
2047
2048 _ = try func.addInst(.{
2049 .tag = .@"and",
2050 .ops = .rrr,
2051 .data = .{ .r_type = .{
2052 .rd = mask_reg,
2053 .rs1 = result_reg,
2054 .rs2 = mask_reg,
2055 } },
2056 });
2057
2058 _ = try func.addInst(.{
2059 .tag = .xor,
2060 .ops = .rrr,
2061 .data = .{ .r_type = .{
2062 .rd = result_reg,
2063 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
2064 .rs2 = mask_reg,
2065 } },
2066 });
2067
2068 break :result .{ .register = result_reg };
2069 };
2070 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2071}
2072
20732108fn airSlice(func: *Func, inst: Air.Inst.Index) !void {
20742109 const zcu = func.bin_file.comp.module.?;
20752110 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
......@@ -2094,417 +2129,487 @@ fn airSlice(func: *Func, inst: Air.Inst.Index) !void {
20942129}
20952130
20962131fn airBinOp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2132 const zcu = func.bin_file.comp.module.?;
20972133 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2098 const lhs = try func.resolveInst(bin_op.lhs);
2099 const rhs = try func.resolveInst(bin_op.rhs);
2100 const lhs_ty = func.typeOf(bin_op.lhs);
2101 const rhs_ty = func.typeOf(bin_op.rhs);
2134 const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
21022135
2103 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2104 break :result try func.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
2105 };
2106 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2136 const dst_ty = func.typeOfIndex(inst);
2137 if (dst_ty.isAbiInt(zcu)) {
2138 const abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
2139 const bit_size: u32 = @intCast(dst_ty.bitSize(zcu));
2140 if (abi_size * 8 > bit_size) {
2141 const dst_lock = switch (dst_mcv) {
2142 .register => |dst_reg| func.register_manager.lockRegAssumeUnused(dst_reg),
2143 else => null,
2144 };
2145 defer if (dst_lock) |lock| func.register_manager.unlockReg(lock);
2146
2147 if (dst_mcv.isRegister()) {
2148 try func.truncateRegister(dst_ty, dst_mcv.getReg().?);
2149 } else {
2150 const tmp_reg, const tmp_lock = try func.allocReg(.int);
2151 defer func.register_manager.unlockReg(tmp_lock);
2152
2153 const hi_ty = try zcu.intType(.unsigned, @intCast((dst_ty.bitSize(zcu) - 1) % 64 + 1));
2154 const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref();
2155 try func.genSetReg(hi_ty, tmp_reg, hi_mcv);
2156 try func.truncateRegister(dst_ty, tmp_reg);
2157 try func.genCopy(hi_ty, hi_mcv, .{ .register = tmp_reg });
2158 }
2159 }
2160 }
2161
2162 return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
21072163}
21082164
21092165fn binOp(
2166 func: *Func,
2167 maybe_inst: ?Air.Inst.Index,
2168 air_tag: Air.Inst.Tag,
2169 lhs_air: Air.Inst.Ref,
2170 rhs_air: Air.Inst.Ref,
2171) !MCValue {
2172 _ = maybe_inst;
2173 const zcu = func.bin_file.comp.module.?;
2174 const lhs_ty = func.typeOf(lhs_air);
2175 const rhs_ty = func.typeOf(rhs_air);
2176
2177 if (lhs_ty.isRuntimeFloat()) libcall: {
2178 const float_bits = lhs_ty.floatBits(func.target.*);
2179 const type_needs_libcall = switch (float_bits) {
2180 16 => true,
2181 32, 64 => false,
2182 80, 128 => true,
2183 else => unreachable,
2184 };
2185 switch (air_tag) {
2186 .rem, .mod => {},
2187 else => if (!type_needs_libcall) break :libcall,
2188 }
2189 return func.fail("binOp libcall runtime-float ops", .{});
2190 }
2191
2192 if (lhs_ty.bitSize(zcu) > 64) return func.fail("TODO: binOp >= 64 bits", .{});
2193
2194 const lhs_mcv = try func.resolveInst(lhs_air);
2195 const rhs_mcv = try func.resolveInst(rhs_air);
2196
2197 const class_for_dst_ty: abi.RegisterClass = switch (air_tag) {
2198 // will always return int register no matter the input
2199 .cmp_eq,
2200 .cmp_neq,
2201 .cmp_lt,
2202 .cmp_lte,
2203 .cmp_gt,
2204 .cmp_gte,
2205 => .int,
2206
2207 else => func.typeRegClass(lhs_ty),
2208 };
2209
2210 const dst_reg, const dst_lock = try func.allocReg(class_for_dst_ty);
2211 defer func.register_manager.unlockReg(dst_lock);
2212
2213 try func.genBinOp(
2214 air_tag,
2215 lhs_mcv,
2216 lhs_ty,
2217 rhs_mcv,
2218 rhs_ty,
2219 dst_reg,
2220 );
2221
2222 return .{ .register = dst_reg };
2223}
2224
2225/// Does the same thing as binOp however is meant to be used internally to the backend.
2226///
2227/// The `dst_reg` argument is meant to be caller-locked. Asserts that the binOp result can be
2228/// fit into the register.
2229///
2230/// Assumes that the `dst_reg` class is correct.
2231fn genBinOp(
21102232 func: *Func,
21112233 tag: Air.Inst.Tag,
2112 lhs: MCValue,
2234 lhs_mcv: MCValue,
21132235 lhs_ty: Type,
2114 rhs: MCValue,
2236 rhs_mcv: MCValue,
21152237 rhs_ty: Type,
2116) InnerError!MCValue {
2238 dst_reg: Register,
2239) !void {
21172240 const zcu = func.bin_file.comp.module.?;
2241 const bit_size = lhs_ty.bitSize(zcu);
2242 assert(bit_size <= 64);
2243
2244 const is_unsigned = lhs_ty.isUnsignedInt(zcu);
2245
2246 const lhs_reg, const maybe_lhs_lock = try func.promoteReg(lhs_ty, lhs_mcv);
2247 const rhs_reg, const maybe_rhs_lock = try func.promoteReg(rhs_ty, rhs_mcv);
2248
2249 defer if (maybe_lhs_lock) |lock| func.register_manager.unlockReg(lock);
2250 defer if (maybe_rhs_lock) |lock| func.register_manager.unlockReg(lock);
21182251
21192252 switch (tag) {
2120 // Arithmetic operations on integers and floats
21212253 .add,
2254 .add_wrap,
21222255 .sub,
2256 .sub_wrap,
21232257 .mul,
2124 .div_float,
2125 .cmp_eq,
2126 .cmp_neq,
2127 .cmp_gt,
2128 .cmp_gte,
2129 .cmp_lt,
2130 .cmp_lte,
2258 .mul_wrap,
21312259 => {
2132 assert(lhs_ty.eql(rhs_ty, zcu));
2133 switch (lhs_ty.zigTypeTag(zcu)) {
2134 .Float => {
2135 const float_bits = lhs_ty.floatBits(zcu.getTarget());
2136 const float_reg_bits: u32 = if (func.hasFeature(.d)) 64 else 32;
2137 if (float_bits <= float_reg_bits) {
2138 return func.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty);
2139 } else {
2140 return func.fail("TODO: binary operations for floats with bits > {d}", .{float_reg_bits});
2141 }
2142 },
2143 .Vector => return func.fail("TODO binary operations on vectors", .{}),
2144 .Int, .Enum, .ErrorSet => {
2145 const int_info = lhs_ty.intInfo(zcu);
2146 if (int_info.bits <= 64) {
2147 return func.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
2148 } else {
2149 return func.fail("TODO binary operations on int with bits > 64", .{});
2150 }
2151 },
2152 else => |x| return func.fail("TOOD: binOp {s}", .{@tagName(x)}),
2153 }
2154 },
2260 if (!math.isPowerOfTwo(bit_size))
2261 return func.fail(
2262 "TODO: genBinOp {s} non-pow 2, found {}",
2263 .{ @tagName(tag), bit_size },
2264 );
21552265
2156 .ptr_add,
2157 .ptr_sub,
2158 => {
21592266 switch (lhs_ty.zigTypeTag(zcu)) {
2160 .Pointer => {
2161 const ptr_ty = lhs_ty;
2162 const elem_ty = switch (ptr_ty.ptrSize(zcu)) {
2163 .One => ptr_ty.childType(zcu).childType(zcu), // ptr to array, so get array element type
2164 else => ptr_ty.childType(zcu),
2165 };
2166 const elem_size = elem_ty.abiSize(zcu);
2167
2168 if (elem_size == 1) {
2169 const base_tag: Air.Inst.Tag = switch (tag) {
2170 .ptr_add => .add,
2171 .ptr_sub => .sub,
2267 .Int => {
2268 const mir_tag: Mir.Inst.Tag = switch (tag) {
2269 .add, .add_wrap => switch (bit_size) {
2270 8, 16, 64 => .add,
2271 32 => .addw,
21722272 else => unreachable,
2173 };
2273 },
2274 .sub, .sub_wrap => switch (bit_size) {
2275 8, 16, 32 => .subw,
2276 64 => .sub,
2277 else => unreachable,
2278 },
2279 .mul, .mul_wrap => switch (bit_size) {
2280 8, 16, 64 => .mul,
2281 32 => .mulw,
2282 else => unreachable,
2283 },
2284 else => unreachable,
2285 };
21742286
2175 return try func.binOpRegister(base_tag, lhs, lhs_ty, rhs, rhs_ty);
2176 } else {
2177 const offset = try func.binOp(
2178 .mul,
2179 rhs,
2180 Type.usize,
2181 .{ .immediate = elem_size },
2182 Type.usize,
2183 );
2287 _ = try func.addInst(.{
2288 .tag = mir_tag,
2289 .ops = .rrr,
2290 .data = .{
2291 .r_type = .{
2292 .rd = dst_reg,
2293 .rs1 = lhs_reg,
2294 .rs2 = rhs_reg,
2295 },
2296 },
2297 });
21842298
2185 const addr = try func.binOp(
2186 tag,
2187 lhs,
2188 Type.manyptr_u8,
2189 offset,
2190 Type.usize,
2191 );
2192 return addr;
2299 // truncate when the instruction is larger than the bit size.
2300 switch (bit_size) {
2301 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2302 32 => {}, // addw/subw affects the first 32-bits
2303 64 => {}, // add/sub affects the entire register
2304 else => unreachable,
21932305 }
21942306 },
2195 else => unreachable,
2196 }
2197 },
2307 .Float => {
2308 const mir_tag: Mir.Inst.Tag = switch (tag) {
2309 .add => switch (bit_size) {
2310 32 => .fadds,
2311 64 => .faddd,
2312 else => unreachable,
2313 },
2314 .sub => switch (bit_size) {
2315 32 => .fsubs,
2316 64 => .fsubd,
2317 else => unreachable,
2318 },
2319 .mul => switch (bit_size) {
2320 32 => .fmuls,
2321 64 => .fmuld,
2322 else => unreachable,
2323 },
2324 else => unreachable,
2325 };
21982326
2199 // These instructions have unsymteric bit sizes on RHS and LHS.
2200 .shr,
2201 .shl,
2202 => {
2203 switch (lhs_ty.zigTypeTag(zcu)) {
2204 .Float => return func.fail("TODO binary operations on floats", .{}),
2205 .Vector => return func.fail("TODO binary operations on vectors", .{}),
2206 .Int => {
2207 const int_info = lhs_ty.intInfo(zcu);
2208 if (int_info.bits <= 64) {
2209 return func.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty);
2210 } else {
2211 return func.fail("TODO binary operations on int with bits > 64", .{});
2212 }
2327 _ = try func.addInst(.{
2328 .tag = mir_tag,
2329 .ops = .rrr,
2330 .data = .{
2331 .r_type = .{
2332 .rd = dst_reg,
2333 .rs1 = lhs_reg,
2334 .rs2 = rhs_reg,
2335 },
2336 },
2337 });
22132338 },
22142339 else => unreachable,
22152340 }
22162341 },
2217 else => return func.fail("TODO binOp {}", .{tag}),
2218 }
2219}
2220
2221fn binOpRegister(
2222 func: *Func,
2223 tag: Air.Inst.Tag,
2224 lhs: MCValue,
2225 lhs_ty: Type,
2226 rhs: MCValue,
2227 rhs_ty: Type,
2228) !MCValue {
2229 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{ .zero = true });
2230 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2231
2232 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{ .zero = true });
2233 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
22342342
2235 const dest_reg, const dest_lock = try func.allocReg(.int);
2236 defer func.register_manager.unlockReg(dest_lock);
2237
2238 const mir_tag: Mir.Inst.Tag = switch (tag) {
2239 .add => .add,
2240 .sub => .sub,
2241 .mul => .mul,
2242
2243 .shl => .sllw,
2244 .shr => .srlw,
2245
2246 .cmp_eq,
2247 .cmp_neq,
2248 .cmp_gt,
2249 .cmp_gte,
2250 .cmp_lt,
2251 .cmp_lte,
2252 => .pseudo,
2343 .ptr_add,
2344 .ptr_sub,
2345 => {
2346 const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg });
2347 const tmp_mcv = MCValue{ .register = tmp_reg };
2348 const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg);
2349 defer func.register_manager.unlockReg(tmp_lock);
2350
2351 // RISC-V has no immediate mul, so we copy the size to a temporary register
2352 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
2353 const elem_size_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = elem_size });
2354
2355 try func.genBinOp(
2356 .mul,
2357 tmp_mcv,
2358 rhs_ty,
2359 .{ .register = elem_size_reg },
2360 Type.usize,
2361 tmp_reg,
2362 );
22532363
2254 else => return func.fail("TODO: binOpRegister {s}", .{@tagName(tag)}),
2255 };
2364 try func.genBinOp(
2365 switch (tag) {
2366 .ptr_add => .add,
2367 .ptr_sub => .sub,
2368 else => unreachable,
2369 },
2370 lhs_mcv,
2371 Type.usize, // we know it's a pointer, so it'll be usize.
2372 tmp_mcv,
2373 Type.usize,
2374 dst_reg,
2375 );
2376 },
22562377
2257 switch (mir_tag) {
2258 .add,
2259 .sub,
2260 .mul,
2261 .sllw,
2262 .srlw,
2378 .bit_and,
2379 .bit_or,
2380 .bool_and,
2381 .bool_or,
22632382 => {
22642383 _ = try func.addInst(.{
2265 .tag = mir_tag,
2384 .tag = switch (tag) {
2385 .bit_and, .bool_and => .@"and",
2386 .bit_or, .bool_or => .@"or",
2387 else => unreachable,
2388 },
22662389 .ops = .rrr,
22672390 .data = .{
22682391 .r_type = .{
2269 .rd = dest_reg,
2392 .rd = dst_reg,
22702393 .rs1 = lhs_reg,
22712394 .rs2 = rhs_reg,
22722395 },
22732396 },
22742397 });
2398
2399 switch (tag) {
2400 .bool_and,
2401 .bool_or,
2402 => try func.truncateRegister(Type.bool, dst_reg),
2403 else => {},
2404 }
22752405 },
22762406
2277 .pseudo => {
2278 const pseudo_op = switch (tag) {
2279 .cmp_eq,
2280 .cmp_neq,
2281 .cmp_gt,
2282 .cmp_gte,
2283 .cmp_lt,
2284 .cmp_lte,
2285 => .pseudo_compare,
2407 .div_trunc,
2408 => {
2409 if (!math.isPowerOfTwo(bit_size))
2410 return func.fail(
2411 "TODO: genBinOp {s} non-pow 2, found {}",
2412 .{ @tagName(tag), bit_size },
2413 );
2414
2415 const mir_tag: Mir.Inst.Tag = switch (tag) {
2416 .div_trunc => switch (bit_size) {
2417 8, 16, 32 => if (is_unsigned) .divuw else .divw,
2418 64 => if (is_unsigned) .divu else .div,
2419 else => unreachable,
2420 },
22862421 else => unreachable,
22872422 };
22882423
22892424 _ = try func.addInst(.{
2290 .tag = .pseudo,
2291 .ops = pseudo_op,
2425 .tag = mir_tag,
2426 .ops = .rrr,
22922427 .data = .{
2293 .compare = .{
2294 .rd = dest_reg,
2428 .r_type = .{
2429 .rd = dst_reg,
22952430 .rs1 = lhs_reg,
22962431 .rs2 = rhs_reg,
2297 .op = switch (tag) {
2298 .cmp_eq => .eq,
2299 .cmp_neq => .neq,
2300 .cmp_gt => .gt,
2301 .cmp_gte => .gte,
2302 .cmp_lt => .lt,
2303 .cmp_lte => .lte,
2304 else => unreachable,
2305 },
2306 .size = func.memSize(lhs_ty),
23072432 },
23082433 },
23092434 });
2310 },
2311
2312 else => unreachable,
2313 }
2314
2315 return MCValue{ .register = dest_reg };
2316}
2317
2318fn binOpFloat(
2319 func: *Func,
2320 tag: Air.Inst.Tag,
2321 lhs: MCValue,
2322 lhs_ty: Type,
2323 rhs: MCValue,
2324 rhs_ty: Type,
2325) !MCValue {
2326 const zcu = func.bin_file.comp.module.?;
2327 const float_bits = lhs_ty.floatBits(zcu.getTarget());
2328
2329 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{});
2330 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2331
2332 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{});
2333 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2334
2335 const mir_tag: Mir.Inst.Tag = switch (tag) {
2336 .add => if (float_bits == 32) .fadds else .faddd,
2337 .sub => if (float_bits == 32) .fsubs else .fsubd,
2338 .mul => if (float_bits == 32) .fmuls else .fmuld,
2339 .div_float => if (float_bits == 32) .fdivs else .fdivd,
23402435
2341 .cmp_eq,
2342 .cmp_neq,
2343 .cmp_gt,
2344 .cmp_gte,
2345 .cmp_lt,
2346 .cmp_lte,
2347 => .pseudo,
2348
2349 else => return func.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}),
2350 };
2436 if (!is_unsigned) {
2437 // truncate when the instruction is larger than the bit size.
2438 switch (bit_size) {
2439 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2440 32 => {}, // divw affects the first 32-bits
2441 64 => {}, // div affects the entire register
2442 else => unreachable,
2443 }
2444 }
2445 },
23512446
2352 const return_class: abi.RegisterClass = switch (tag) {
2353 .add,
2354 .sub,
2355 .mul,
2356 .div_float,
2357 => .float,
2447 .shr,
2448 .shr_exact,
2449 .shl,
2450 .shl_exact,
2451 => {
2452 if (!math.isPowerOfTwo(bit_size))
2453 return func.fail(
2454 "TODO: genBinOp {s} non-pow 2, found {}",
2455 .{ @tagName(tag), bit_size },
2456 );
23582457
2359 .cmp_eq,
2360 .cmp_neq,
2361 .cmp_gt,
2362 .cmp_gte,
2363 .cmp_lt,
2364 .cmp_lte,
2365 => .int,
2366 else => unreachable,
2367 };
2458 // it's important that the shift amount is exact
2459 try func.truncateRegister(rhs_ty, rhs_reg);
23682460
2369 const dest_reg, const dest_lock = try func.allocReg(return_class);
2370 defer func.register_manager.unlockReg(dest_lock);
2461 const mir_tag: Mir.Inst.Tag = switch (tag) {
2462 .shl, .shl_exact => switch (bit_size) {
2463 8, 16, 64 => .sll,
2464 32 => .sllw,
2465 else => unreachable,
2466 },
2467 .shr, .shr_exact => switch (bit_size) {
2468 8, 16, 64 => .srl,
2469 32 => .srlw,
2470 else => unreachable,
2471 },
2472 else => unreachable,
2473 };
23712474
2372 switch (tag) {
2373 .add,
2374 .sub,
2375 .mul,
2376 .div_float,
2377 => {
23782475 _ = try func.addInst(.{
23792476 .tag = mir_tag,
23802477 .ops = .rrr,
23812478 .data = .{ .r_type = .{
2382 .rd = dest_reg,
2479 .rd = dst_reg,
23832480 .rs1 = lhs_reg,
23842481 .rs2 = rhs_reg,
23852482 } },
23862483 });
2484
2485 switch (bit_size) {
2486 8, 16 => try func.truncateRegister(lhs_ty, dst_reg),
2487 32 => {},
2488 64 => {},
2489 else => unreachable,
2490 }
23872491 },
23882492
2493 // TODO: move the isel logic out of lower and into here.
23892494 .cmp_eq,
23902495 .cmp_neq,
2391 .cmp_gt,
2392 .cmp_gte,
23932496 .cmp_lt,
23942497 .cmp_lte,
2498 .cmp_gt,
2499 .cmp_gte,
23952500 => {
23962501 _ = try func.addInst(.{
23972502 .tag = .pseudo,
23982503 .ops = .pseudo_compare,
23992504 .data = .{
24002505 .compare = .{
2401 .rd = dest_reg,
2402 .rs1 = lhs_reg,
2403 .rs2 = rhs_reg,
24042506 .op = switch (tag) {
24052507 .cmp_eq => .eq,
24062508 .cmp_neq => .neq,
2407 .cmp_gt => .gt,
2408 .cmp_gte => .gte,
24092509 .cmp_lt => .lt,
24102510 .cmp_lte => .lte,
2511 .cmp_gt => .gt,
2512 .cmp_gte => .gte,
24112513 else => unreachable,
24122514 },
2413 .size = func.memSize(lhs_ty),
2515 .rd = dst_reg,
2516 .rs1 = lhs_reg,
2517 .rs2 = rhs_reg,
2518 .ty = lhs_ty,
24142519 },
24152520 },
24162521 });
24172522 },
24182523
2419 else => unreachable,
2420 }
2421
2422 return MCValue{ .register = dest_reg };
2423}
2424
2425fn airPtrArithmetic(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2426 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2427 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
2428 const lhs = try func.resolveInst(bin_op.lhs);
2429 const rhs = try func.resolveInst(bin_op.rhs);
2430 const lhs_ty = func.typeOf(bin_op.lhs);
2431 const rhs_ty = func.typeOf(bin_op.rhs);
2432
2433 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2434 break :result try func.binOp(tag, lhs, lhs_ty, rhs, rhs_ty);
2435 };
2436 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2437}
2438
2439fn airAddWrap(func: *Func, inst: Air.Inst.Index) !void {
2440 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2441 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement addwrap for {}", .{func.target.cpu.arch});
2442 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2443}
2444
2445fn airAddSat(func: *Func, inst: Air.Inst.Index) !void {
2446 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2447 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement add_sat for {}", .{func.target.cpu.arch});
2448 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2449}
2450
2451fn airSubWrap(func: *Func, inst: Air.Inst.Index) !void {
2452 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2453 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2454 // RISCV arthemtic instructions already wrap, so this is simply a sub binOp with
2455 // no overflow checks.
2456 const lhs = try func.resolveInst(bin_op.lhs);
2457 const rhs = try func.resolveInst(bin_op.rhs);
2458 const lhs_ty = func.typeOf(bin_op.lhs);
2459 const rhs_ty = func.typeOf(bin_op.rhs);
2460
2461 break :result try func.binOp(.sub, lhs, lhs_ty, rhs, rhs_ty);
2462 };
2463 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2464}
2465
2466fn airSubSat(func: *Func, inst: Air.Inst.Index) !void {
2467 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2468 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement sub_sat for {}", .{func.target.cpu.arch});
2469 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2470}
2524 // A branchless @min/@max sequence.
2525 //
2526 // Assume that a0 and a1 are the lhs and rhs respectively.
2527 // Also assume that a2 is the destination register.
2528 //
2529 // Algorithm:
2530 // slt s0, a0, a1
2531 // sub s0, zero, s0
2532 // xor a2, a0, a1
2533 // and s0, a2, s0
2534 // xor a2, a0, s0 # a0 is @min, a1 is @max
2535 //
2536 // "slt s0, a0, a1" will set s0 to 1 if a0 is less than a1, and 1 otherwise.
2537 //
2538 // "sub s0, zero, s0" will set all the bits of s0 to 1 if it was 1, otherwise it'll remain at 0.
2539 //
2540 // "xor a2, a0, a1" stores the bitwise XOR of a0 and a1 in a2. Effectively getting the difference between them.
2541 //
2542 // "and a0, a2, s0" here we mask the result of the XOR with the negated s0. If a0 < a1, s0 is -1, which
2543 // doesn't change the bits of a2. If a0 >= a1, s0 is 0, nullifying a2.
2544 //
2545 // "xor a2, a0, s0" the final XOR operation adjusts a2 to be the minimum value of a0 and a1. If a0 was less than
2546 // a1, s0 was -1, flipping all the bits in a2 and effectively restoring a0. If a0 was greater than or equal to a1,
2547 // s0 was 0, leaving a2 unchanged as a0.
2548 .min, .max => {
2549 const int_info = lhs_ty.intInfo(zcu);
2550
2551 const mask_reg, const mask_lock = try func.allocReg(.int);
2552 defer func.register_manager.unlockReg(mask_lock);
24712553
2472fn airMul(func: *Func, inst: Air.Inst.Index) !void {
2473 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2474 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2475 const lhs = try func.resolveInst(bin_op.lhs);
2476 const rhs = try func.resolveInst(bin_op.rhs);
2477 const lhs_ty = func.typeOf(bin_op.lhs);
2478 const rhs_ty = func.typeOf(bin_op.rhs);
2479
2480 break :result try func.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
2481 };
2482 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2483}
2554 _ = try func.addInst(.{
2555 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2556 .ops = .rrr,
2557 .data = .{ .r_type = .{
2558 .rd = mask_reg,
2559 .rs1 = lhs_reg,
2560 .rs2 = rhs_reg,
2561 } },
2562 });
24842563
2485fn airDiv(func: *Func, inst: Air.Inst.Index) !void {
2486 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2487 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2488 const lhs = try func.resolveInst(bin_op.lhs);
2489 const rhs = try func.resolveInst(bin_op.rhs);
2490 const lhs_ty = func.typeOf(bin_op.lhs);
2491 const rhs_ty = func.typeOf(bin_op.rhs);
2564 _ = try func.addInst(.{
2565 .tag = .sub,
2566 .ops = .rrr,
2567 .data = .{ .r_type = .{
2568 .rd = mask_reg,
2569 .rs1 = .zero,
2570 .rs2 = mask_reg,
2571 } },
2572 });
24922573
2493 break :result try func.binOp(.div_float, lhs, lhs_ty, rhs, rhs_ty);
2494 };
2495 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2496}
2574 _ = try func.addInst(.{
2575 .tag = .xor,
2576 .ops = .rrr,
2577 .data = .{ .r_type = .{
2578 .rd = dst_reg,
2579 .rs1 = lhs_reg,
2580 .rs2 = rhs_reg,
2581 } },
2582 });
24972583
2498fn airMulWrap(func: *Func, inst: Air.Inst.Index) !void {
2499 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2500 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement mulwrap for {}", .{func.target.cpu.arch});
2501 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2584 _ = try func.addInst(.{
2585 .tag = .@"and",
2586 .ops = .rrr,
2587 .data = .{ .r_type = .{
2588 .rd = mask_reg,
2589 .rs1 = dst_reg,
2590 .rs2 = mask_reg,
2591 } },
2592 });
2593
2594 _ = try func.addInst(.{
2595 .tag = .xor,
2596 .ops = .rrr,
2597 .data = .{ .r_type = .{
2598 .rd = dst_reg,
2599 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
2600 .rs2 = mask_reg,
2601 } },
2602 });
2603 },
2604 else => return func.fail("TODO: genBinOp {}", .{tag}),
2605 }
25022606}
25032607
2504fn airMulSat(func: *Func, inst: Air.Inst.Index) !void {
2505 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2506 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement mul_sat for {}", .{func.target.cpu.arch});
2507 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2608fn airPtrArithmetic(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2609 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2610 const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data;
2611 const dst_mcv = try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
2612 return func.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
25082613}
25092614
25102615fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
......@@ -2513,19 +2618,16 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
25132618 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
25142619
25152620 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2516 const lhs = try func.resolveInst(extra.lhs);
2517 const rhs = try func.resolveInst(extra.rhs);
25182621 const lhs_ty = func.typeOf(extra.lhs);
2519 const rhs_ty = func.typeOf(extra.rhs);
25202622
25212623 const int_info = lhs_ty.intInfo(zcu);
25222624
25232625 const tuple_ty = func.typeOfIndex(inst);
2524 const result_mcv = try func.allocRegOrMem(inst, false);
2626 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
25252627 const offset = result_mcv.load_frame;
25262628
25272629 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2528 const add_result = try func.binOp(.add, lhs, lhs_ty, rhs, rhs_ty);
2630 const add_result = try func.binOp(null, .add, extra.lhs, extra.rhs);
25292631 const add_result_reg = try func.copyToTmpRegister(lhs_ty, add_result);
25302632 const add_result_reg_lock = func.register_manager.lockRegAssumeUnused(add_result_reg);
25312633 defer func.register_manager.unlockReg(add_result_reg_lock);
......@@ -2542,7 +2644,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
25422644 .i_type = .{
25432645 .rd = shift_reg,
25442646 .rs1 = add_result_reg,
2545 .imm12 = Immediate.s(shift_amount),
2647 .imm12 = Immediate.u(shift_amount),
25462648 },
25472649 },
25482650 });
......@@ -2554,7 +2656,7 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
25542656 .i_type = .{
25552657 .rd = shift_reg,
25562658 .rs1 = shift_reg,
2557 .imm12 = Immediate.s(shift_amount),
2659 .imm12 = Immediate.u(shift_amount),
25582660 },
25592661 },
25602662 });
......@@ -2566,18 +2668,23 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
25662668 add_result,
25672669 );
25682670
2569 const overflow_mcv = try func.binOp(
2671 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2672 defer func.register_manager.unlockReg(overflow_lock);
2673
2674 try func.genBinOp(
25702675 .cmp_neq,
25712676 .{ .register = shift_reg },
25722677 lhs_ty,
25732678 .{ .register = add_result_reg },
25742679 lhs_ty,
2680 overflow_reg,
25752681 );
2682
25762683 try func.genSetMem(
25772684 .{ .frame = offset.index },
25782685 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
25792686 Type.u1,
2580 overflow_mcv,
2687 .{ .register = overflow_reg },
25812688 );
25822689
25832690 break :result result_mcv;
......@@ -2602,49 +2709,64 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
26022709
26032710 const int_info = lhs_ty.intInfo(zcu);
26042711
2605 if (!math.isPowerOfTwo(int_info.bits) or !(int_info.bits >= 8)) {
2712 if (!math.isPowerOfTwo(int_info.bits) or int_info.bits < 8) {
26062713 return func.fail("TODO: airSubWithOverflow non-power of 2 and less than 8 bits", .{});
26072714 }
26082715
2716 if (int_info.bits > 64) {
2717 return func.fail("TODO: airSubWithOverflow > 64 bits", .{});
2718 }
2719
26092720 const tuple_ty = func.typeOfIndex(inst);
2610 const result_mcv = try func.allocRegOrMem(inst, false);
2721 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
26112722 const offset = result_mcv.load_frame;
26122723
2613 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{});
2724 const dest_mcv = try func.binOp(null, .sub, extra.lhs, extra.rhs);
2725 assert(dest_mcv == .register);
2726 const dest_reg = dest_mcv.register;
2727
2728 try func.genSetMem(
2729 .{ .frame = offset.index },
2730 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
2731 lhs_ty,
2732 .{ .register = dest_reg },
2733 );
2734
2735 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs);
26142736 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
26152737
2616 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{});
2738 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs);
26172739 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
26182740
2619 const dest_reg, const dest_lock = try func.allocReg(.int);
2620 defer func.register_manager.unlockReg(dest_lock);
2741 const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 });
2742
2743 const overflow_lock = func.register_manager.lockRegAssumeUnused(overflow_reg);
2744 defer func.register_manager.unlockReg(overflow_lock);
26212745
26222746 switch (int_info.signedness) {
2623 .unsigned => return func.fail("TODO: airSubWithOverflow unsigned", .{}),
2747 .unsigned => {
2748 _ = try func.addInst(.{
2749 .tag = .sltu,
2750 .ops = .rrr,
2751 .data = .{ .r_type = .{
2752 .rd = overflow_reg,
2753 .rs1 = lhs_reg,
2754 .rs2 = rhs_reg,
2755 } },
2756 });
2757
2758 try func.genSetMem(
2759 .{ .frame = offset.index },
2760 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
2761 Type.u1,
2762 .{ .register = overflow_reg },
2763 );
2764
2765 break :result result_mcv;
2766 },
26242767 .signed => {
26252768 switch (int_info.bits) {
26262769 64 => {
2627 // result
2628 _ = try func.addInst(.{
2629 .tag = .sub,
2630 .ops = .rrr,
2631 .data = .{ .r_type = .{
2632 .rd = dest_reg,
2633 .rs1 = lhs_reg,
2634 .rs2 = rhs_reg,
2635 } },
2636 });
2637
2638 try func.genSetMem(
2639 .{ .frame = offset.index },
2640 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
2641 lhs_ty,
2642 .{ .register = dest_reg },
2643 );
2644
2645 // overflow check
2646 const overflow_reg = try func.copyToTmpRegister(Type.usize, .{ .immediate = 0 });
2647
26482770 _ = try func.addInst(.{
26492771 .tag = .slt,
26502772 .ops = .rrr,
......@@ -2675,19 +2797,20 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
26752797 } },
26762798 });
26772799
2678 const overflow_mcv = try func.binOp(
2800 try func.genBinOp(
26792801 .cmp_neq,
26802802 .{ .register = overflow_reg },
26812803 Type.usize,
26822804 .{ .register = rhs_reg },
26832805 Type.usize,
2806 overflow_reg,
26842807 );
26852808
26862809 try func.genSetMem(
26872810 .{ .frame = offset.index },
26882811 offset.off + @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
26892812 Type.u1,
2690 overflow_mcv,
2813 .{ .register = overflow_reg },
26912814 );
26922815
26932816 break :result result_mcv;
......@@ -2702,16 +2825,42 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27022825}
27032826
27042827fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2705 //const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
2828 const zcu = func.bin_file.comp.module.?;
27062829 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
27072830 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
2708 const zcu = func.bin_file.comp.module.?;
2831
27092832 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
27102833 const lhs = try func.resolveInst(extra.lhs);
27112834 const rhs = try func.resolveInst(extra.rhs);
27122835 const lhs_ty = func.typeOf(extra.lhs);
27132836 const rhs_ty = func.typeOf(extra.rhs);
27142837
2838 const tuple_ty = func.typeOfIndex(inst);
2839
2840 // genSetReg needs to support register_offset src_mcv for this to be true.
2841 const result_mcv = try func.allocRegOrMem(tuple_ty, inst, false);
2842
2843 const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu));
2844 const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu));
2845
2846 const dest_reg, const dest_lock = try func.allocReg(.int);
2847 defer func.register_manager.unlockReg(dest_lock);
2848
2849 try func.genBinOp(
2850 .mul,
2851 lhs,
2852 lhs_ty,
2853 rhs,
2854 rhs_ty,
2855 dest_reg,
2856 );
2857
2858 try func.genCopy(
2859 lhs_ty,
2860 result_mcv.offset(result_off),
2861 .{ .register = dest_reg },
2862 );
2863
27152864 switch (lhs_ty.zigTypeTag(zcu)) {
27162865 else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}),
27172866 .Int => {
......@@ -2719,74 +2868,53 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27192868 const int_info = lhs_ty.intInfo(zcu);
27202869 switch (int_info.bits) {
27212870 1...32 => {
2722 if (func.hasFeature(.m)) {
2723 const dest = try func.binOp(.mul, lhs, lhs_ty, rhs, rhs_ty);
2724
2725 const add_result_lock = func.register_manager.lockRegAssumeUnused(dest.register);
2726 defer func.register_manager.unlockReg(add_result_lock);
2727
2728 const tuple_ty = func.typeOfIndex(inst);
2729
2730 const result_mcv = try func.allocRegOrMem(inst, true);
2731
2732 const result_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu));
2733 const overflow_off: i32 = @intCast(tuple_ty.structFieldOffset(1, zcu));
2734
2735 try func.genCopy(
2736 lhs_ty,
2737 result_mcv.offset(result_off),
2738 dest,
2739 );
2740
2741 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2742 if (int_info.signedness == .unsigned) {
2743 switch (int_info.bits) {
2744 1...8 => {
2745 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
2746
2747 const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs, .{});
2748 defer if (add_lock) |lock| func.register_manager.unlockReg(lock);
2749
2750 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2751 defer func.register_manager.unlockReg(overflow_lock);
2752
2753 _ = try func.addInst(.{
2754 .tag = .andi,
2755 .ops = .rri,
2756 .data = .{ .i_type = .{
2757 .rd = overflow_reg,
2758 .rs1 = add_reg,
2759 .imm12 = Immediate.s(max_val),
2760 } },
2761 });
2762
2763 const overflow_mcv = try func.binOp(
2764 .cmp_neq,
2765 .{ .register = overflow_reg },
2766 lhs_ty,
2767 .{ .register = add_reg },
2768 lhs_ty,
2769 );
2770
2771 try func.genCopy(
2772 lhs_ty,
2773 result_mcv.offset(overflow_off),
2774 overflow_mcv,
2775 );
2776
2777 break :result result_mcv;
2778 },
2779
2780 else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}),
2781 }
2782 } else {
2783 return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{});
2871 if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) {
2872 if (int_info.signedness == .unsigned) {
2873 switch (int_info.bits) {
2874 1...8 => {
2875 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
2876
2877 const add_reg, const add_lock = try func.promoteReg(lhs_ty, lhs);
2878 defer if (add_lock) |lock| func.register_manager.unlockReg(lock);
2879
2880 const overflow_reg, const overflow_lock = try func.allocReg(.int);
2881 defer func.register_manager.unlockReg(overflow_lock);
2882
2883 _ = try func.addInst(.{
2884 .tag = .andi,
2885 .ops = .rri,
2886 .data = .{ .i_type = .{
2887 .rd = overflow_reg,
2888 .rs1 = add_reg,
2889 .imm12 = Immediate.s(max_val),
2890 } },
2891 });
2892
2893 try func.genBinOp(
2894 .cmp_neq,
2895 .{ .register = overflow_reg },
2896 lhs_ty,
2897 .{ .register = add_reg },
2898 lhs_ty,
2899 overflow_reg,
2900 );
2901
2902 try func.genCopy(
2903 lhs_ty,
2904 result_mcv.offset(overflow_off),
2905 .{ .register = overflow_reg },
2906 );
2907
2908 break :result result_mcv;
2909 },
2910
2911 else => return func.fail("TODO: airMulWithOverflow check for size {d}", .{int_info.bits}),
27842912 }
27852913 } else {
2786 return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{});
2914 return func.fail("TODO: airMulWithOverflow calculate carry for signed addition", .{});
27872915 }
27882916 } else {
2789 return func.fail("TODO: emulate mul for targets without M feature", .{});
2917 return func.fail("TODO: airMulWithOverflow with < 8 bits or non-pow of 2", .{});
27902918 }
27912919 },
27922920 else => return func.fail("TODO: airMulWithOverflow larger than 32-bit mul", .{}),
......@@ -2799,123 +2927,32 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
27992927}
28002928
28012929fn airShlWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
2802 _ = inst;
2803 return func.fail("TODO implement airShlWithOverflow for {}", .{func.target.cpu.arch});
2804}
2805
2806fn airRem(func: *Func, inst: Air.Inst.Index) !void {
2807 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2808 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement rem for {}", .{func.target.cpu.arch});
2809 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2810}
2811
2812fn airMod(func: *Func, inst: Air.Inst.Index) !void {
2813 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2814 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement zcu for {}", .{func.target.cpu.arch});
2815 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2816}
2817
2818fn airBitAnd(func: *Func, inst: Air.Inst.Index) !void {
28192930 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2820 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2821 const lhs = try func.resolveInst(bin_op.lhs);
2822 const rhs = try func.resolveInst(bin_op.rhs);
2823
2824 const lhs_ty = func.typeOf(bin_op.lhs);
2825 const rhs_ty = func.typeOf(bin_op.rhs);
2826
2827 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{});
2828 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2829
2830 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{});
2831 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2832
2833 const dest_reg, const dest_lock = try func.allocReg(.int);
2834 defer func.register_manager.unlockReg(dest_lock);
2835
2836 _ = try func.addInst(.{
2837 .tag = .@"and",
2838 .ops = .rrr,
2839 .data = .{ .r_type = .{
2840 .rd = dest_reg,
2841 .rs1 = lhs_reg,
2842 .rs2 = rhs_reg,
2843 } },
2844 });
2845
2846 break :result .{ .register = dest_reg };
2847 };
2931 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlWithOverflow", .{});
28482932 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
28492933}
28502934
2851fn airBitOr(func: *Func, inst: Air.Inst.Index) !void {
2935fn airAddSat(func: *Func, inst: Air.Inst.Index) !void {
28522936 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2853 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2854 const lhs = try func.resolveInst(bin_op.lhs);
2855 const rhs = try func.resolveInst(bin_op.rhs);
2856
2857 const lhs_ty = func.typeOf(bin_op.lhs);
2858 const rhs_ty = func.typeOf(bin_op.rhs);
2859
2860 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{});
2861 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
2862
2863 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{});
2864 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
2865
2866 const dest_reg, const dest_lock = try func.allocReg(.int);
2867 defer func.register_manager.unlockReg(dest_lock);
2868
2869 _ = try func.addInst(.{
2870 .tag = .@"or",
2871 .ops = .rrr,
2872 .data = .{ .r_type = .{
2873 .rd = dest_reg,
2874 .rs1 = lhs_reg,
2875 .rs2 = rhs_reg,
2876 } },
2877 });
2878
2879 break :result .{ .register = dest_reg };
2880 };
2937 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airAddSat", .{});
28812938 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
28822939}
28832940
2884fn airXor(func: *Func, inst: Air.Inst.Index) !void {
2941fn airSubSat(func: *Func, inst: Air.Inst.Index) !void {
28852942 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2886 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement xor for {}", .{func.target.cpu.arch});
2943 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airSubSat", .{});
28872944 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
28882945}
28892946
2890fn airShl(func: *Func, inst: Air.Inst.Index) !void {
2947fn airMulSat(func: *Func, inst: Air.Inst.Index) !void {
28912948 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2892 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2893 const lhs = try func.resolveInst(bin_op.lhs);
2894 const rhs = try func.resolveInst(bin_op.rhs);
2895 const lhs_ty = func.typeOf(bin_op.lhs);
2896 const rhs_ty = func.typeOf(bin_op.rhs);
2897
2898 break :result try func.binOp(.shl, lhs, lhs_ty, rhs, rhs_ty);
2899 };
2949 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airMulSat", .{});
29002950 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
29012951}
29022952
29032953fn airShlSat(func: *Func, inst: Air.Inst.Index) !void {
29042954 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2905 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement shl_sat for {}", .{func.target.cpu.arch});
2906 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2907}
2908
2909fn airShr(func: *Func, inst: Air.Inst.Index) !void {
2910 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2911 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
2912 const lhs = try func.resolveInst(bin_op.lhs);
2913 const rhs = try func.resolveInst(bin_op.rhs);
2914 const lhs_ty = func.typeOf(bin_op.lhs);
2915 const rhs_ty = func.typeOf(bin_op.rhs);
2916
2917 break :result try func.binOp(.shr, lhs, lhs_ty, rhs, rhs_ty);
2918 };
2955 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airShlSat", .{});
29192956 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
29202957}
29212958
......@@ -2935,7 +2972,7 @@ fn airOptionalPayload(func: *Func, inst: Air.Inst.Index) !void {
29352972 break :result opt_mcv;
29362973 }
29372974
2938 const pl_mcv = try func.allocRegOrMem(inst, true);
2975 const pl_mcv = try func.allocRegOrMem(pl_ty, inst, true);
29392976 try func.genCopy(pl_ty, pl_mcv, opt_mcv);
29402977 break :result pl_mcv;
29412978 };
......@@ -2978,15 +3015,15 @@ fn airUnwrapErrErr(func: *Func, inst: Air.Inst.Index) !void {
29783015 const eu_lock = func.register_manager.lockReg(reg);
29793016 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
29803017
2981 var result = try func.copyToNewRegister(inst, operand);
2982
3018 const result = try func.copyToNewRegister(inst, operand);
29833019 if (err_off > 0) {
2984 result = try func.binOp(
3020 try func.genBinOp(
29853021 .shr,
29863022 result,
29873023 err_union_ty,
29883024 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
29893025 Type.u8,
3026 result.register,
29903027 );
29913028 }
29923029 break :result result;
......@@ -3031,19 +3068,18 @@ fn genUnwrapErrUnionPayloadMir(
30313068 const eu_lock = func.register_manager.lockReg(reg);
30323069 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
30333070
3034 var result: MCValue = .{ .register = try func.copyToTmpRegister(err_union_ty, err_union) };
3035
3071 const result_reg = try func.copyToTmpRegister(err_union_ty, err_union);
30363072 if (payload_off > 0) {
3037 result = try func.binOp(
3073 try func.genBinOp(
30383074 .shr,
3039 result,
3075 .{ .register = result_reg },
30403076 err_union_ty,
30413077 .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
30423078 Type.u8,
3079 result_reg,
30433080 );
30443081 }
3045
3046 break :result result;
3082 break :result .{ .register = result_reg };
30473083 },
30483084 else => return func.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}),
30493085 }
......@@ -3108,7 +3144,7 @@ fn airWrapOptional(func: *Func, inst: Air.Inst.Index) !void {
31083144 };
31093145 defer if (pl_lock) |lock| func.register_manager.unlockReg(lock);
31103146
3111 const opt_mcv = try func.allocRegOrMem(inst, true);
3147 const opt_mcv = try func.allocRegOrMem(opt_ty, inst, true);
31123148 try func.genCopy(pl_ty, opt_mcv, pl_mcv);
31133149
31143150 if (!same_repr) {
......@@ -3237,7 +3273,7 @@ fn airSlicePtr(func: *Func, inst: Air.Inst.Index) !void {
32373273 const src_mcv = try func.resolveInst(ty_op.operand);
32383274 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
32393275
3240 const dst_mcv = try func.allocRegOrMem(inst, true);
3276 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
32413277 const dst_ty = func.typeOfIndex(inst);
32423278 try func.genCopy(dst_ty, dst_mcv, src_mcv);
32433279 break :result dst_mcv;
......@@ -3249,6 +3285,8 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
32493285 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
32503286 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
32513287 const src_mcv = try func.resolveInst(ty_op.operand);
3288 const ty = func.typeOfIndex(inst);
3289
32523290 switch (src_mcv) {
32533291 .load_frame => |frame_addr| {
32543292 const len_mcv: MCValue = .{ .load_frame = .{
......@@ -3257,7 +3295,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
32573295 } };
32583296 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
32593297
3260 const dst_mcv = try func.allocRegOrMem(inst, true);
3298 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
32613299 try func.genCopy(Type.usize, dst_mcv, len_mcv);
32623300 break :result dst_mcv;
32633301 },
......@@ -3266,7 +3304,7 @@ fn airSliceLen(func: *Func, inst: Air.Inst.Index) !void {
32663304
32673305 if (func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result len_mcv;
32683306
3269 const dst_mcv = try func.allocRegOrMem(inst, true);
3307 const dst_mcv = try func.allocRegOrMem(ty, inst, true);
32703308 try func.genCopy(Type.usize, dst_mcv, len_mcv);
32713309 break :result dst_mcv;
32723310 },
......@@ -3289,41 +3327,19 @@ fn airPtrSlicePtrPtr(func: *Func, inst: Air.Inst.Index) !void {
32893327}
32903328
32913329fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void {
3292 const zcu = func.bin_file.comp.module.?;
3293 const is_volatile = false; // TODO
3330 const mod = func.bin_file.comp.module.?;
32943331 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
32953332
3296 if (!is_volatile and func.liveness.isUnused(inst)) return func.finishAir(
3297 inst,
3298 .unreach,
3299 .{ bin_op.lhs, bin_op.rhs, .none },
3300 );
33013333 const result: MCValue = result: {
3302 const slice_mcv = try func.resolveInst(bin_op.lhs);
3303 const index_mcv = try func.resolveInst(bin_op.rhs);
3334 const elem_ty = func.typeOfIndex(inst);
3335 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
33043336
33053337 const slice_ty = func.typeOf(bin_op.lhs);
3306
3307 const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu);
3308
3309 const index_lock: ?RegisterLock = if (index_mcv == .register)
3310 func.register_manager.lockRegAssumeUnused(index_mcv.register)
3311 else
3312 null;
3313 defer if (index_lock) |reg| func.register_manager.unlockReg(reg);
3314
3315 const base_mcv: MCValue = switch (slice_mcv) {
3316 .load_frame,
3317 .load_symbol,
3318 => .{ .register = try func.copyToTmpRegister(slice_ptr_field_type, slice_mcv) },
3319 else => return func.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
3320 };
3321
3322 const dest = try func.allocRegOrMem(inst, true);
3323 const addr = try func.binOp(.ptr_add, base_mcv, slice_ptr_field_type, index_mcv, Type.usize);
3324 try func.load(dest, addr, slice_ptr_field_type);
3325
3326 break :result dest;
3338 const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod);
3339 const elem_ptr = try func.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
3340 const dst_mcv = try func.allocRegOrMem(elem_ty, inst, false);
3341 try func.load(dst_mcv, elem_ptr, slice_ptr_field_type);
3342 break :result dst_mcv;
33273343 };
33283344 return func.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
33293345}
......@@ -3331,14 +3347,58 @@ fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void {
33313347fn airSliceElemPtr(func: *Func, inst: Air.Inst.Index) !void {
33323348 const ty_pl = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
33333349 const extra = func.air.extraData(Air.Bin, ty_pl.payload).data;
3334 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement slice_elem_ptr for {}", .{func.target.cpu.arch});
3335 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
3350 const dst_mcv = try func.genSliceElemPtr(extra.lhs, extra.rhs);
3351 return func.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
3352}
3353
3354fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
3355 const zcu = func.bin_file.comp.module.?;
3356 const slice_ty = func.typeOf(lhs);
3357 const slice_mcv = try func.resolveInst(lhs);
3358 const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) {
3359 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3360 else => null,
3361 };
3362 defer if (slice_mcv_lock) |lock| func.register_manager.unlockReg(lock);
3363
3364 const elem_ty = slice_ty.childType(zcu);
3365 const elem_size = elem_ty.abiSize(zcu);
3366
3367 const index_ty = func.typeOf(rhs);
3368 const index_mcv = try func.resolveInst(rhs);
3369 const index_mcv_lock: ?RegisterLock = switch (index_mcv) {
3370 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
3371 else => null,
3372 };
3373 defer if (index_mcv_lock) |lock| func.register_manager.unlockReg(lock);
3374
3375 const offset_reg = try func.elemOffset(index_ty, index_mcv, elem_size);
3376 const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
3377 defer func.register_manager.unlockReg(offset_reg_lock);
3378
3379 const addr_reg, const addr_lock = try func.allocReg(.int);
3380 defer func.register_manager.unlockReg(addr_lock);
3381 try func.genSetReg(Type.usize, addr_reg, slice_mcv);
3382
3383 _ = try func.addInst(.{
3384 .tag = .add,
3385 .ops = .rrr,
3386 .data = .{ .r_type = .{
3387 .rd = addr_reg,
3388 .rs1 = addr_reg,
3389 .rs2 = offset_reg,
3390 } },
3391 });
3392
3393 return .{ .register = addr_reg };
33363394}
33373395
33383396fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
33393397 const zcu = func.bin_file.comp.module.?;
33403398 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
33413399 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
3400 const result_ty = func.typeOfIndex(inst);
3401
33423402 const array_ty = func.typeOf(bin_op.lhs);
33433403 const array_mcv = try func.resolveInst(bin_op.lhs);
33443404
......@@ -3367,7 +3427,7 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
33673427 const offset_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
33683428 defer func.register_manager.unlockReg(offset_lock);
33693429
3370 const dst_mcv = try func.allocRegOrMem(inst, false);
3430 const dst_mcv = try func.allocRegOrMem(result_ty, inst, false);
33713431 _ = try func.addInst(.{
33723432 .tag = .add,
33733433 .ops = .rrr,
......@@ -3427,7 +3487,19 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void {
34273487 const offset_reg_lock = func.register_manager.lockRegAssumeUnused(offset_reg);
34283488 defer func.register_manager.unlockReg(offset_reg_lock);
34293489
3430 break :result try func.binOp(.ptr_add, base_ptr_mcv, base_ptr_ty, .{ .register = offset_reg }, base_ptr_ty);
3490 const result_reg, const result_lock = try func.allocReg(.int);
3491 defer func.register_manager.unlockReg(result_lock);
3492
3493 try func.genBinOp(
3494 .ptr_add,
3495 base_ptr_mcv,
3496 base_ptr_ty,
3497 .{ .register = offset_reg },
3498 Type.usize,
3499 result_reg,
3500 );
3501
3502 break :result MCValue{ .register = result_reg };
34313503 };
34323504 return func.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
34333505}
......@@ -3487,7 +3559,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
34873559 .data = .{ .i_type = .{
34883560 .rd = temp_reg,
34893561 .rs1 = operand_reg,
3490 .imm12 = Immediate.s(63),
3562 .imm12 = Immediate.u(63),
34913563 } },
34923564 });
34933565
......@@ -3695,7 +3767,7 @@ fn airLoad(func: *Func, inst: Air.Inst.Index) !void {
36953767 // The MCValue that holds the pointer can be re-used as the value.
36963768 break :blk ptr;
36973769 } else {
3698 break :blk try func.allocRegOrMem(inst, true);
3770 break :blk try func.allocRegOrMem(elem_ty, inst, true);
36993771 }
37003772 };
37013773
......@@ -3876,7 +3948,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
38763948 .tag = .srli,
38773949 .ops = .rri,
38783950 .data = .{ .i_type = .{
3879 .imm12 = Immediate.s(@intCast(field_off)),
3951 .imm12 = Immediate.u(@intCast(field_off)),
38803952 .rd = dst_reg,
38813953 .rs1 = dst_reg,
38823954 } },
......@@ -3911,7 +3983,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
39113983 func.reuseOperand(inst, operand, 0, src_mcv))
39123984 off_mcv
39133985 else dst: {
3914 const dst_mcv = try func.allocRegOrMem(inst, true);
3986 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
39153987 try func.genCopy(field_ty, dst_mcv, off_mcv);
39163988 break :dst dst_mcv;
39173989 };
......@@ -3972,7 +4044,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void {
39724044 const src_mcv = func.args[arg_index];
39734045 const arg_ty = func.typeOfIndex(inst);
39744046
3975 const dst_mcv = try func.allocRegOrMem(inst, false);
4047 const dst_mcv = try func.allocRegOrMem(arg_ty, inst, false);
39764048
39774049 log.debug("airArg {} -> {}", .{ src_mcv, dst_mcv });
39784050
......@@ -4004,13 +4076,13 @@ fn airBreakpoint(func: *Func) !void {
40044076}
40054077
40064078fn airRetAddr(func: *Func, inst: Air.Inst.Index) !void {
4007 const dst_mcv = try func.allocRegOrMem(inst, true);
4079 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
40084080 try func.genCopy(Type.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } });
40094081 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
40104082}
40114083
40124084fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
4013 const dst_mcv = try func.allocRegOrMem(inst, true);
4085 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
40144086 try func.genCopy(Type.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } });
40154087 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
40164088}
......@@ -4196,10 +4268,7 @@ fn genCall(
41964268 if (func.mod.pic) {
41974269 return func.fail("TODO: genCall pic", .{});
41984270 } else {
4199 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4200 const got_addr = sym.zigGotAddress(elf_file);
4201 try func.genSetReg(Type.usize, .ra, .{ .memory = @intCast(got_addr) });
4202
4271 try func.genSetReg(Type.usize, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
42034272 _ = try func.addInst(.{
42044273 .tag = .jalr,
42054274 .ops = .rri,
......@@ -4323,14 +4392,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void {
43234392 try func.exitlude_jump_relocs.append(func.gpa, index);
43244393}
43254394
4326fn airCmp(func: *Func, inst: Air.Inst.Index) !void {
4327 const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];
4395fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
43284396 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
43294397 const zcu = func.bin_file.comp.module.?;
43304398
43314399 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
4332 const lhs = try func.resolveInst(bin_op.lhs);
4333 const rhs = try func.resolveInst(bin_op.rhs);
43344400 const lhs_ty = func.typeOf(bin_op.lhs);
43354401
43364402 switch (lhs_ty.zigTypeTag(zcu)) {
......@@ -4346,7 +4412,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void {
43464412 .Int => lhs_ty,
43474413 .Bool => Type.u1,
43484414 .Pointer => Type.usize,
4349 .ErrorSet => Type.u16,
4415 .ErrorSet => Type.anyerror,
43504416 .Optional => blk: {
43514417 const payload_ty = lhs_ty.optionalChild(zcu);
43524418 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
......@@ -4362,7 +4428,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void {
43624428
43634429 const int_info = int_ty.intInfo(zcu);
43644430 if (int_info.bits <= 64) {
4365 break :result try func.binOp(tag, lhs, int_ty, rhs, int_ty);
4431 break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
43664432 } else {
43674433 return func.fail("TODO riscv cmp for ints > 64 bits", .{});
43684434 }
......@@ -4373,7 +4439,7 @@ fn airCmp(func: *Func, inst: Air.Inst.Index) !void {
43734439 if (float_bits > float_reg_size) {
43744440 return func.fail("TODO: airCmp float > 64/32 bits", .{});
43754441 }
4376 break :result try func.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty);
4442 break :result try func.binOp(inst, tag, bin_op.lhs, bin_op.rhs);
43774443 },
43784444 else => unreachable,
43794445 }
......@@ -4537,7 +4603,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
45374603 else
45384604 .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = Type.bool };
45394605
4540 const return_mcv = try func.allocRegOrMem(inst, true);
4606 const return_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
45414607 assert(return_mcv == .register); // should not be larger 8 bytes
45424608 const return_reg = return_mcv.register;
45434609
......@@ -4569,7 +4635,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
45694635 some_info.ty,
45704636 .{ .immediate = 0 },
45714637 ),
4572 .size = .byte,
4638 .ty = Type.bool,
45734639 },
45744640 },
45754641 });
......@@ -4601,7 +4667,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
46014667 some_info.ty,
46024668 .{ .immediate = 0 },
46034669 ),
4604 .size = .byte,
4670 .ty = Type.bool,
46054671 },
46064672 },
46074673 });
......@@ -4623,9 +4689,9 @@ fn airIsNull(func: *Func, inst: Air.Inst.Index) !void {
46234689fn airIsNullPtr(func: *Func, inst: Air.Inst.Index) !void {
46244690 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
46254691 const operand = try func.resolveInst(un_op);
4626 _ = operand; // autofix
4692 _ = operand;
46274693 const ty = func.typeOf(un_op);
4628 _ = ty; // autofix
4694 _ = ty;
46294695
46304696 if (true) return func.fail("TODO: airIsNullPtr", .{});
46314697
......@@ -4656,9 +4722,9 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void {
46564722fn airIsNonNullPtr(func: *Func, inst: Air.Inst.Index) !void {
46574723 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
46584724 const operand = try func.resolveInst(un_op);
4659 _ = operand; // autofix
4725 _ = operand;
46604726 const ty = func.typeOf(un_op);
4661 _ = ty; // autofix
4727 _ = ty;
46624728
46634729 if (true) return func.fail("TODO: airIsNonNullPtr", .{});
46644730
......@@ -4685,7 +4751,7 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void {
46854751 // The MCValue that holds the pointer can be re-used as the value.
46864752 break :blk operand_ptr;
46874753 } else {
4688 break :blk try func.allocRegOrMem(inst, true);
4754 break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
46894755 }
46904756 };
46914757 try func.load(operand, operand_ptr, func.typeOf(un_op));
......@@ -4701,45 +4767,44 @@ fn airIsErrPtr(func: *Func, inst: Air.Inst.Index) !void {
47014767///
47024768/// Result is in the return register.
47034769fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
4770 _ = maybe_inst;
47044771 const zcu = func.bin_file.comp.module.?;
47054772 const err_ty = eu_ty.errorUnionSet(zcu);
47064773 if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false
4707
4708 _ = maybe_inst;
4709
47104774 const err_off: u31 = @intCast(errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu));
47114775
4776 const return_reg, const return_lock = try func.allocReg(.int);
4777 defer func.register_manager.unlockReg(return_lock);
4778
47124779 switch (eu_mcv) {
47134780 .register => |reg| {
47144781 const eu_lock = func.register_manager.lockReg(reg);
47154782 defer if (eu_lock) |lock| func.register_manager.unlockReg(lock);
47164783
4717 const return_reg = try func.copyToTmpRegister(eu_ty, eu_mcv);
4718 const return_lock = func.register_manager.lockRegAssumeUnused(return_reg);
4719 defer func.register_manager.unlockReg(return_lock);
4720
4721 var return_mcv: MCValue = .{ .register = return_reg };
4784 try func.genCopy(eu_ty, .{ .register = return_reg }, eu_mcv);
47224785
47234786 if (err_off > 0) {
4724 return_mcv = try func.binOp(
4787 try func.genBinOp(
47254788 .shr,
4726 return_mcv,
4789 .{ .register = return_reg },
47274790 eu_ty,
47284791 .{ .immediate = @as(u6, @intCast(err_off * 8)) },
47294792 Type.u8,
4793 return_reg,
47304794 );
47314795 }
47324796
4733 return try func.binOp(
4797 try func.genBinOp(
47344798 .cmp_neq,
4735 return_mcv,
4736 Type.u16,
4799 .{ .register = return_reg },
4800 Type.anyerror,
47374801 .{ .immediate = 0 },
4738 Type.u16,
4802 Type.u8,
4803 return_reg,
47394804 );
47404805 },
47414806 .load_frame => |frame_addr| {
4742 return func.binOp(
4807 try func.genBinOp(
47434808 .cmp_neq,
47444809 .{ .load_frame = .{
47454810 .index = frame_addr.index,
......@@ -4748,10 +4813,13 @@ fn isErr(func: *Func, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue)
47484813 Type.anyerror,
47494814 .{ .immediate = 0 },
47504815 Type.anyerror,
4816 return_reg,
47514817 );
47524818 },
47534819 else => return func.fail("TODO implement isErr for {}", .{eu_mcv}),
47544820 }
4821
4822 return .{ .register = return_reg };
47554823}
47564824
47574825fn airIsNonErr(func: *Func, inst: Air.Inst.Index) !void {
......@@ -4799,7 +4867,7 @@ fn airIsNonErrPtr(func: *Func, inst: Air.Inst.Index) !void {
47994867 // The MCValue that holds the pointer can be re-used as the value.
48004868 break :blk operand_ptr;
48014869 } else {
4802 break :blk try func.allocRegOrMem(inst, true);
4870 break :blk try func.allocRegOrMem(func.typeOfIndex(inst), inst, true);
48034871 }
48044872 };
48054873 const operand_ptr_ty = func.typeOf(un_op);
......@@ -4916,16 +4984,18 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
49164984 // switch branches must be comptime-known, so this is stored in an immediate
49174985 const item_mcv = try func.resolveInst(item);
49184986
4919 const cmp_mcv: MCValue = try func.binOp(
4987 const cmp_reg, const cmp_lock = try func.allocReg(.int);
4988 defer func.register_manager.unlockReg(cmp_lock);
4989
4990 try func.genBinOp(
49204991 .cmp_neq,
49214992 condition,
49224993 condition_ty,
49234994 item_mcv,
49244995 condition_ty,
4996 cmp_reg,
49254997 );
49264998
4927 const cmp_reg = try func.copyToTmpRegister(Type.bool, cmp_mcv);
4928
49294999 if (!(i < relocs.len - 1)) {
49305000 _ = try func.addInst(.{
49315001 .tag = .pseudo,
......@@ -5019,7 +5089,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void {
50195089 break :result block_tracking.short;
50205090 }
50215091
5022 const dst_mcv = if (first_br) try func.allocRegOrMem(br.block_inst, true) else dst: {
5092 const dst_mcv = if (first_br) try func.allocRegOrMem(block_ty, br.block_inst, true) else dst: {
50235093 try func.getValue(block_tracking.short, br.block_inst);
50245094 break :dst block_tracking.short;
50255095 };
......@@ -5063,10 +5133,10 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
50635133 const lhs_ty = Type.bool;
50645134 const rhs_ty = Type.bool;
50655135
5066 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs, .{});
5136 const lhs_reg, const lhs_lock = try func.promoteReg(lhs_ty, lhs);
50675137 defer if (lhs_lock) |lock| func.register_manager.unlockReg(lock);
50685138
5069 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs, .{});
5139 const rhs_reg, const rhs_lock = try func.promoteReg(rhs_ty, rhs);
50705140 defer if (rhs_lock) |lock| func.register_manager.unlockReg(lock);
50715141
50725142 const result_reg, const result_lock = try func.allocReg(.int);
......@@ -5262,7 +5332,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
52625332 const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) {
52635333 .register_pair, .memory, .indirect, .load_frame => null,
52645334 .load_symbol => src: {
5265 const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address(), .{});
5335 const src_addr_reg, const src_addr_lock = try func.promoteReg(Type.usize, src_mcv.address());
52665336 errdefer func.register_manager.unlockReg(src_addr_lock);
52675337
52685338 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
......@@ -5557,7 +5627,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
55575627 .data = .{ .i_type = .{
55585628 .rd = reg,
55595629 .rs1 = reg,
5560 .imm12 = Immediate.s(32),
5630 .imm12 = Immediate.u(32),
55615631 } },
55625632 });
55635633
......@@ -5604,10 +5674,9 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
56045674 .m = .{
56055675 .base = .{ .frame = frame.index },
56065676 .mod = .{
5607 .rm = .{
5608 .size = func.memSize(ty),
5609 .disp = frame.off,
5610 },
5677 .size = func.memSize(ty),
5678 .unsigned = ty.isUnsignedInt(zcu),
5679 .disp = frame.off,
56115680 },
56125681 },
56135682 } },
......@@ -5622,7 +5691,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
56225691 .data = .{ .i_type = .{
56235692 .rd = reg,
56245693 .rs1 = reg,
5625 .imm12 = Immediate.s(0),
5694 .imm12 = Immediate.u(0),
56265695 } },
56275696 });
56285697 },
......@@ -5636,19 +5705,17 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
56365705 .register_offset => |reg_off| .{
56375706 .base = .{ .reg = reg_off.reg },
56385707 .mod = .{
5639 .rm = .{
5640 .size = func.memSize(ty),
5641 .disp = reg_off.off,
5642 },
5708 .size = func.memSize(ty),
5709 .disp = reg_off.off,
5710 .unsigned = false,
56435711 },
56445712 },
56455713 .lea_frame => |frame| .{
56465714 .base = .{ .frame = frame.index },
56475715 .mod = .{
5648 .rm = .{
5649 .size = func.memSize(ty),
5650 .disp = frame.off,
5651 },
5716 .size = func.memSize(ty),
5717 .disp = frame.off,
5718 .unsigned = false,
56525719 },
56535720 },
56545721 else => unreachable,
......@@ -5787,9 +5854,10 @@ fn genSetMem(
57875854 .r = reg,
57885855 .m = .{
57895856 .base = .{ .frame = frame_index },
5790 .mod = .{ .rm = .{
5857 .mod = .{
57915858 .size = Memory.Size.fromByteSize(src_size),
5792 } },
5859 .unsigned = false,
5860 },
57935861 },
57945862 } },
57955863 });
......@@ -5802,10 +5870,11 @@ fn genSetMem(
58025870 .r = reg,
58035871 .m = .{
58045872 .base = base,
5805 .mod = .{ .rm = .{
5873 .mod = .{
58065874 .size = func.memSize(ty),
58075875 .disp = disp,
5808 } },
5876 .unsigned = false,
5877 },
58095878 },
58105879 } },
58115880 });
......@@ -5820,7 +5889,7 @@ fn genSetMem(
58205889 .immediate => {
58215890 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
58225891 // a register allocation.
5823 const reg, const reg_lock = try func.promoteReg(ty, src_mcv, .{});
5892 const reg, const reg_lock = try func.promoteReg(ty, src_mcv);
58245893 defer if (reg_lock) |lock| func.register_manager.unlockReg(lock);
58255894
58265895 return func.genSetMem(base, disp, ty, .{ .register = reg });
......@@ -5833,9 +5902,10 @@ fn airIntFromPtr(func: *Func, inst: Air.Inst.Index) !void {
58335902 const un_op = func.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
58345903 const result = result: {
58355904 const src_mcv = try func.resolveInst(un_op);
5905 const src_ty = func.typeOfIndex(inst);
58365906 if (func.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
58375907
5838 const dst_mcv = try func.allocRegOrMem(inst, true);
5908 const dst_mcv = try func.allocRegOrMem(src_ty, inst, true);
58395909 const dst_ty = func.typeOfIndex(inst);
58405910 try func.genCopy(dst_ty, dst_mcv, src_mcv);
58415911 break :result dst_mcv;
......@@ -5858,7 +5928,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
58585928
58595929 const dst_mcv = if (dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and
58605930 func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
5861 const dst_mcv = try func.allocRegOrMem(inst, true);
5931 const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true);
58625932 try func.genCopy(switch (math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
58635933 .lt => dst_ty,
58645934 .eq => if (!dst_mcv.isMemory() or src_mcv.isMemory()) dst_ty else src_ty,
......@@ -6080,7 +6150,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
60806150 .tag = .slli,
60816151 .ops = .rri,
60826152 .data = .{ .i_type = .{
6083 .imm12 = Immediate.s(4),
6153 .imm12 = Immediate.u(4),
60846154 .rd = err_reg,
60856155 .rs1 = err_reg,
60866156 } },
......@@ -6104,7 +6174,7 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
61046174 .r = start_reg,
61056175 .m = .{
61066176 .base = .{ .reg = addr_reg },
6107 .mod = .{ .off = 0 },
6177 .mod = .{ .size = .dword, .unsigned = true },
61086178 },
61096179 },
61106180 },
......@@ -6118,13 +6188,13 @@ fn airErrorName(func: *Func, inst: Air.Inst.Index) !void {
61186188 .r = end_reg,
61196189 .m = .{
61206190 .base = .{ .reg = addr_reg },
6121 .mod = .{ .off = 8 },
6191 .mod = .{ .size = .dword, .unsigned = true },
61226192 },
61236193 },
61246194 },
61256195 });
61266196
6127 const dst_mcv = try func.allocRegOrMem(inst, false);
6197 const dst_mcv = try func.allocRegOrMem(func.typeOfIndex(inst), inst, false);
61286198 const frame = dst_mcv.load_frame;
61296199 try func.genSetMem(
61306200 .{ .frame = frame.index },
src/arch/riscv64/Encoding.zig+168-53
......@@ -4,6 +4,7 @@ data: Data,
44const OpCode = enum(u7) {
55 OP = 0b0110011,
66 OP_IMM = 0b0010011,
7 OP_IMM_32 = 0b0011011,
78 OP_32 = 0b0111011,
89
910 BRANCH = 0b1100011,
......@@ -41,17 +42,22 @@ const Enc = struct {
4142 funct3: u3,
4243 funct7: u7,
4344 },
44 /// funct3 + offset
45 fo: struct {
46 funct3: u3,
47 offset: u12 = 0,
48 },
4945 /// funct5 + rm + fmt
5046 fmt: struct {
5147 funct5: u5,
5248 rm: u3,
5349 fmt: Fmt,
5450 },
51 /// funct3
52 f: struct {
53 funct3: u3,
54 },
55 /// typ + funct3 + has_5
56 sh: struct {
57 typ: u6,
58 funct3: u3,
59 has_5: bool,
60 },
5561 /// U-type
5662 none,
5763 },
......@@ -72,10 +78,14 @@ pub const Mnemonic = enum {
7278 sltiu,
7379 xori,
7480 andi,
81
7582 slli,
7683 srli,
7784 srai,
78 sllw,
85
86 slliw,
87 srliw,
88 sraiw,
7989
8090 addi,
8191 jalr,
......@@ -98,19 +108,48 @@ pub const Mnemonic = enum {
98108
99109 // R Type
100110 add,
111 addw,
112 sub,
113 subw,
101114 @"and",
102115 @"or",
103 sub,
104116 slt,
105 mul,
106117 sltu,
107118 xor,
108119
120 sll,
121 srl,
122 sra,
123
124 sllw,
125 srlw,
126 sraw,
127
109128 // System
110129 ecall,
111130 ebreak,
112131 unimp,
113132
133 // M extension
134 mul,
135 mulw,
136
137 mulh,
138 mulhu,
139 mulhsu,
140
141 div,
142 divu,
143
144 divw,
145 divuw,
146
147 rem,
148 remu,
149
150 remw,
151 remuw,
152
114153 // F extension (32-bit float)
115154 fadds,
116155 fsubs,
......@@ -170,19 +209,56 @@ pub const Mnemonic = enum {
170209 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
171210
172211 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
212 .mulh => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
213 .mulhsu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
214 .mulhu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
215
216 .div => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
217 .divu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
218
219 .rem => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
220 .remu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
221
222 .sll => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
223 .srl => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
224 .sra => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
173225
174226
175227 // OP_IMM
176228
177 .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
178 .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
179 .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
229 .addi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b000 } } },
230 .andi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b111 } } },
231 .xori => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b100 } } },
180232
181 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
233 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b011 } } },
234
235 .slli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
236 .srli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
237 .srai => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
238
239
240 // OP_IMM_32
182241
183 .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
184 .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
185 .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
242 .slliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
243 .srliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
244 .sraiw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
245
246
247 // OP_32
248
249 .addw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
250 .subw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
251 .mulw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
252
253 .divw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
254 .divuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
255
256 .remw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
257 .remuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
258
259 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
260 .srlw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
261 .sraw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
186262
187263
188264 // OP_FP
......@@ -226,43 +302,38 @@ pub const Mnemonic = enum {
226302
227303 // LOAD
228304
229 .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
230 .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
231 .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
232 .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
233 .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
234 .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
235 .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
305 .lb => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b000 } } },
306 .lh => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b001 } } },
307 .lw => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b010 } } },
308 .ld => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b011 } } },
309 .lbu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b100 } } },
310 .lhu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b101 } } },
311 .lwu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b110 } } },
236312
237313
238314 // STORE
239315
240 .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
241 .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
242 .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
243 .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
316 .sb => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b000 } } },
317 .sh => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b001 } } },
318 .sw => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b010 } } },
319 .sd => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b011 } } },
244320
245321
246322 // LOAD_FP
247323
248 .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
249 .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
324 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
325 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
250326
251327
252328 // STORE_FP
253329
254 .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
255 .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
330 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
331 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
256332
257333
258334 // JALR
259335
260 .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
261
262
263 // OP_32
264
265 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
336 .jalr => .{ .opcode = .JALR, .data = .{ .f = .{ .funct3 = 0b000 } } },
266337
267338
268339 // LUI
......@@ -282,18 +353,18 @@ pub const Mnemonic = enum {
282353
283354 // BRANCH
284355
285 .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
356 .beq => .{ .opcode = .BRANCH, .data = .{ .f = .{ .funct3 = 0b000 } } },
286357
287358
288359 // SYSTEM
289360
290 .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
291 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
361 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
362 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
292363
293364
294365 // NONE
295366
296 .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
367 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
297368
298369
299370 // zig fmt: on
......@@ -320,10 +391,15 @@ pub const InstEnc = enum {
320391 .sltiu,
321392 .xori,
322393 .andi,
394
323395 .slli,
324396 .srli,
325397 .srai,
326398
399 .slliw,
400 .srliw,
401 .sraiw,
402
327403 .ld,
328404 .lw,
329405 .lwu,
......@@ -357,14 +433,41 @@ pub const InstEnc = enum {
357433
358434 .slt,
359435 .sltu,
436
437 .sll,
438 .srl,
439 .sra,
440
360441 .sllw,
361 .mul,
442 .srlw,
443 .sraw,
444
445 .div,
446 .divu,
447 .divw,
448 .divuw,
449
450 .rem,
451 .remu,
452 .remw,
453 .remuw,
454
362455 .xor,
363 .add,
364 .sub,
365456 .@"and",
366457 .@"or",
367458
459 .add,
460 .addw,
461
462 .sub,
463 .subw,
464
465 .mul,
466 .mulw,
467 .mulh,
468 .mulhu,
469 .mulhsu,
470
368471 .fadds,
369472 .faddd,
370473
......@@ -516,12 +619,12 @@ pub const Data = union(InstEnc) {
516619 .imm0_11 = switch (mnem) {
517620 .ecall => 0x000,
518621 .ebreak => 0x001,
519 .unimp => 0,
622 .unimp => 0x000,
520623 else => unreachable,
521624 },
522625
523626 .opcode = @intFromEnum(enc.opcode),
524 .funct3 = enc.data.fo.funct3,
627 .funct3 = enc.data.f.funct3,
525628 },
526629 };
527630 },
......@@ -567,20 +670,32 @@ pub const Data = union(InstEnc) {
567670 .imm5_11 = @truncate(umm >> 5),
568671
569672 .opcode = @intFromEnum(enc.opcode),
570 .funct3 = enc.data.fo.funct3,
673 .funct3 = enc.data.f.funct3,
571674 },
572675 };
573676 },
574677 .I => {
575678 assert(ops.len == 3);
576679 return .{
577 .I = .{
578 .rd = ops[0].reg.encodeId(),
579 .rs1 = ops[1].reg.encodeId(),
580 .imm0_11 = ops[2].imm.asBits(u12) + enc.data.fo.offset,
680 .I = switch (enc.data) {
681 .f => |f| .{
682 .rd = ops[0].reg.encodeId(),
683 .rs1 = ops[1].reg.encodeId(),
684 .imm0_11 = ops[2].imm.asBits(u12),
581685
582 .opcode = @intFromEnum(enc.opcode),
583 .funct3 = enc.data.fo.funct3,
686 .opcode = @intFromEnum(enc.opcode),
687 .funct3 = f.funct3,
688 },
689 .sh => |sh| .{
690 .rd = ops[0].reg.encodeId(),
691 .rs1 = ops[1].reg.encodeId(),
692 .imm0_11 = (@as(u12, sh.typ) << 6) |
693 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
694
695 .opcode = @intFromEnum(enc.opcode),
696 .funct3 = sh.funct3,
697 },
698 else => unreachable,
584699 },
585700 };
586701 },
......@@ -629,7 +744,7 @@ pub const Data = union(InstEnc) {
629744 .imm12 = @truncate(umm >> 12),
630745
631746 .opcode = @intFromEnum(enc.opcode),
632 .funct3 = enc.data.fo.funct3,
747 .funct3 = enc.data.f.funct3,
633748 },
634749 };
635750 },
src/arch/riscv64/Lower.zig+26-14
......@@ -44,6 +44,8 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
4444 insts: []const Instruction,
4545 relocs: []const Reloc,
4646} {
47 const zcu = lower.bin_file.comp.module.?;
48
4749 lower.result_insts = undefined;
4850 lower.result_relocs = undefined;
4951 errdefer lower.result_insts = undefined;
......@@ -75,13 +77,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
7577 const dest_reg_class = dest_reg.class();
7678 const float = dest_reg_class == .float;
7779
78 const src_size = rm.m.mod.size();
80 const src_size = rm.m.mod.size;
81 const unsigned = rm.m.mod.unsigned;
7982
8083 const tag: Encoding.Mnemonic = if (!float)
8184 switch (src_size) {
82 .byte => .lb,
83 .hword => .lh,
84 .word => .lw,
85 .byte => if (unsigned) .lbu else .lb,
86 .hword => if (unsigned) .lhu else .lh,
87 .word => if (unsigned) .lwu else .lw,
8588 .dword => .ld,
8689 }
8790 else switch (src_size) {
......@@ -103,7 +106,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
103106 const float = src_reg_class == .float;
104107
105108 // TODO: do we actually need this? are all stores not usize?
106 const dest_size = rm.m.mod.size();
109 const dest_size = rm.m.mod.size;
107110
108111 const tag: Encoding.Mnemonic = if (!float)
109112 switch (dest_size) {
......@@ -181,10 +184,12 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
181184
182185 try lower.emit(.lui, &.{
183186 .{ .reg = dst_reg },
184 .{ .imm = lower.reloc(.{ .load_symbol_reloc = .{
185 .atom_index = data.atom_index,
186 .sym_index = data.sym_index,
187 } }) },
187 .{ .imm = lower.reloc(.{
188 .load_symbol_reloc = .{
189 .atom_index = data.atom_index,
190 .sym_index = data.sym_index,
191 },
192 }) },
188193 });
189194
190195 // the above reloc implies this one
......@@ -237,7 +242,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
237242 const rs2 = compare.rs2;
238243
239244 const class = rs1.class();
240 const size = compare.size.bitSize();
245 const ty = compare.ty;
246 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(zcu)) catch {
247 return lower.fail("pseudo_compare size {}", .{ty.bitSize(zcu)});
248 };
249
250 const is_unsigned = ty.isUnsignedInt(zcu);
251
252 const less_than: Encoding.Mnemonic = if (is_unsigned) .sltu else .slt;
241253
242254 switch (class) {
243255 .int => switch (op) {
......@@ -268,14 +280,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
268280 });
269281 },
270282 .gt => {
271 try lower.emit(.sltu, &.{
283 try lower.emit(less_than, &.{
272284 .{ .reg = rd },
273285 .{ .reg = rs1 },
274286 .{ .reg = rs2 },
275287 });
276288 },
277289 .gte => {
278 try lower.emit(.sltu, &.{
290 try lower.emit(less_than, &.{
279291 .{ .reg = rd },
280292 .{ .reg = rs1 },
281293 .{ .reg = rs2 },
......@@ -288,14 +300,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
288300 });
289301 },
290302 .lt => {
291 try lower.emit(.slt, &.{
303 try lower.emit(less_than, &.{
292304 .{ .reg = rd },
293305 .{ .reg = rs1 },
294306 .{ .reg = rs2 },
295307 });
296308 },
297309 .lte => {
298 try lower.emit(.slt, &.{
310 try lower.emit(less_than, &.{
299311 .{ .reg = rd },
300312 .{ .reg = rs2 },
301313 .{ .reg = rs1 },
src/arch/riscv64/Mir.zig+27-2
......@@ -39,16 +39,28 @@ pub const Inst = struct {
3939 unimp,
4040
4141 add,
42 addw,
4243 sub,
44 subw,
4345
4446 sltu,
4547 slt,
4648
47 srli,
4849 slli,
50 srli,
4951 srai,
52
53 slliw,
54 srliw,
55 sraiw,
56
57 sll,
58 srl,
59 sra,
60
5061 sllw,
5162 srlw,
63 sraw,
5264
5365 jal,
5466
......@@ -69,6 +81,17 @@ pub const Inst = struct {
6981
7082 // M extension
7183 mul,
84 mulw,
85
86 div,
87 divu,
88 divw,
89 divuw,
90
91 rem,
92 remu,
93 remw,
94 remuw,
7295
7396 // F extension (32-bit float)
7497 fadds,
......@@ -216,7 +239,7 @@ pub const Inst = struct {
216239 lt,
217240 lte,
218241 },
219 size: Memory.Size,
242 ty: Type,
220243 },
221244
222245 reloc: struct {
......@@ -408,6 +431,8 @@ pub const RegisterList = struct {
408431const Mir = @This();
409432const std = @import("std");
410433const builtin = @import("builtin");
434const Type = @import("../../type.zig").Type;
435
411436const assert = std.debug.assert;
412437
413438const bits = @import("bits.zig");
src/arch/riscv64/bits.zig+5-35
......@@ -19,19 +19,10 @@ pub const Memory = struct {
1919 reloc: Symbol,
2020 };
2121
22 pub const Mod = union(enum(u1)) {
23 rm: struct {
24 size: Size,
25 disp: i32 = 0,
26 },
27 off: i32,
28
29 pub fn size(mod: Mod) Size {
30 return switch (mod) {
31 .rm => |rm| rm.size,
32 .off => Size.dword, // assumed to be a register size
33 };
34 }
22 pub const Mod = struct {
23 size: Size,
24 unsigned: bool,
25 disp: i32 = 0,
3526 };
3627
3728 pub const Size = enum(u4) {
......@@ -76,10 +67,7 @@ pub const Memory = struct {
7667
7768 /// Asserts `mem` can be represented as a `FrameLoc`.
7869 pub fn toFrameLoc(mem: Memory, mir: Mir) Mir.FrameLoc {
79 const offset: i32 = switch (mem.mod) {
80 .off => |off| off,
81 .rm => |rm| rm.disp,
82 };
70 const offset: i32 = mem.mod.disp;
8371
8472 switch (mem.base) {
8573 .reg => |reg| {
......@@ -130,24 +118,6 @@ pub const Immediate = union(enum) {
130118 };
131119 }
132120
133 pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
134 return switch (imm) {
135 .signed => |x| switch (bit_size) {
136 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))),
137 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))),
138 32, 64 => @as(u32, @bitCast(x)),
139 else => unreachable,
140 },
141 .unsigned => |x| switch (bit_size) {
142 1, 8 => @as(u8, @intCast(x)),
143 16 => @as(u16, @intCast(x)),
144 32 => @as(u32, @intCast(x)),
145 64 => x,
146 else => unreachable,
147 },
148 };
149 }
150
151121 pub fn asBits(imm: Immediate, comptime T: type) T {
152122 const int_info = @typeInfo(T).Int;
153123 if (int_info.signedness != .unsigned) @compileError("Immediate.asBits needs unsigned T");
src/arch/riscv64/encoder.zig+25
......@@ -32,6 +32,31 @@ pub const Instruction = struct {
3232 pub fn encode(inst: Instruction, writer: anytype) !void {
3333 try writer.writeInt(u32, inst.encoding.data.toU32(), .little);
3434 }
35
36 pub fn format(
37 inst: Instruction,
38 comptime fmt: []const u8,
39 _: std.fmt.FormatOptions,
40 writer: anytype,
41 ) !void {
42 std.debug.assert(fmt.len == 0);
43
44 const encoding = inst.encoding;
45
46 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
47
48 var i: u32 = 0;
49 while (i < inst.ops.len and inst.ops[i] != .none) : (i += 1) {
50 if (i != inst.ops.len and i != 0) try writer.writeAll(", ");
51
52 switch (@as(Instruction.Operand, inst.ops[i])) {
53 .none => unreachable, // it's sliced out above
54 .reg => |reg| try writer.writeAll(@tagName(reg)),
55 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
56 .mem => unreachable, // there is no "mem" operand in the actual instructions
57 }
58 }
59 }
3560};
3661
3762const std = @import("std");
test/behavior/align.zig-1
......@@ -249,7 +249,6 @@ fn testBytesAlign(b: u8) !void {
249249}
250250
251251test "@alignCast slices" {
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
253252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
254253 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
255254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/array.zig+1-11
......@@ -50,7 +50,6 @@ fn getArrayLen(a: []const u32) usize {
5050test "array concat with undefined" {
5151 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5453
5554 const S = struct {
5655 fn doTheTest() !void {
......@@ -89,7 +88,6 @@ test "array concat with tuple" {
8988
9089test "array init with concat" {
9190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9391
9492 const a = 'a';
9593 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
......@@ -99,7 +97,6 @@ test "array init with concat" {
9997test "array init with mult" {
10098 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103100
104101 const a = 'a';
105102 var i: [8]u8 = [2]u8{ a, 'b' } ** 4;
......@@ -244,7 +241,6 @@ fn plusOne(x: u32) u32 {
244241test "single-item pointer to array indexing and slicing" {
245242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
246243 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
247 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
248244
249245 try testSingleItemPtrArrayIndexSlice();
250246 try comptime testSingleItemPtrArrayIndexSlice();
......@@ -270,7 +266,6 @@ fn doSomeMangling(array: *[4]u8) void {
270266
271267test "implicit cast zero sized array ptr to slice" {
272268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
274269
275270 {
276271 var b = "".*;
......@@ -309,7 +304,6 @@ const Str = struct { a: []Sub };
309304test "set global var array via slice embedded in struct" {
310305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
311306 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
313307
314308 var s = Str{ .a = s_array[0..] };
315309
......@@ -376,7 +370,6 @@ test "comptime evaluating function that takes array by value" {
376370test "runtime initialize array elem and then implicit cast to slice" {
377371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
378372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
380373
381374 var two: i32 = 2;
382375 _ = &two;
......@@ -387,7 +380,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
387380test "array literal as argument to function" {
388381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
389382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
391383
392384 const S = struct {
393385 fn entry(two: i32) !void {
......@@ -416,7 +408,6 @@ test "double nested array to const slice cast in array literal" {
416408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
417409 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
418410 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
419 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
420411
421412 const S = struct {
422413 fn entry(two: i32) !void {
......@@ -522,7 +513,6 @@ test "type deduction for array subscript expression" {
522513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
523514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
524515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
526516
527517 const S = struct {
528518 fn doTheTest() !void {
......@@ -542,6 +532,7 @@ test "sentinel element count towards the ABI size calculation" {
542532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
543533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
544534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
545536
546537 const S = struct {
547538 fn doTheTest() !void {
......@@ -956,7 +947,6 @@ test "array initialized with string literal" {
956947
957948test "array initialized with array with sentinel" {
958949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
959 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
960950
961951 const S = struct {
962952 a: u32,
test/behavior/basic.zig-3
......@@ -709,7 +709,6 @@ test "result location is optional inside error union" {
709709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
711711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
713712
714713 const x = maybe(true) catch unreachable;
715714 try expect(x.? == 42);
......@@ -1091,8 +1090,6 @@ test "orelse coercion as function argument" {
10911090}
10921091
10931092test "runtime-known globals initialized with undefined" {
1094 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1095
10961093 const S = struct {
10971094 var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
10981095 var vp: [*]u32 = undefined;
test/behavior/bitcast.zig+3
......@@ -165,6 +165,7 @@ test "@bitCast packed structs at runtime and comptime" {
165165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167167 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
168 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
168169
169170 const Full = packed struct {
170171 number: u16,
......@@ -191,6 +192,7 @@ test "@bitCast packed structs at runtime and comptime" {
191192test "@bitCast extern structs at runtime and comptime" {
192193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
193194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
194196
195197 const Full = extern struct {
196198 number: u16,
......@@ -225,6 +227,7 @@ test "bitcast packed struct to integer and back" {
225227 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226228 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227229 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
228231
229232 const LevelUpMove = packed struct {
230233 move_id: u9,
test/behavior/byval_arg_var.zig-1
......@@ -5,7 +5,6 @@ var result: []const u8 = "wrong";
55
66test "pass string literal byvalue to a generic var param" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
109
1110 start();
test/behavior/cast.zig+1-24
......@@ -266,7 +266,6 @@ fn MakeType(comptime T: type) type {
266266test "implicit cast from *[N]T to [*c]T" {
267267 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
268268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
270269
271270 var x: [4]u16 = [4]u16{ 0, 1, 2, 3 };
272271 var y: [*c]u16 = &x;
......@@ -343,7 +342,6 @@ test "array coercion to undefined at runtime" {
343342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
344343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
345344 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
346 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
347345
348346 @setRuntimeSafety(true);
349347
......@@ -409,7 +407,6 @@ test "peer type unsigned int to signed" {
409407test "expected [*c]const u8, found [*:0]const u8" {
410408 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
411409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
412 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
413410
414411 var a: [*:0]const u8 = "hello";
415412 _ = &a;
......@@ -496,7 +493,6 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
496493 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
497494 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
498495 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
500496
501497 const S = struct {
502498 fn doTheTest() anyerror!void {
......@@ -577,7 +573,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
577573test "single-item pointer of array to slice to unknown length pointer" {
578574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
579575 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
580 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
581576
582577 try testCastPtrOfArrayToSliceAndPtr();
583578 try comptime testCastPtrOfArrayToSliceAndPtr();
......@@ -673,6 +668,7 @@ test "@floatCast cast down" {
673668test "peer type resolution: unreachable, error set, unreachable" {
674669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
675670 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
671 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
676672
677673 const Error = error{
678674 FileDescriptorAlreadyPresentInSet,
......@@ -834,7 +830,6 @@ test "peer cast *[0]T to E![]const T" {
834830 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
835831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
836832 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
837 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
838833
839834 var buffer: [5]u8 = "abcde".*;
840835 const buf: anyerror![]const u8 = buffer[0..];
......@@ -850,7 +845,6 @@ test "peer cast *[0]T to []const T" {
850845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
851846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852847 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
853 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
854848
855849 var buffer: [5]u8 = "abcde".*;
856850 const buf: []const u8 = buffer[0..];
......@@ -895,7 +889,6 @@ test "peer resolution of string literals" {
895889test "peer cast [:x]T to []T" {
896890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
897891 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
898 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
899892
900893 const S = struct {
901894 fn doTheTest() !void {
......@@ -912,7 +905,6 @@ test "peer cast [:x]T to []T" {
912905test "peer cast [N:x]T to [N]T" {
913906 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
914907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
916908
917909 const S = struct {
918910 fn doTheTest() !void {
......@@ -929,7 +921,6 @@ test "peer cast [N:x]T to [N]T" {
929921test "peer cast *[N:x]T to *[N]T" {
930922 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
931923 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
933924
934925 const S = struct {
935926 fn doTheTest() !void {
......@@ -987,7 +978,6 @@ test "peer cast [:x]T to [*:x]T" {
987978test "peer type resolution implicit cast to return type" {
988979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
989980 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
990 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
991981
992982 const S = struct {
993983 fn doTheTest() !void {
......@@ -1008,7 +998,6 @@ test "peer type resolution implicit cast to return type" {
1008998test "peer type resolution implicit cast to variable type" {
1009999 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10101000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1011 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10121001
10131002 const S = struct {
10141003 fn doTheTest() !void {
......@@ -1052,7 +1041,6 @@ test "cast between C pointer with different but compatible types" {
10521041test "peer type resolve string lit with sentinel-terminated mutable slice" {
10531042 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10541043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1055 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10561044
10571045 var array: [4:0]u8 = undefined;
10581046 array[4] = 0; // TODO remove this when #4372 is solved
......@@ -1119,7 +1107,6 @@ test "implicit cast from [*]T to ?*anyopaque" {
11191107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11201108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11211109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1122 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11231110
11241111 var a = [_]u8{ 3, 2, 1 };
11251112 var runtime_zero: usize = 0;
......@@ -1319,7 +1306,6 @@ test "*const [N]null u8 to ?[]const u8" {
13191306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13201307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13211308 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1322 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13231309
13241310 const S = struct {
13251311 fn doTheTest() !void {
......@@ -1363,7 +1349,6 @@ test "assignment to optional pointer result loc" {
13631349}
13641350
13651351test "cast between *[N]void and []void" {
1366 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13671352 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13681353
13691354 var a: [4]void = undefined;
......@@ -1618,8 +1603,6 @@ test "optional slice passed as parameter coerced to allowzero many pointer" {
16181603}
16191604
16201605test "single item pointer to pointer to array to slice" {
1621 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1622
16231606 var x: i32 = 1234;
16241607 try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234);
16251608 const z1 = @as([]const i32, @as(*[1]i32, &x));
......@@ -1662,8 +1645,6 @@ test "@volatileCast without a result location" {
16621645}
16631646
16641647test "coercion from single-item pointer to @as to slice" {
1665 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1666
16671648 var x: u32 = 1;
16681649
16691650 // Why the following line gets a compile error?
......@@ -1728,7 +1709,6 @@ test "peer type resolution: same array type with sentinel" {
17281709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17291710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17301711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1731 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17321712
17331713 var a: [2:0]u32 = .{ 0, 1 };
17341714 var b: [2:0]u32 = .{ 2, 3 };
......@@ -1751,7 +1731,6 @@ test "peer type resolution: array with sentinel and array without sentinel" {
17511731 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17521732 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17531733 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1754 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17551734
17561735 var a: [2:0]u32 = .{ 0, 1 };
17571736 var b: [2]u32 = .{ 2, 3 };
......@@ -1956,7 +1935,6 @@ test "peer type resolution: array and tuple" {
19561935 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19571936 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19581937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1959 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19601938
19611939 var arr: [3]i32 = .{ 1, 2, 3 };
19621940 _ = &arr;
......@@ -2281,7 +2259,6 @@ test "peer type resolution: arrays of compatible types" {
22812259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22822260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22832261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2284 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
22852262
22862263 var e0: u8 = 3;
22872264 var e1: u8 = 2;
test/behavior/enum.zig+1
......@@ -618,6 +618,7 @@ test "enum with specified tag values" {
618618test "non-exhaustive enum" {
619619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620620 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
621 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
621622
622623 const S = struct {
623624 const E = enum(u8) { a, b, _ };
test/behavior/error.zig-1
......@@ -856,7 +856,6 @@ test "alignment of wrapping an error union payload" {
856856
857857test "compare error union and error set" {
858858 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
859 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
860859
861860 var a: anyerror = error.Foo;
862861 var b: anyerror!u32 = error.Bar;
test/behavior/eval.zig+2-3
......@@ -395,6 +395,7 @@ test "return 0 from function that has u0 return type" {
395395test "statically initialized struct" {
396396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
397397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
398399
399400 st_init_str_foo.x += 1;
400401 try expect(st_init_str_foo.x == 14);
......@@ -740,7 +741,6 @@ test "array concatenation of function calls" {
740741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
741742 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
742743 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
743 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
744744
745745 var a = oneItem(3) ++ oneItem(4);
746746 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
......@@ -750,7 +750,6 @@ test "array multiplication of function calls" {
750750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
751751 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
752752 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
753 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
754753
755754 var a = oneItem(3) ** scalar(2);
756755 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
......@@ -768,7 +767,6 @@ test "array concatenation peer resolves element types - value" {
768767 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
769768 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
770769 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
771 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
772770
773771 var a = [2]u3{ 1, 7 };
774772 var b = [3]u8{ 200, 225, 255 };
......@@ -786,6 +784,7 @@ test "array concatenation peer resolves element types - pointer" {
786784 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
787785 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
788786 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
789788
790789 var a = [2]u3{ 1, 7 };
791790 var b = [3]u8{ 200, 225, 255 };
test/behavior/for.zig-5
......@@ -200,7 +200,6 @@ test "for on slice with allowzero ptr" {
200200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
201201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
202202 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
204203
205204 const S = struct {
206205 fn doTheTest(slice: []const u8) !void {
......@@ -216,7 +215,6 @@ test "for on slice with allowzero ptr" {
216215test "else continue outer for" {
217216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
218217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
220218
221219 var i: usize = 6;
222220 var buf: [5]u8 = undefined;
......@@ -313,7 +311,6 @@ test "slice and two counters, one is offset and one is runtime" {
313311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
314312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
317314
318315 const slice: []const u8 = "blah";
319316 var start: usize = 0;
......@@ -343,7 +340,6 @@ test "two slices, one captured by-ref" {
343340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
347343
348344 var buf: [10]u8 = undefined;
349345 const slice1: []const u8 = "blah";
......@@ -400,7 +396,6 @@ test "inline for with slice as the comptime-known" {
400396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
402398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
404399
405400 const comptime_slice = "hello";
406401 var runtime_i: usize = 3;
test/behavior/generics.zig-2
......@@ -158,7 +158,6 @@ test "generic fn with implicit cast" {
158158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
159159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
162161
163162 try expect(getFirstByte(u8, &[_]u8{13}) == 13);
164163 try expect(getFirstByte(u16, &[_]u16{
......@@ -320,7 +319,6 @@ test "generic function instantiation non-duplicates" {
320319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
321320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
324322 if (builtin.os.tag == .wasi) return error.SkipZigTest;
325323
326324 const S = struct {
test/behavior/globals.zig-1
......@@ -29,7 +29,6 @@ test "slices pointing at the same address as global array." {
2929 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3332
3433 const S = struct {
3534 const a = [_]u8{ 1, 2, 3 };
test/behavior/if.zig-1
......@@ -45,7 +45,6 @@ var global_with_err: anyerror!u32 = error.SomeError;
4545
4646test "unwrap mutable global var" {
4747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4948
5049 if (global_with_val) |v| {
5150 try expect(v == 0);
test/behavior/inline_switch.zig-1
......@@ -76,7 +76,6 @@ test "inline switch unions" {
7676test "inline else bool" {
7777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7878 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8079
8180 var a = true;
8281 _ = &a;
test/behavior/math.zig-6
......@@ -592,8 +592,6 @@ fn testSignedWrappingEval(x: i32) !void {
592592}
593593
594594test "signed negation wrapping" {
595 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
596
597595 try testSignedNegationWrappingEval(minInt(i16));
598596 try comptime testSignedNegationWrappingEval(minInt(i16));
599597}
......@@ -664,8 +662,6 @@ test "bit shift a u1" {
664662}
665663
666664test "truncating shift right" {
667 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
668
669665 try testShrTrunc(maxInt(u16));
670666 try comptime testShrTrunc(maxInt(u16));
671667}
......@@ -1455,8 +1451,6 @@ fn testShlExact(x: u8) !void {
14551451}
14561452
14571453test "exact shift right" {
1458 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1459
14601454 try testShrExact(0b10110100);
14611455 try comptime testShrExact(0b10110100);
14621456}
test/behavior/nan.zig-1
......@@ -26,7 +26,6 @@ test "nan memory equality" {
2626 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2727 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2828 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3029
3130 // signaled
3231 try testing.expect(mem.eql(u8, mem.asBytes(&snan_u16), mem.asBytes(&snan_f16)));
test/behavior/optional.zig-2
......@@ -488,7 +488,6 @@ const NoReturn = struct {
488488
489489test "optional of noreturn used with if" {
490490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
491 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
492491
493492 NoReturn.a = 64;
494493 if (NoReturn.loop()) |_| {
......@@ -500,7 +499,6 @@ test "optional of noreturn used with if" {
500499
501500test "optional of noreturn used with orelse" {
502501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
503 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
504502
505503 NoReturn.a = 64;
506504 const val = NoReturn.testOrelse();
test/behavior/packed-struct.zig+2-2
......@@ -258,6 +258,7 @@ test "nested packed struct unaligned" {
258258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
259259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
261262 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
262263
263264 const S1 = packed struct {
......@@ -330,6 +331,7 @@ test "byte-aligned field pointer offsets" {
330331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
331332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
332333 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
333335
334336 const S = struct {
335337 const A = packed struct {
......@@ -491,7 +493,6 @@ test "@intFromPtr on a packed struct field" {
491493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
492494 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493495 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
494 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
495496 if (native_endian != .little) return error.SkipZigTest;
496497
497498 const S = struct {
......@@ -515,7 +516,6 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
515516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
516517 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
517518 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
518 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
519519 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
520520
521521 const S1 = packed struct {
test/behavior/pointers.zig-3
......@@ -201,7 +201,6 @@ test "allowzero pointer and slice" {
201201 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
202202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
203203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
205204
206205 var ptr: [*]allowzero i32 = @ptrFromInt(0);
207206 const opt_ptr: ?[*]allowzero i32 = ptr;
......@@ -440,7 +439,6 @@ test "indexing array with sentinel returns correct type" {
440439test "element pointer to slice" {
441440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
442441 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
443 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
444442
445443 const S = struct {
446444 fn doTheTest() !void {
......@@ -488,7 +486,6 @@ test "element pointer arithmetic to slice" {
488486
489487test "array slicing to slice" {
490488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
491 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
492489
493490 const S = struct {
494491 fn doTheTest() !void {
test/behavior/ptrcast.zig-2
......@@ -232,7 +232,6 @@ test "implicit optional pointer to optional anyopaque pointer" {
232232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
233233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
234234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
236235
237236 var buf: [4]u8 = "aoeu".*;
238237 const x: ?[*]u8 = &buf;
......@@ -245,7 +244,6 @@ test "@ptrCast slice to slice" {
245244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
246245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
247246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
249247
250248 const S = struct {
251249 fn foo(slice: []u32) []i32 {
test/behavior/reflection.zig+1
......@@ -28,6 +28,7 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2828test "reflection: @field" {
2929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3030 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3132
3233 var f = Foo{
3334 .one = 42,
test/behavior/sizeof_and_typeof.zig-1
......@@ -81,7 +81,6 @@ const P = packed struct {
8181test "@offsetOf" {
8282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8383 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8584
8685 // Packed structs have fixed memory layout
8786 try expect(@offsetOf(P, "a") == 0);
test/behavior/slice.zig-12
......@@ -67,7 +67,6 @@ test "comptime slice of undefined pointer of length 0" {
6767
6868test "implicitly cast array of size 0 to slice" {
6969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7170
7271 var msg = [_]u8{};
7372 try assertLenIsZero(&msg);
......@@ -233,7 +232,6 @@ test "runtime safety lets us slice from len..len" {
233232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
234233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
235234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
237235
238236 var an_array = [_]u8{ 1, 2, 3 };
239237 try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
......@@ -289,7 +287,6 @@ fn sliceSum(comptime q: []const u8) i32 {
289287test "slice type with custom alignment" {
290288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
291289 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
293290
294291 const LazilyResolvedType = struct {
295292 anything: i32,
......@@ -347,7 +344,6 @@ test "empty array to slice" {
347344test "@ptrCast slice to pointer" {
348345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
349346 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
351347
352348 const S = struct {
353349 fn doTheTest() !void {
......@@ -402,7 +398,6 @@ test "slice syntax resulting in pointer-to-array" {
402398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
403399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
406401 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
407402
408403 const S = struct {
......@@ -622,7 +617,6 @@ test "slice syntax resulting in pointer-to-array" {
622617test "slice pointer-to-array null terminated" {
623618 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
624619 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
626620
627621 comptime {
628622 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
......@@ -641,7 +635,6 @@ test "slice pointer-to-array null terminated" {
641635
642636test "slice pointer-to-array zero length" {
643637 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
644 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
645638
646639 comptime {
647640 {
......@@ -676,7 +669,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
676669 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
677670 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
678671 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
679 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
680672
681673 const S = struct {
682674 const U = union {
......@@ -786,7 +778,6 @@ test "slicing array with sentinel as end index" {
786778test "slicing slice with sentinel as end index" {
787779 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
788780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
790781
791782 const S = struct {
792783 fn do() !void {
......@@ -857,7 +848,6 @@ test "global slice field access" {
857848}
858849
859850test "slice of void" {
860 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
861851 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
862852
863853 var n: usize = 10;
......@@ -981,7 +971,6 @@ test "get address of element of zero-sized slice" {
981971 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
982972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
983973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
984 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
985974 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
986975
987976 const S = struct {
......@@ -996,7 +985,6 @@ test "sentinel-terminated 0-length slices" {
996985 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
997986 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
998987 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
999 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1000988
1001989 const u32s: [4]u32 = [_]u32{ 0, 1, 2, 3 };
1002990
test/behavior/struct.zig+4
......@@ -68,6 +68,7 @@ const SmallStruct = struct {
6868
6969test "lower unnamed constants" {
7070 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7172
7273 var foo = SmallStruct{ .a = 1, .b = 255 };
7374 try expect(foo.first() == 1);
......@@ -874,6 +875,7 @@ test "packed struct field passed to generic function" {
874875test "anonymous struct literal syntax" {
875876 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
876877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
877879
878880 const S = struct {
879881 const Point = struct {
......@@ -1103,6 +1105,7 @@ test "packed struct with undefined initializers" {
11031105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11041106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11051107 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11061109
11071110 const S = struct {
11081111 const P = packed struct {
......@@ -1365,6 +1368,7 @@ test "store to comptime field" {
13651368test "struct field init value is size of the struct" {
13661369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13671370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1371 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13681372
13691373 const namespace = struct {
13701374 const S = extern struct {
test/behavior/struct_contains_slice_of_itself.zig-2
......@@ -13,7 +13,6 @@ const NodeAligned = struct {
1313
1414test "struct contains slice of itself" {
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1716
1817 var other_nodes = [_]Node{
1918 Node{
......@@ -54,7 +53,6 @@ test "struct contains slice of itself" {
5453test "struct contains aligned slice of itself" {
5554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5856
5957 var other_nodes = [_]NodeAligned{
6058 NodeAligned{
test/behavior/switch.zig-4
......@@ -118,7 +118,6 @@ fn trueIfBoolFalseOtherwise(comptime T: type) bool {
118118
119119test "switching on booleans" {
120120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
122121
123122 try testSwitchOnBools();
124123 try comptime testSwitchOnBools();
......@@ -277,7 +276,6 @@ fn testSwitchEnumPtrCapture() !void {
277276
278277test "switch handles all cases of number" {
279278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281279
282280 try testSwitchHandleAllCases();
283281 try comptime testSwitchHandleAllCases();
......@@ -647,7 +645,6 @@ test "switch prong pointer capture alignment" {
647645test "switch on pointer type" {
648646 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
649647 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
650 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
651648
652649 const S = struct {
653650 const X = struct {
......@@ -912,7 +909,6 @@ test "peer type resolution on switch captures ignores unused payload bits" {
912909test "switch prong captures range" {
913910 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
914911 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
916912
917913 const S = struct {
918914 fn a(b: []u3, c: u3) void {
test/behavior/this.zig+1
......@@ -27,6 +27,7 @@ test "this refer to module call private fn" {
2727test "this refer to container" {
2828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3031
3132 var pt: Point(i32) = undefined;
3233 pt.x = 12;
test/behavior/undefined.zig-1
......@@ -91,7 +91,6 @@ test "reslice of undefined global var slice" {
9191 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
9292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9594
9695 var stack_buf: [100]u8 = [_]u8{0} ** 100;
9796 buf = &stack_buf;
test/behavior/union.zig+3
......@@ -2044,6 +2044,7 @@ test "extern union initialized via reintepreted struct field initializer" {
20442044
20452045test "packed union initialized via reintepreted struct field initializer" {
20462046 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20472048
20482049 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20492050
......@@ -2064,6 +2065,7 @@ test "packed union initialized via reintepreted struct field initializer" {
20642065
20652066test "store of comptime reinterpreted memory to extern union" {
20662067 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2068 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20672069
20682070 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20692071
......@@ -2086,6 +2088,7 @@ test "store of comptime reinterpreted memory to extern union" {
20862088
20872089test "store of comptime reinterpreted memory to packed union" {
20882090 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2091 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20892092
20902093 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20912094
test/behavior/vector.zig-1
......@@ -166,7 +166,6 @@ test "array to vector" {
166166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
167167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
168168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
170169
171170 const S = struct {
172171 fn doTheTest() !void {
test/behavior/while.zig-1
......@@ -379,7 +379,6 @@ test "while loop with comptime true condition needs no else block to return valu
379379test "int returned from switch in while" {
380380 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
381381 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
383382
384383 var x: u32 = 3;
385384 const val: usize = while (true) switch (x) {
test/behavior/widening.zig-2
......@@ -32,7 +32,6 @@ test "implicit unsigned integer to signed integer" {
3232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3434 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635
3736 var a: u8 = 250;
3837 var b: i16 = a;
......@@ -80,7 +79,6 @@ test "cast small unsigned to larger signed" {
8079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8281 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
8482
8583 try expect(castSmallUnsignedToLargerSigned1(200) == @as(i16, 200));
8684 try expect(castSmallUnsignedToLargerSigned2(9999) == @as(i64, 9999));