authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-24 20:29:21+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-24 20:29:21+02:00
log905a18849f7f2c3f269fbf425170e0c86b12524a
tree437c299f0a0c141c8593d3ff69a59e8840469a73
parent7c87f9c828282aa12fb2d77c9c6a2318d83b8dff
parent672d6df42900b8521597c58af64a723985bbfd36
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11923 from koachan/sparc64-codegen

stage2: sparc64: Another batch of new Air lowerings, improvements, and fixes

9 files changed, 895 insertions(+), 213 deletions(-)

src/arch/sparc64/CodeGen.zig+627-191
...@@ -13,6 +13,7 @@ const link = @import("../../link.zig");...@@ -13,6 +13,7 @@ const link = @import("../../link.zig");
13const Module = @import("../../Module.zig");13const Module = @import("../../Module.zig");
14const TypedValue = @import("../../TypedValue.zig");14const TypedValue = @import("../../TypedValue.zig");
15const ErrorMsg = Module.ErrorMsg;15const ErrorMsg = Module.ErrorMsg;
16const codegen = @import("../../codegen.zig");
16const Air = @import("../../Air.zig");17const Air = @import("../../Air.zig");
17const Mir = @import("Mir.zig");18const Mir = @import("Mir.zig");
18const Emit = @import("Emit.zig");19const Emit = @import("Emit.zig");
...@@ -26,6 +27,8 @@ const build_options = @import("build_options");...@@ -26,6 +27,8 @@ const build_options = @import("build_options");
2627
27const bits = @import("bits.zig");28const bits = @import("bits.zig");
28const abi = @import("abi.zig");29const abi = @import("abi.zig");
30const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
31const errUnionErrorOffset = codegen.errUnionErrorOffset;
29const Instruction = bits.Instruction;32const Instruction = bits.Instruction;
30const ShiftWidth = Instruction.ShiftWidth;33const ShiftWidth = Instruction.ShiftWidth;
31const RegisterManager = abi.RegisterManager;34const RegisterManager = abi.RegisterManager;
...@@ -93,8 +96,11 @@ register_manager: RegisterManager = .{},...@@ -93,8 +96,11 @@ register_manager: RegisterManager = .{},
93/// Maps offset to what is stored there.96/// Maps offset to what is stored there.
94stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},97stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
9598
96/// Tracks the current instruction allocated to the compare flags99/// Tracks the current instruction allocated to the condition flags
97compare_flags_inst: ?Air.Inst.Index = null,100condition_flags_inst: ?Air.Inst.Index = null,
101
102/// Tracks the current instruction allocated to the condition register
103condition_register_inst: ?Air.Inst.Index = null,
98104
99/// Offset from the stack base, representing the end of the stack frame.105/// Offset from the stack base, representing the end of the stack frame.
100max_end_stack: u32 = 0,106max_end_stack: u32 = 0,
...@@ -141,17 +147,19 @@ const MCValue = union(enum) {...@@ -141,17 +147,19 @@ const MCValue = union(enum) {
141 stack_offset: u32,147 stack_offset: u32,
142 /// The value is a pointer to one of the stack variables (payload is stack offset).148 /// The value is a pointer to one of the stack variables (payload is stack offset).
143 ptr_stack_offset: u32,149 ptr_stack_offset: u32,
144 /// The value is in the specified CCR assuming an unsigned operation,150 /// The value is in the specified CCR. The value is 1 (if
145 /// with the operator applied on top of it.151 /// the type is u1) or true (if the type in bool) iff the
146 compare_flags_unsigned: struct {152 /// specified condition is true.
147 cmp: math.CompareOperator,153 condition_flags: struct {
154 cond: Instruction.Condition,
148 ccr: Instruction.CCR,155 ccr: Instruction.CCR,
149 },156 },
150 /// The value is in the specified CCR assuming an signed operation,157 /// The value is in the specified Register. The value is 1 (if
151 /// with the operator applied on top of it.158 /// the type is u1) or true (if the type in bool) iff the
152 compare_flags_signed: struct {159 /// specified condition is true.
153 cmp: math.CompareOperator,160 condition_register: struct {
154 ccr: Instruction.CCR,161 cond: Instruction.RCondition,
162 reg: Register,
155 },163 },
156164
157 fn isMemory(mcv: MCValue) bool {165 fn isMemory(mcv: MCValue) bool {
...@@ -176,6 +184,8 @@ const MCValue = union(enum) {...@@ -176,6 +184,8 @@ const MCValue = union(enum) {
176184
177 .immediate,185 .immediate,
178 .memory,186 .memory,
187 .condition_flags,
188 .condition_register,
179 .ptr_stack_offset,189 .ptr_stack_offset,
180 .undef,190 .undef,
181 => false,191 => false,
...@@ -226,26 +236,12 @@ const CallMCValues = struct {...@@ -226,26 +236,12 @@ const CallMCValues = struct {
226const BigTomb = struct {236const BigTomb = struct {
227 function: *Self,237 function: *Self,
228 inst: Air.Inst.Index,238 inst: Air.Inst.Index,
229 tomb_bits: Liveness.Bpi,239 lbt: Liveness.BigTomb,
230 big_tomb_bits: u32,
231 bit_index: usize,
232240
233 fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {241 fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
234 const this_bit_index = bt.bit_index;242 const dies = bt.lbt.feed();
235 bt.bit_index += 1;243 const op_index = Air.refToIndex(op_ref) orelse return;
236244 if (!dies) return;
237 const op_int = @enumToInt(op_ref);
238 if (op_int < Air.Inst.Ref.typed_value_map.len) return;
239 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
240
241 if (this_bit_index < Liveness.bpi - 1) {
242 const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
243 if (!dies) return;
244 } else {
245 const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
246 const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
247 if (!dies) return;
248 }
249 bt.function.processDeath(op_index);245 bt.function.processDeath(op_index);
250 }246 }
251247
...@@ -511,8 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -511,8 +507,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
511 .mul => @panic("TODO try self.airMul(inst)"),507 .mul => @panic("TODO try self.airMul(inst)"),
512 .mulwrap => @panic("TODO try self.airMulWrap(inst)"),508 .mulwrap => @panic("TODO try self.airMulWrap(inst)"),
513 .mul_sat => @panic("TODO try self.airMulSat(inst)"),509 .mul_sat => @panic("TODO try self.airMulSat(inst)"),
514 .rem => @panic("TODO try self.airRem(inst)"),510 .rem => try self.airRem(inst),
515 .mod => @panic("TODO try self.airMod(inst)"),511 .mod => try self.airMod(inst),
516 .shl, .shl_exact => @panic("TODO try self.airShl(inst)"),512 .shl, .shl_exact => @panic("TODO try self.airShl(inst)"),
517 .shl_sat => @panic("TODO try self.airShlSat(inst)"),513 .shl_sat => @panic("TODO try self.airShlSat(inst)"),
518 .min => @panic("TODO try self.airMin(inst)"),514 .min => @panic("TODO try self.airMin(inst)"),
...@@ -553,9 +549,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -553,9 +549,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
553549
554 .bool_and => @panic("TODO try self.airBoolOp(inst)"),550 .bool_and => @panic("TODO try self.airBoolOp(inst)"),
555 .bool_or => @panic("TODO try self.airBoolOp(inst)"),551 .bool_or => @panic("TODO try self.airBoolOp(inst)"),
556 .bit_and => @panic("TODO try self.airBitAnd(inst)"),552 .bit_and => try self.airBinOp(inst, .bit_and),
557 .bit_or => @panic("TODO try self.airBitOr(inst)"),553 .bit_or => try self.airBinOp(inst, .bit_or),
558 .xor => @panic("TODO try self.airXor(inst)"),554 .xor => try self.airBinOp(inst, .xor),
559 .shr, .shr_exact => @panic("TODO try self.airShr(inst)"),555 .shr, .shr_exact => @panic("TODO try self.airShr(inst)"),
560556
561 .alloc => try self.airAlloc(inst),557 .alloc => try self.airAlloc(inst),
...@@ -568,17 +564,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -568,17 +564,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
568 .breakpoint => try self.airBreakpoint(),564 .breakpoint => try self.airBreakpoint(),
569 .ret_addr => @panic("TODO try self.airRetAddr(inst)"),565 .ret_addr => @panic("TODO try self.airRetAddr(inst)"),
570 .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),566 .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
571 .fence => @panic("TODO try self.airFence()"),567 .fence => try self.airFence(inst),
572 .cond_br => try self.airCondBr(inst),568 .cond_br => try self.airCondBr(inst),
573 .dbg_stmt => try self.airDbgStmt(inst),569 .dbg_stmt => try self.airDbgStmt(inst),
574 .fptrunc => @panic("TODO try self.airFptrunc(inst)"),570 .fptrunc => @panic("TODO try self.airFptrunc(inst)"),
575 .fpext => @panic("TODO try self.airFpext(inst)"),571 .fpext => @panic("TODO try self.airFpext(inst)"),
576 .intcast => @panic("TODO try self.airIntCast(inst)"),572 .intcast => try self.airIntCast(inst),
577 .trunc => @panic("TODO try self.airTrunc(inst)"),573 .trunc => @panic("TODO try self.airTrunc(inst)"),
578 .bool_to_int => @panic("TODO try self.airBoolToInt(inst)"),574 .bool_to_int => try self.airBoolToInt(inst),
579 .is_non_null => @panic("TODO try self.airIsNonNull(inst)"),575 .is_non_null => try self.airIsNonNull(inst),
580 .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"),576 .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"),
581 .is_null => @panic("TODO try self.airIsNull(inst)"),577 .is_null => try self.airIsNull(inst),
582 .is_null_ptr => @panic("TODO try self.airIsNullPtr(inst)"),578 .is_null_ptr => @panic("TODO try self.airIsNullPtr(inst)"),
583 .is_non_err => try self.airIsNonErr(inst),579 .is_non_err => try self.airIsNonErr(inst),
584 .is_non_err_ptr => @panic("TODO try self.airIsNonErrPtr(inst)"),580 .is_non_err_ptr => @panic("TODO try self.airIsNonErrPtr(inst)"),
...@@ -601,7 +597,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -601,7 +597,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
601 .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"),597 .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"),
602 .atomic_load => @panic("TODO try self.airAtomicLoad(inst)"),598 .atomic_load => @panic("TODO try self.airAtomicLoad(inst)"),
603 .memcpy => @panic("TODO try self.airMemcpy(inst)"),599 .memcpy => @panic("TODO try self.airMemcpy(inst)"),
604 .memset => @panic("TODO try self.airMemset(inst)"),600 .memset => try self.airMemset(inst),
605 .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"),601 .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"),
606 .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"),602 .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"),
607 .clz => @panic("TODO try self.airClz(inst)"),603 .clz => @panic("TODO try self.airClz(inst)"),
...@@ -615,12 +611,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -615,12 +611,12 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
615 .select => @panic("TODO try self.airSelect(inst)"),611 .select => @panic("TODO try self.airSelect(inst)"),
616 .shuffle => @panic("TODO try self.airShuffle(inst)"),612 .shuffle => @panic("TODO try self.airShuffle(inst)"),
617 .reduce => @panic("TODO try self.airReduce(inst)"),613 .reduce => @panic("TODO try self.airReduce(inst)"),
618 .aggregate_init => @panic("TODO try self.airAggregateInit(inst)"),614 .aggregate_init => try self.airAggregateInit(inst),
619 .union_init => @panic("TODO try self.airUnionInit(inst)"),615 .union_init => @panic("TODO try self.airUnionInit(inst)"),
620 .prefetch => @panic("TODO try self.airPrefetch(inst)"),616 .prefetch => @panic("TODO try self.airPrefetch(inst)"),
621 .mul_add => @panic("TODO try self.airMulAdd(inst)"),617 .mul_add => @panic("TODO try self.airMulAdd(inst)"),
622618
623 .@"try" => @panic("TODO try self.airTry(inst)"),619 .@"try" => try self.airTry(inst),
624 .try_ptr => @panic("TODO try self.airTryPtr(inst)"),620 .try_ptr => @panic("TODO try self.airTryPtr(inst)"),
625621
626 .dbg_var_ptr,622 .dbg_var_ptr,
...@@ -659,7 +655,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -659,7 +655,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
659 .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"),655 .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"),
660 .ptr_slice_ptr_ptr => @panic("TODO try self.airPtrSlicePtrPtr(inst)"),656 .ptr_slice_ptr_ptr => @panic("TODO try self.airPtrSlicePtrPtr(inst)"),
661657
662 .array_elem_val => @panic("TODO try self.airArrayElemVal(inst)"),658 .array_elem_val => try self.airArrayElemVal(inst),
663 .slice_elem_val => try self.airSliceElemVal(inst),659 .slice_elem_val => try self.airSliceElemVal(inst),
664 .slice_elem_ptr => @panic("TODO try self.airSliceElemPtr(inst)"),660 .slice_elem_ptr => @panic("TODO try self.airSliceElemPtr(inst)"),
665 .ptr_elem_val => @panic("TODO try self.airPtrElemVal(inst)"),661 .ptr_elem_val => @panic("TODO try self.airPtrElemVal(inst)"),
...@@ -676,7 +672,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -676,7 +672,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
676 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),672 .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst),
677 .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"),673 .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"),
678 .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"),674 .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"),
679 .errunion_payload_ptr_set => @panic("TODO try self.airErrUnionPayloadPtrSet(inst)"),675 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
680 .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"),676 .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"),
681 .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"),677 .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"),
682678
...@@ -738,8 +734,8 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -738,8 +734,8 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
738 else => unreachable,734 else => unreachable,
739 };735 };
740736
741 try self.spillCompareFlagsIfOccupied();737 try self.spillConditionFlagsIfOccupied();
742 self.compare_flags_inst = inst;738 self.condition_flags_inst = inst;
743739
744 const dest = blk: {740 const dest = blk: {
745 if (rhs_immediate_ok) {741 if (rhs_immediate_ok) {
...@@ -781,11 +777,39 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -781,11 +777,39 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
781 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });777 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
782}778}
783779
780fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
781 const vector_ty = self.air.typeOfIndex(inst);
782 const len = vector_ty.vectorLen();
783 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
784 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
785 const result: MCValue = res: {
786 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
787 return self.fail("TODO implement airAggregateInit for {}", .{self.target.cpu.arch});
788 };
789
790 if (elements.len <= Liveness.bpi - 1) {
791 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
792 std.mem.copy(Air.Inst.Ref, &buf, elements);
793 return self.finishAir(inst, result, buf);
794 }
795 var bt = try self.iterateBigTomb(inst, elements.len);
796 for (elements) |elem| {
797 bt.feed(elem);
798 }
799 return bt.finishAir(result);
800}
801
784fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {802fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
785 const stack_offset = try self.allocMemPtr(inst);803 const stack_offset = try self.allocMemPtr(inst);
786 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });804 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
787}805}
788806
807fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
808 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
809 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
810 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
811}
812
789fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {813fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
790 const ty_op = self.air.instructions.items(.data)[inst].ty_op;814 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
791 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {815 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -969,6 +993,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -969,6 +993,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
969 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });993 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
970}994}
971995
996fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
997 const un_op = self.air.instructions.items(.data)[inst].un_op;
998 const operand = try self.resolveInst(un_op);
999 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else operand;
1000 return self.finishAir(inst, result, .{ un_op, .none, .none });
1001}
1002
972fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1003fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
973 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1004 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
974 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1005 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -1072,7 +1103,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1072,7 +1103,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
10721103
1073 // CCR is volatile across function calls1104 // CCR is volatile across function calls
1074 // (SCD 2.4.1, page 3P-10)1105 // (SCD 2.4.1, page 3P-10)
1075 try self.spillCompareFlagsIfOccupied();1106 try self.spillConditionFlagsIfOccupied();
1107
1108 // Save caller-saved registers, but crucially *after* we save the
1109 // compare flags as saving compare flags may require a new
1110 // caller-saved register
1111 for (abi.caller_preserved_regs) |reg| {
1112 try self.register_manager.getReg(reg, null);
1113 }
10761114
1077 for (info.args) |mc_arg, arg_i| {1115 for (info.args) |mc_arg, arg_i| {
1078 const arg = args[arg_i];1116 const arg = args[arg_i];
...@@ -1167,7 +1205,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1167,7 +1205,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1167 return self.finishAir(inst, result, buf);1205 return self.finishAir(inst, result, buf);
1168 }1206 }
11691207
1170 @panic("TODO handle return value with BigTomb");1208 var bt = try self.iterateBigTomb(inst, 1 + args.len);
1209 bt.feed(callee);
1210 for (args) |arg| {
1211 bt.feed(arg);
1212 }
1213 return bt.finishAir(result);
1171}1214}
11721215
1173fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {1216fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
...@@ -1208,12 +1251,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1208,12 +1251,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
1208 .inst = inst,1251 .inst = inst,
1209 });1252 });
12101253
1211 try self.spillCompareFlagsIfOccupied();1254 try self.spillConditionFlagsIfOccupied();
1212 self.compare_flags_inst = inst;1255 self.condition_flags_inst = inst;
12131256
1214 break :result switch (int_info.signedness) {1257 break :result switch (int_info.signedness) {
1215 .signed => MCValue{ .compare_flags_signed = .{ .cmp = op, .ccr = .xcc } },1258 .signed => MCValue{ .condition_flags = .{
1216 .unsigned => MCValue{ .compare_flags_unsigned = .{ .cmp = op, .ccr = .xcc } },1259 .cond = .{ .icond = Instruction.ICondition.fromCompareOperatorSigned(op) },
1260 .ccr = .xcc,
1261 } },
1262 .unsigned => MCValue{ .condition_flags = .{
1263 .cond = .{ .icond = Instruction.ICondition.fromCompareOperatorUnsigned(op) },
1264 .ccr = .xcc,
1265 } },
1217 };1266 };
1218 } else {1267 } else {
1219 return self.fail("TODO SPARCv9 cmp for ints > 64 bits", .{});1268 return self.fail("TODO SPARCv9 cmp for ints > 64 bits", .{});
...@@ -1224,69 +1273,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1224,69 +1273,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
12241273
1225fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {1274fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1226 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1275 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1227 const cond = try self.resolveInst(pl_op.operand);1276 const condition = try self.resolveInst(pl_op.operand);
1228 const extra = self.air.extraData(Air.CondBr, pl_op.payload);1277 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
1229 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];1278 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
1230 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1279 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1231 const liveness_condbr = self.liveness.getCondBr(inst);1280 const liveness_condbr = self.liveness.getCondBr(inst);
12321281
1233 // Here we either emit a BPcc for branching on CCR content,1282 // Here we emit a branch to the false section.
1234 // or emit a BPr to branch on register content.1283 const reloc: Mir.Inst.Index = try self.condBr(condition);
1235 const reloc: Mir.Inst.Index = switch (cond) {
1236 .compare_flags_signed,
1237 .compare_flags_unsigned,
1238 => try self.addInst(.{
1239 .tag = .bpcc,
1240 .data = .{
1241 .branch_predict_int = .{
1242 .ccr = switch (cond) {
1243 .compare_flags_signed => |cmp_op| cmp_op.ccr,
1244 .compare_flags_unsigned => |cmp_op| cmp_op.ccr,
1245 else => unreachable,
1246 },
1247 .cond = switch (cond) {
1248 .compare_flags_signed => |cmp_op| blk: {
1249 // Here we map to the opposite condition because the jump is to the false branch.
1250 const condition = Instruction.ICondition.fromCompareOperatorSigned(cmp_op.cmp);
1251 break :blk condition.negate();
1252 },
1253 .compare_flags_unsigned => |cmp_op| blk: {
1254 // Here we map to the opposite condition because the jump is to the false branch.
1255 const condition = Instruction.ICondition.fromCompareOperatorUnsigned(cmp_op.cmp);
1256 break :blk condition.negate();
1257 },
1258 else => unreachable,
1259 },
1260 .inst = undefined, // Will be filled by performReloc
1261 },
1262 },
1263 }),
1264 else => blk: {
1265 const reg = switch (cond) {
1266 .register => |r| r,
1267 else => try self.copyToTmpRegister(Type.bool, cond),
1268 };
1269
1270 break :blk try self.addInst(.{
1271 .tag = .bpr,
1272 .data = .{
1273 .branch_predict_reg = .{
1274 .cond = .eq_zero,
1275 .rs1 = reg,
1276 .inst = undefined, // populated later through performReloc
1277 },
1278 },
1279 });
1280 },
1281 };
1282
1283 // Regardless of the branch type that's emitted, we need to reserve
1284 // a space for the delay slot.
1285 // TODO Find a way to fill this delay slot
1286 _ = try self.addInst(.{
1287 .tag = .nop,
1288 .data = .{ .nop = {} },
1289 });
12901284
1291 // If the condition dies here in this condbr instruction, process1285 // If the condition dies here in this condbr instruction, process
1292 // that death now instead of later as this has an effect on1286 // that death now instead of later as this has an effect on
...@@ -1305,7 +1299,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1305,7 +1299,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1305 var parent_stack = try self.stack.clone(self.gpa);1299 var parent_stack = try self.stack.clone(self.gpa);
1306 defer parent_stack.deinit(self.gpa);1300 defer parent_stack.deinit(self.gpa);
1307 const parent_registers = self.register_manager.registers;1301 const parent_registers = self.register_manager.registers;
1308 const parent_compare_flags_inst = self.compare_flags_inst;1302 const parent_condition_flags_inst = self.condition_flags_inst;
13091303
1310 try self.branch_stack.append(.{});1304 try self.branch_stack.append(.{});
1311 errdefer {1305 errdefer {
...@@ -1324,7 +1318,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1324,7 +1318,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1324 defer saved_then_branch.deinit(self.gpa);1318 defer saved_then_branch.deinit(self.gpa);
13251319
1326 self.register_manager.registers = parent_registers;1320 self.register_manager.registers = parent_registers;
1327 self.compare_flags_inst = parent_compare_flags_inst;1321 self.condition_flags_inst = parent_condition_flags_inst;
13281322
1329 self.stack.deinit(self.gpa);1323 self.stack.deinit(self.gpa);
1330 self.stack = parent_stack;1324 self.stack = parent_stack;
...@@ -1468,6 +1462,53 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {...@@ -1468,6 +1462,53 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1468 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1462 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1469}1463}
14701464
1465fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1466 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1467 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch});
1468 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1469}
1470
1471fn airFence(self: *Self, inst: Air.Inst.Index) !void {
1472 // TODO weaken this as needed, currently this implements the strongest membar form
1473 const fence = self.air.instructions.items(.data)[inst].fence;
1474 _ = fence;
1475
1476 // membar #StoreStore | #LoadStore | #StoreLoad | #LoadLoad
1477 _ = try self.addInst(.{
1478 .tag = .membar,
1479 .data = .{
1480 .membar_mask = .{
1481 .mmask = .{
1482 .store_store = true,
1483 .store_load = true,
1484 .load_store = true,
1485 .load_load = true,
1486 },
1487 },
1488 },
1489 });
1490
1491 return self.finishAir(inst, .dead, .{ .none, .none, .none });
1492}
1493
1494fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1495 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1496 if (self.liveness.isUnused(inst))
1497 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1498
1499 const operand_ty = self.air.typeOf(ty_op.operand);
1500 const operand = try self.resolveInst(ty_op.operand);
1501 const info_a = operand_ty.intInfo(self.target.*);
1502 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
1503 if (info_a.signedness != info_b.signedness)
1504 return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
1505
1506 if (info_a.bits == info_b.bits)
1507 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
1508
1509 return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch});
1510}
1511
1471fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {1512fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
1472 const un_op = self.air.instructions.items(.data)[inst].un_op;1513 const un_op = self.air.instructions.items(.data)[inst].un_op;
1473 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1514 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -1488,6 +1529,24 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1488,6 +1529,24 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
1488 return self.finishAir(inst, result, .{ un_op, .none, .none });1529 return self.finishAir(inst, result, .{ un_op, .none, .none });
1489}1530}
14901531
1532fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
1533 const un_op = self.air.instructions.items(.data)[inst].un_op;
1534 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1535 const operand = try self.resolveInst(un_op);
1536 break :result try self.isNull(operand);
1537 };
1538 return self.finishAir(inst, result, .{ un_op, .none, .none });
1539}
1540
1541fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
1542 const un_op = self.air.instructions.items(.data)[inst].un_op;
1543 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1544 const operand = try self.resolveInst(un_op);
1545 break :result try self.isNonNull(operand);
1546 };
1547 return self.finishAir(inst, result, .{ un_op, .none, .none });
1548}
1549
1491fn airLoad(self: *Self, inst: Air.Inst.Index) !void {1550fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1492 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1551 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1493 const elem_ty = self.air.typeOfIndex(inst);1552 const elem_ty = self.air.typeOfIndex(inst);
...@@ -1529,6 +1588,158 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -1529,6 +1588,158 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
1529 return self.finishAirBookkeeping();1588 return self.finishAirBookkeeping();
1530}1589}
15311590
1591fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
1592 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1593 const extra = self.air.extraData(Air.Bin, pl_op.payload);
1594
1595 const operand = pl_op.operand;
1596 const value = extra.data.lhs;
1597 const length = extra.data.rhs;
1598 _ = operand;
1599 _ = value;
1600 _ = length;
1601
1602 return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch});
1603}
1604
1605fn airMod(self: *Self, inst: Air.Inst.Index) !void {
1606 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1607 const lhs = try self.resolveInst(bin_op.lhs);
1608 const rhs = try self.resolveInst(bin_op.rhs);
1609 const lhs_ty = self.air.typeOf(bin_op.lhs);
1610 const rhs_ty = self.air.typeOf(bin_op.rhs);
1611 assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?));
1612
1613 if (self.liveness.isUnused(inst))
1614 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1615
1616 // TODO add safety check
1617
1618 // We use manual assembly emission to generate faster code
1619 // First, ensure lhs, rhs, rem, and added are in registers
1620
1621 const lhs_is_register = lhs == .register;
1622 const rhs_is_register = rhs == .register;
1623
1624 const lhs_reg = if (lhs_is_register)
1625 lhs.register
1626 else
1627 try self.register_manager.allocReg(null, gp);
1628
1629 const lhs_lock = self.register_manager.lockReg(lhs_reg);
1630 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1631
1632 const rhs_reg = if (rhs_is_register)
1633 rhs.register
1634 else
1635 try self.register_manager.allocReg(null, gp);
1636 const rhs_lock = self.register_manager.lockReg(rhs_reg);
1637 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1638
1639 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1640 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1641
1642 const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1643 const regs_locks = self.register_manager.lockRegsAssumeUnused(2, regs);
1644 defer for (regs_locks) |reg| {
1645 self.register_manager.unlockReg(reg);
1646 };
1647
1648 const add_reg = regs[0];
1649 const mod_reg = regs[1];
1650
1651 // mod_reg = @rem(lhs_reg, rhs_reg)
1652 _ = try self.addInst(.{
1653 .tag = .sdivx,
1654 .data = .{
1655 .arithmetic_3op = .{
1656 .is_imm = false,
1657 .rd = mod_reg,
1658 .rs1 = lhs_reg,
1659 .rs2_or_imm = .{ .rs2 = rhs_reg },
1660 },
1661 },
1662 });
1663
1664 _ = try self.addInst(.{
1665 .tag = .mulx,
1666 .data = .{
1667 .arithmetic_3op = .{
1668 .is_imm = false,
1669 .rd = mod_reg,
1670 .rs1 = mod_reg,
1671 .rs2_or_imm = .{ .rs2 = rhs_reg },
1672 },
1673 },
1674 });
1675
1676 _ = try self.addInst(.{
1677 .tag = .sub,
1678 .data = .{
1679 .arithmetic_3op = .{
1680 .is_imm = false,
1681 .rd = mod_reg,
1682 .rs1 = lhs_reg,
1683 .rs2_or_imm = .{ .rs2 = mod_reg },
1684 },
1685 },
1686 });
1687
1688 // add_reg = mod_reg + rhs_reg
1689 _ = try self.addInst(.{
1690 .tag = .add,
1691 .data = .{
1692 .arithmetic_3op = .{
1693 .is_imm = false,
1694 .rd = add_reg,
1695 .rs1 = mod_reg,
1696 .rs2_or_imm = .{ .rs2 = rhs_reg },
1697 },
1698 },
1699 });
1700
1701 // if (add_reg == rhs_reg) add_reg = 0
1702 _ = try self.addInst(.{
1703 .tag = .cmp,
1704 .data = .{
1705 .arithmetic_2op = .{
1706 .is_imm = false,
1707 .rs1 = add_reg,
1708 .rs2_or_imm = .{ .rs2 = rhs_reg },
1709 },
1710 },
1711 });
1712
1713 _ = try self.addInst(.{
1714 .tag = .movcc,
1715 .data = .{
1716 .conditional_move_int = .{
1717 .is_imm = true,
1718 .ccr = .xcc,
1719 .cond = .{ .icond = .eq },
1720 .rd = add_reg,
1721 .rs2_or_imm = .{ .imm = 0 },
1722 },
1723 },
1724 });
1725
1726 // if (lhs_reg < 0) mod_reg = add_reg
1727 _ = try self.addInst(.{
1728 .tag = .movr,
1729 .data = .{
1730 .conditional_move_reg = .{
1731 .is_imm = false,
1732 .cond = .lt_zero,
1733 .rd = mod_reg,
1734 .rs1 = lhs_reg,
1735 .rs2_or_imm = .{ .rs2 = add_reg },
1736 },
1737 },
1738 });
1739
1740 return self.finishAir(inst, .{ .register = mod_reg }, .{ bin_op.lhs, bin_op.rhs, .none });
1741}
1742
1532fn airNot(self: *Self, inst: Air.Inst.Index) !void {1743fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1533 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1744 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1534 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1745 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -1537,42 +1748,17 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1537,42 +1748,17 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1537 switch (operand) {1748 switch (operand) {
1538 .dead => unreachable,1749 .dead => unreachable,
1539 .unreach => unreachable,1750 .unreach => unreachable,
1540 .compare_flags_unsigned => |op| {1751 .condition_flags => |op| {
1541 const r = MCValue{1752 break :result MCValue{
1542 .compare_flags_unsigned = .{1753 .condition_flags = .{
1543 .cmp = switch (op.cmp) {1754 .cond = op.cond.negate(),
1544 .gte => .lt,
1545 .gt => .lte,
1546 .neq => .eq,
1547 .lt => .gte,
1548 .lte => .gt,
1549 .eq => .neq,
1550 },
1551 .ccr = op.ccr,
1552 },
1553 };
1554 break :result r;
1555 },
1556 .compare_flags_signed => |op| {
1557 const r = MCValue{
1558 .compare_flags_signed = .{
1559 .cmp = switch (op.cmp) {
1560 .gte => .lt,
1561 .gt => .lte,
1562 .neq => .eq,
1563 .lt => .gte,
1564 .lte => .gt,
1565 .eq => .neq,
1566 },
1567 .ccr = op.ccr,1755 .ccr = op.ccr,
1568 },1756 },
1569 };1757 };
1570 break :result r;
1571 },1758 },
1572 else => {1759 else => {
1573 switch (operand_ty.zigTypeTag()) {1760 switch (operand_ty.zigTypeTag()) {
1574 .Bool => {1761 .Bool => {
1575 // TODO convert this to mvn + and
1576 const op_reg = switch (operand) {1762 const op_reg = switch (operand) {
1577 .register => |r| r,1763 .register => |r| r,
1578 else => try self.copyToTmpRegister(operand_ty, operand),1764 else => try self.copyToTmpRegister(operand_ty, operand),
...@@ -1638,7 +1824,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1638,7 +1824,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
16381824
1639 break :result MCValue{ .register = dest_reg };1825 break :result MCValue{ .register = dest_reg };
1640 } else {1826 } else {
1641 return self.fail("TODO AArch64 not on integers > u64/i64", .{});1827 return self.fail("TODO sparc64 not on integers > u64/i64", .{});
1642 }1828 }
1643 },1829 },
1644 else => unreachable,1830 else => unreachable,
...@@ -1656,6 +1842,27 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1656,6 +1842,27 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1656 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });1842 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1657}1843}
16581844
1845fn airRem(self: *Self, inst: Air.Inst.Index) !void {
1846 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1847 const lhs = try self.resolveInst(bin_op.lhs);
1848 const rhs = try self.resolveInst(bin_op.rhs);
1849 const lhs_ty = self.air.typeOf(bin_op.lhs);
1850 const rhs_ty = self.air.typeOf(bin_op.rhs);
1851
1852 // TODO add safety check
1853
1854 // result = lhs - @divTrunc(lhs, rhs) * rhs
1855 const result: MCValue = if (self.liveness.isUnused(inst)) blk: {
1856 break :blk .dead;
1857 } else blk: {
1858 const tmp0 = try self.binOp(.div_trunc, lhs, rhs, lhs_ty, rhs_ty, null);
1859 const tmp1 = try self.binOp(.mul, tmp0, rhs, lhs_ty, rhs_ty, null);
1860 break :blk try self.binOp(.sub, lhs, tmp1, lhs_ty, rhs_ty, null);
1861 };
1862
1863 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1864}
1865
1659fn airRet(self: *Self, inst: Air.Inst.Index) !void {1866fn airRet(self: *Self, inst: Air.Inst.Index) !void {
1660 const un_op = self.air.instructions.items(.data)[inst].un_op;1867 const un_op = self.air.instructions.items(.data)[inst].un_op;
1661 const operand = try self.resolveInst(un_op);1868 const operand = try self.resolveInst(un_op);
...@@ -1826,7 +2033,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1826,7 +2033,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1826 _ = try self.addInst(.{2033 _ = try self.addInst(.{
1827 .tag = .movcc,2034 .tag = .movcc,
1828 .data = .{2035 .data = .{
1829 .conditional_move = .{2036 .conditional_move_int = .{
1830 .ccr = rwo.flag.ccr,2037 .ccr = rwo.flag.ccr,
1831 .cond = .{ .icond = rwo.flag.cond },2038 .cond = .{ .icond = rwo.flag.cond },
1832 .is_imm = true,2039 .is_imm = true,
...@@ -1855,6 +2062,24 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {...@@ -1855,6 +2062,24 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
1855 return self.fail("TODO implement switch for {}", .{self.target.cpu.arch});2062 return self.fail("TODO implement switch for {}", .{self.target.cpu.arch});
1856}2063}
18572064
2065fn airTry(self: *Self, inst: Air.Inst.Index) !void {
2066 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2067 const extra = self.air.extraData(Air.Try, pl_op.payload);
2068 const body = self.air.extra[extra.end..][0..extra.data.body_len];
2069 const result: MCValue = result: {
2070 const error_union_ty = self.air.typeOf(pl_op.operand);
2071 const error_union = try self.resolveInst(pl_op.operand);
2072 const is_err_result = try self.isErr(error_union_ty, error_union);
2073 const reloc = try self.condBr(is_err_result);
2074
2075 try self.genBody(body);
2076
2077 try self.performReloc(reloc);
2078 break :result try self.errUnionPayload(error_union, error_union_ty);
2079 };
2080 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
2081}
2082
1858fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {2083fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1859 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2084 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1860 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2085 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -2011,7 +2236,10 @@ fn binOp(...@@ -2011,7 +2236,10 @@ fn binOp(
2011) InnerError!MCValue {2236) InnerError!MCValue {
2012 const mod = self.bin_file.options.module.?;2237 const mod = self.bin_file.options.module.?;
2013 switch (tag) {2238 switch (tag) {
2014 .add, .cmp_eq => {2239 .add,
2240 .sub,
2241 .cmp_eq,
2242 => {
2015 switch (lhs_ty.zigTypeTag()) {2243 switch (lhs_ty.zigTypeTag()) {
2016 .Float => return self.fail("TODO binary operations on floats", .{}),2244 .Float => return self.fail("TODO binary operations on floats", .{}),
2017 .Vector => return self.fail("TODO binary operations on vectors", .{}),2245 .Vector => return self.fail("TODO binary operations on vectors", .{}),
...@@ -2037,6 +2265,7 @@ fn binOp(...@@ -2037,6 +2265,7 @@ fn binOp(
20372265
2038 const mir_tag: Mir.Inst.Tag = switch (tag) {2266 const mir_tag: Mir.Inst.Tag = switch (tag) {
2039 .add => .add,2267 .add => .add,
2268 .sub => .sub,
2040 .cmp_eq => .cmp,2269 .cmp_eq => .cmp,
2041 else => unreachable,2270 else => unreachable,
2042 };2271 };
...@@ -2058,6 +2287,39 @@ fn binOp(...@@ -2058,6 +2287,39 @@ fn binOp(
2058 }2287 }
2059 },2288 },
20602289
2290 .div_trunc => {
2291 switch (lhs_ty.zigTypeTag()) {
2292 .Vector => return self.fail("TODO binary operations on vectors", .{}),
2293 .Int => {
2294 assert(lhs_ty.eql(rhs_ty, mod));
2295 const int_info = lhs_ty.intInfo(self.target.*);
2296 if (int_info.bits <= 64) {
2297 const rhs_immediate_ok = switch (tag) {
2298 .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12),
2299 else => unreachable,
2300 };
2301
2302 const mir_tag: Mir.Inst.Tag = switch (tag) {
2303 .div_trunc => switch (int_info.signedness) {
2304 .signed => Mir.Inst.Tag.sdivx,
2305 .unsigned => Mir.Inst.Tag.udivx,
2306 },
2307 else => unreachable,
2308 };
2309
2310 if (rhs_immediate_ok) {
2311 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, true, metadata);
2312 } else {
2313 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2314 }
2315 } else {
2316 return self.fail("TODO binary operations on int with bits > 64", .{});
2317 }
2318 },
2319 else => unreachable,
2320 }
2321 },
2322
2061 .mul => {2323 .mul => {
2062 switch (lhs_ty.zigTypeTag()) {2324 switch (lhs_ty.zigTypeTag()) {
2063 .Vector => return self.fail("TODO binary operations on vectors", .{}),2325 .Vector => return self.fail("TODO binary operations on vectors", .{}),
...@@ -2131,6 +2393,58 @@ fn binOp(...@@ -2131,6 +2393,58 @@ fn binOp(
2131 }2393 }
2132 },2394 },
21332395
2396 .bit_and,
2397 .bit_or,
2398 .xor,
2399 => {
2400 switch (lhs_ty.zigTypeTag()) {
2401 .Vector => return self.fail("TODO binary operations on vectors", .{}),
2402 .Int => {
2403 assert(lhs_ty.eql(rhs_ty, mod));
2404 const int_info = lhs_ty.intInfo(self.target.*);
2405 if (int_info.bits <= 64) {
2406 // Only say yes if the operation is
2407 // commutative, i.e. we can swap both of the
2408 // operands
2409 const lhs_immediate_ok = switch (tag) {
2410 .bit_and,
2411 .bit_or,
2412 .xor,
2413 => lhs == .immediate and lhs.immediate <= std.math.maxInt(u13),
2414 else => unreachable,
2415 };
2416 const rhs_immediate_ok = switch (tag) {
2417 .bit_and,
2418 .bit_or,
2419 .xor,
2420 => rhs == .immediate and rhs.immediate <= std.math.maxInt(u13),
2421 else => unreachable,
2422 };
2423
2424 const mir_tag: Mir.Inst.Tag = switch (tag) {
2425 .bit_and => .@"and",
2426 .bit_or => .@"or",
2427 .xor => .xor,
2428 else => unreachable,
2429 };
2430
2431 if (rhs_immediate_ok) {
2432 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
2433 } else if (lhs_immediate_ok) {
2434 // swap lhs and rhs
2435 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
2436 } else {
2437 // TODO convert large immediates to register before adding
2438 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2439 }
2440 } else {
2441 return self.fail("TODO binary operations on int with bits > 64", .{});
2442 }
2443 },
2444 else => unreachable,
2445 }
2446 },
2447
2134 .shl => {2448 .shl => {
2135 const base_tag: Air.Inst.Tag = switch (tag) {2449 const base_tag: Air.Inst.Tag = switch (tag) {
2136 .shl => .shl_exact,2450 .shl => .shl_exact,
...@@ -2259,7 +2573,14 @@ fn binOpImmediate(...@@ -2259,7 +2573,14 @@ fn binOpImmediate(
2259 const mir_data: Mir.Inst.Data = switch (mir_tag) {2573 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2260 .add,2574 .add,
2261 .addcc,2575 .addcc,
2576 .@"and",
2577 .@"or",
2578 .xor,
2579 .xnor,
2262 .mulx,2580 .mulx,
2581 .sdivx,
2582 .udivx,
2583 .sub,
2263 .subcc,2584 .subcc,
2264 => .{2585 => .{
2265 .arithmetic_3op = .{2586 .arithmetic_3op = .{
...@@ -2272,7 +2593,6 @@ fn binOpImmediate(...@@ -2272,7 +2593,6 @@ fn binOpImmediate(
2272 .sllx => .{2593 .sllx => .{
2273 .shift = .{2594 .shift = .{
2274 .is_imm = true,2595 .is_imm = true,
2275 .width = ShiftWidth.shift64,
2276 .rd = dest_reg,2596 .rd = dest_reg,
2277 .rs1 = lhs_reg,2597 .rs1 = lhs_reg,
2278 .rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) },2598 .rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) },
...@@ -2377,7 +2697,14 @@ fn binOpRegister(...@@ -2377,7 +2697,14 @@ fn binOpRegister(
2377 const mir_data: Mir.Inst.Data = switch (mir_tag) {2697 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2378 .add,2698 .add,
2379 .addcc,2699 .addcc,
2700 .@"and",
2701 .@"or",
2702 .xor,
2703 .xnor,
2380 .mulx,2704 .mulx,
2705 .sdivx,
2706 .udivx,
2707 .sub,
2381 .subcc,2708 .subcc,
2382 => .{2709 => .{
2383 .arithmetic_3op = .{2710 .arithmetic_3op = .{
...@@ -2390,7 +2717,6 @@ fn binOpRegister(...@@ -2390,7 +2717,6 @@ fn binOpRegister(
2390 .sllx => .{2717 .sllx => .{
2391 .shift = .{2718 .shift = .{
2392 .is_imm = false,2719 .is_imm = false,
2393 .width = ShiftWidth.shift64,
2394 .rd = dest_reg,2720 .rd = dest_reg,
2395 .rs1 = lhs_reg,2721 .rs1 = lhs_reg,
2396 .rs2_or_imm = .{ .rs2 = rhs_reg },2722 .rs2_or_imm = .{ .rs2 = rhs_reg },
...@@ -2464,6 +2790,62 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {...@@ -2464,6 +2790,62 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void {
2464 block_data.relocs.appendAssumeCapacity(br_index);2790 block_data.relocs.appendAssumeCapacity(br_index);
2465}2791}
24662792
2793fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
2794 // Here we either emit a BPcc for branching on CCR content,
2795 // or emit a BPr to branch on register content.
2796 const reloc: Mir.Inst.Index = switch (condition) {
2797 .condition_flags => |flags| try self.addInst(.{
2798 .tag = .bpcc,
2799 .data = .{
2800 .branch_predict_int = .{
2801 .ccr = flags.ccr,
2802 // Here we map to the opposite condition because the jump is to the false branch.
2803 .cond = flags.cond.icond.negate(),
2804 .inst = undefined, // Will be filled by performReloc
2805 },
2806 },
2807 }),
2808 .condition_register => |reg| try self.addInst(.{
2809 .tag = .bpr,
2810 .data = .{
2811 .branch_predict_reg = .{
2812 .rs1 = reg.reg,
2813 // Here we map to the opposite condition because the jump is to the false branch.
2814 .cond = reg.cond.negate(),
2815 .inst = undefined, // Will be filled by performReloc
2816 },
2817 },
2818 }),
2819 else => blk: {
2820 const reg = switch (condition) {
2821 .register => |r| r,
2822 else => try self.copyToTmpRegister(Type.bool, condition),
2823 };
2824
2825 break :blk try self.addInst(.{
2826 .tag = .bpr,
2827 .data = .{
2828 .branch_predict_reg = .{
2829 .cond = .eq_zero,
2830 .rs1 = reg,
2831 .inst = undefined, // populated later through performReloc
2832 },
2833 },
2834 });
2835 },
2836 };
2837
2838 // Regardless of the branch type that's emitted, we need to reserve
2839 // a space for the delay slot.
2840 // TODO Find a way to fill this delay slot
2841 _ = try self.addInst(.{
2842 .tag = .nop,
2843 .data = .{ .nop = {} },
2844 });
2845
2846 return reloc;
2847}
2848
2467/// Copies a value to a register without tracking the register. The register is not considered2849/// Copies a value to a register without tracking the register. The register is not considered
2468/// allocated. A second call to `copyToTmpRegister` may return the same register.2850/// allocated. A second call to `copyToTmpRegister` may return the same register.
2469/// This can have a side effect of spilling instructions to the stack to free up a register.2851/// This can have a side effect of spilling instructions to the stack to free up a register.
...@@ -2478,6 +2860,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -2478,6 +2860,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
2478 try table.ensureUnusedCapacity(self.gpa, additional_count);2860 try table.ensureUnusedCapacity(self.gpa, additional_count);
2479}2861}
24802862
2863/// Given an error union, returns the payload
2864fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
2865 const err_ty = error_union_ty.errorUnionSet();
2866 const payload_ty = error_union_ty.errorUnionPayload();
2867 if (err_ty.errorSetIsEmpty()) {
2868 return error_union_mcv;
2869 }
2870 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2871 return MCValue.none;
2872 }
2873
2874 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
2875 switch (error_union_mcv) {
2876 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2877 .stack_offset => |off| {
2878 return MCValue{ .stack_offset = off - payload_offset };
2879 },
2880 .memory => |addr| {
2881 return MCValue{ .memory = addr + payload_offset };
2882 },
2883 else => unreachable, // invalid MCValue for an error union
2884 }
2885}
2886
2481fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {2887fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
2482 @setCold(true);2888 @setCold(true);
2483 assert(self.err_msg == null);2889 assert(self.err_msg == null);
...@@ -2667,20 +3073,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2667,20 +3073,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2667 switch (mcv) {3073 switch (mcv) {
2668 .dead => unreachable,3074 .dead => unreachable,
2669 .unreach, .none => return, // Nothing to do.3075 .unreach, .none => return, // Nothing to do.
2670 .compare_flags_signed,3076 .condition_flags => |op| {
2671 .compare_flags_unsigned,3077 const condition = op.cond;
2672 => {3078 const ccr = op.ccr;
2673 const condition = switch (mcv) {
2674 .compare_flags_unsigned => |op| Instruction.ICondition.fromCompareOperatorUnsigned(op.cmp),
2675 .compare_flags_signed => |op| Instruction.ICondition.fromCompareOperatorSigned(op.cmp),
2676 else => unreachable,
2677 };
26783079
2679 const ccr = switch (mcv) {
2680 .compare_flags_unsigned => |op| op.ccr,
2681 .compare_flags_signed => |op| op.ccr,
2682 else => unreachable,
2683 };
2684 // TODO handle floating point CCRs3080 // TODO handle floating point CCRs
2685 assert(ccr == .xcc or ccr == .icc);3081 assert(ccr == .xcc or ccr == .icc);
26863082
...@@ -2698,11 +3094,39 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2698,11 +3094,39 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2698 _ = try self.addInst(.{3094 _ = try self.addInst(.{
2699 .tag = .movcc,3095 .tag = .movcc,
2700 .data = .{3096 .data = .{
2701 .conditional_move = .{3097 .conditional_move_int = .{
2702 .ccr = ccr,3098 .ccr = ccr,
2703 .cond = .{ .icond = condition },3099 .cond = condition,
3100 .is_imm = true,
3101 .rd = reg,
3102 .rs2_or_imm = .{ .imm = 1 },
3103 },
3104 },
3105 });
3106 },
3107 .condition_register => |op| {
3108 const condition = op.cond;
3109 const register = op.reg;
3110
3111 _ = try self.addInst(.{
3112 .tag = .mov,
3113 .data = .{
3114 .arithmetic_2op = .{
3115 .is_imm = false,
3116 .rs1 = reg,
3117 .rs2_or_imm = .{ .rs2 = .g0 },
3118 },
3119 },
3120 });
3121
3122 _ = try self.addInst(.{
3123 .tag = .movr,
3124 .data = .{
3125 .conditional_move_reg = .{
3126 .cond = condition,
2704 .is_imm = true,3127 .is_imm = true,
2705 .rd = reg,3128 .rd = reg,
3129 .rs1 = register,
2706 .rs2_or_imm = .{ .imm = 1 },3130 .rs2_or_imm = .{ .imm = 1 },
2707 },3131 },
2708 },3132 },
...@@ -2773,7 +3197,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2773,7 +3197,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2773 .data = .{3197 .data = .{
2774 .shift = .{3198 .shift = .{
2775 .is_imm = true,3199 .is_imm = true,
2776 .width = .shift64,
2777 .rd = reg,3200 .rd = reg,
2778 .rs1 = reg,3201 .rs1 = reg,
2779 .rs2_or_imm = .{ .imm = 12 },3202 .rs2_or_imm = .{ .imm = 12 },
...@@ -2804,7 +3227,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2804,7 +3227,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2804 .data = .{3227 .data = .{
2805 .shift = .{3228 .shift = .{
2806 .is_imm = true,3229 .is_imm = true,
2807 .width = .shift64,
2808 .rd = reg,3230 .rd = reg,
2809 .rs1 = reg,3231 .rs1 = reg,
2810 .rs2_or_imm = .{ .imm = 32 },3232 .rs2_or_imm = .{ .imm = 32 },
...@@ -2874,8 +3296,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2874,8 +3296,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2874 else => return self.fail("TODO implement memset", .{}),3296 else => return self.fail("TODO implement memset", .{}),
2875 }3297 }
2876 },3298 },
2877 .compare_flags_unsigned,3299 .condition_flags,
2878 .compare_flags_signed,3300 .condition_register,
2879 .immediate,3301 .immediate,
2880 .ptr_stack_offset,3302 .ptr_stack_offset,
2881 => {3303 => {
...@@ -2916,7 +3338,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2916,7 +3338,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2916 _ = try self.addInst(.{3338 _ = try self.addInst(.{
2917 .tag = .movcc,3339 .tag = .movcc,
2918 .data = .{3340 .data = .{
2919 .conditional_move = .{3341 .conditional_move_int = .{
2920 .ccr = rwo.flag.ccr,3342 .ccr = rwo.flag.ccr,
2921 .cond = .{ .icond = rwo.flag.cond },3343 .cond = .{ .icond = rwo.flag.cond },
2922 .is_imm = true,3344 .is_imm = true,
...@@ -3103,7 +3525,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3103,7 +3525,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3103 } },3525 } },
3104 });3526 });
31053527
3106 return MCValue{ .compare_flags_unsigned = .{ .cmp = .gt, .ccr = .xcc } };3528 return MCValue{ .condition_flags = .{ .cond = .{ .icond = .gu }, .ccr = .xcc } };
3107 } else {3529 } else {
3108 return self.fail("TODO isErr for errors with size > 8", .{});3530 return self.fail("TODO isErr for errors with size > 8", .{});
3109 }3531 }
...@@ -3116,9 +3538,30 @@ fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3116,9 +3538,30 @@ fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3116 // Call isErr, then negate the result.3538 // Call isErr, then negate the result.
3117 const is_err_result = try self.isErr(ty, operand);3539 const is_err_result = try self.isErr(ty, operand);
3118 switch (is_err_result) {3540 switch (is_err_result) {
3119 .compare_flags_unsigned => |op| {3541 .condition_flags => |op| {
3120 assert(op.cmp == .gt);3542 return MCValue{ .condition_flags = .{ .cond = op.cond.negate(), .ccr = op.ccr } };
3121 return MCValue{ .compare_flags_unsigned = .{ .cmp = .lte, .ccr = op.ccr } };3543 },
3544 .immediate => |imm| {
3545 assert(imm == 0);
3546 return MCValue{ .immediate = 1 };
3547 },
3548 else => unreachable,
3549 }
3550}
3551
3552fn isNull(self: *Self, operand: MCValue) !MCValue {
3553 _ = operand;
3554 // Here you can specialize this instruction if it makes sense to, otherwise the default
3555 // will call isNonNull and invert the result.
3556 return self.fail("TODO call isNonNull and invert the result", .{});
3557}
3558
3559fn isNonNull(self: *Self, operand: MCValue) !MCValue {
3560 // Call isNull, then negate the result.
3561 const is_null_result = try self.isNull(operand);
3562 switch (is_null_result) {
3563 .condition_flags => |op| {
3564 return MCValue{ .condition_flags = .{ .cond = op.cond.negate(), .ccr = op.ccr } };
3122 },3565 },
3123 .immediate => |imm| {3566 .immediate => |imm| {
3124 assert(imm == 0);3567 assert(imm == 0);
...@@ -3133,9 +3576,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT...@@ -3133,9 +3576,7 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
3133 return BigTomb{3576 return BigTomb{
3134 .function = self,3577 .function = self,
3135 .inst = inst,3578 .inst = inst,
3136 .tomb_bits = self.liveness.getTombBits(inst),3579 .lbt = self.liveness.iterateBigTomb(inst),
3137 .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
3138 .bit_index = 0,
3139 };3580 };
3140}3581}
31413582
...@@ -3168,8 +3609,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -3168,8 +3609,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
3168 .undef => unreachable,3609 .undef => unreachable,
3169 .unreach => unreachable,3610 .unreach => unreachable,
3170 .dead => unreachable,3611 .dead => unreachable,
3171 .compare_flags_unsigned,3612 .condition_flags,
3172 .compare_flags_signed,3613 .condition_register,
3173 .register_with_overflow,3614 .register_with_overflow,
3174 => unreachable, // cannot hold an address3615 => unreachable, // cannot hold an address
3175 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),3616 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
...@@ -3181,7 +3622,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -3181,7 +3622,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
3181 switch (dst_mcv) {3622 switch (dst_mcv) {
3182 .dead => unreachable,3623 .dead => unreachable,
3183 .undef => unreachable,3624 .undef => unreachable,
3184 .compare_flags_signed, .compare_flags_unsigned => unreachable,3625 .condition_flags => unreachable,
3185 .register => |dst_reg| {3626 .register => |dst_reg| {
3186 try self.genLoad(dst_reg, addr_reg, i13, 0, elem_size);3627 try self.genLoad(dst_reg, addr_reg, i13, 0, elem_size);
3187 },3628 },
...@@ -3277,10 +3718,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -3277,10 +3718,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
3277 },3718 },
3278 .register_with_overflow => |rwo| {3719 .register_with_overflow => |rwo| {
3279 self.register_manager.freeReg(rwo.reg);3720 self.register_manager.freeReg(rwo.reg);
3280 self.compare_flags_inst = null;3721 self.condition_flags_inst = null;
3281 },3722 },
3282 .compare_flags_signed, .compare_flags_unsigned => {3723 .condition_flags => {
3283 self.compare_flags_inst = null;3724 self.condition_flags_inst = null;
3284 },3725 },
3285 else => {}, // TODO process stack allocation death3726 else => {}, // TODO process stack allocation death
3286 }3727 }
...@@ -3474,15 +3915,13 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {...@@ -3474,15 +3915,13 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
3474 }3915 }
3475}3916}
34763917
3477/// Save the current instruction stored in the compare flags if3918/// Save the current instruction stored in the condition flags if
3478/// occupied3919/// occupied
3479fn spillCompareFlagsIfOccupied(self: *Self) !void {3920fn spillConditionFlagsIfOccupied(self: *Self) !void {
3480 if (self.compare_flags_inst) |inst_to_save| {3921 if (self.condition_flags_inst) |inst_to_save| {
3481 const mcv = self.getResolvedInstValue(inst_to_save);3922 const mcv = self.getResolvedInstValue(inst_to_save);
3482 const new_mcv = switch (mcv) {3923 const new_mcv = switch (mcv) {
3483 .compare_flags_signed,3924 .condition_flags => try self.allocRegOrMem(inst_to_save, true),
3484 .compare_flags_unsigned,
3485 => try self.allocRegOrMem(inst_to_save, true),
3486 .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),3925 .register_with_overflow => try self.allocRegOrMem(inst_to_save, false),
3487 else => unreachable, // mcv doesn't occupy the compare flags3926 else => unreachable, // mcv doesn't occupy the compare flags
3488 };3927 };
...@@ -3493,7 +3932,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {...@@ -3493,7 +3932,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
3493 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];3932 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
3494 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);3933 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
34953934
3496 self.compare_flags_inst = null;3935 self.condition_flags_inst = null;
34973936
3498 // TODO consolidate with register manager and spillInstruction3937 // TODO consolidate with register manager and spillInstruction
3499 // this call should really belong in the register manager!3938 // this call should really belong in the register manager!
...@@ -3522,8 +3961,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3522,8 +3961,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3522 .undef => unreachable,3961 .undef => unreachable,
3523 .unreach => unreachable,3962 .unreach => unreachable,
3524 .dead => unreachable,3963 .dead => unreachable,
3525 .compare_flags_unsigned,3964 .condition_flags,
3526 .compare_flags_signed,3965 .condition_register,
3527 .register_with_overflow,3966 .register_with_overflow,
3528 => unreachable, // cannot hold an address3967 => unreachable, // cannot hold an address
3529 .immediate => |imm| {3968 .immediate => |imm| {
...@@ -3604,7 +4043,6 @@ fn truncRegister(...@@ -3604,7 +4043,6 @@ fn truncRegister(
3604 .data = .{4043 .data = .{
3605 .shift = .{4044 .shift = .{
3606 .is_imm = true,4045 .is_imm = true,
3607 .width = ShiftWidth.shift64,
3608 .rd = dest_reg,4046 .rd = dest_reg,
3609 .rs1 = operand_reg,4047 .rs1 = operand_reg,
3610 .rs2_or_imm = .{ .imm = @intCast(u6, 64 - int_bits) },4048 .rs2_or_imm = .{ .imm = @intCast(u6, 64 - int_bits) },
...@@ -3619,7 +4057,6 @@ fn truncRegister(...@@ -3619,7 +4057,6 @@ fn truncRegister(
3619 .data = .{4057 .data = .{
3620 .shift = .{4058 .shift = .{
3621 .is_imm = true,4059 .is_imm = true,
3622 .width = ShiftWidth.shift32,
3623 .rd = dest_reg,4060 .rd = dest_reg,
3624 .rs1 = dest_reg,4061 .rs1 = dest_reg,
3625 .rs2_or_imm = .{ .imm = @intCast(u6, int_bits) },4062 .rs2_or_imm = .{ .imm = @intCast(u6, int_bits) },
...@@ -3636,7 +4073,6 @@ fn truncRegister(...@@ -3636,7 +4073,6 @@ fn truncRegister(
3636 .data = .{4073 .data = .{
3637 .shift = .{4074 .shift = .{
3638 .is_imm = true,4075 .is_imm = true,
3639 .width = ShiftWidth.shift32,
3640 .rd = dest_reg,4076 .rd = dest_reg,
3641 .rs1 = operand_reg,4077 .rs1 = operand_reg,
3642 .rs2_or_imm = .{ .imm = 0 },4078 .rs2_or_imm = .{ .imm = 0 },
src/arch/sparc64/Emit.zig+84-8
...@@ -93,13 +93,20 @@ pub fn emitMir(...@@ -93,13 +93,20 @@ pub fn emitMir(
93 .lduw => try emit.mirArithmetic3Op(inst),93 .lduw => try emit.mirArithmetic3Op(inst),
94 .ldx => try emit.mirArithmetic3Op(inst),94 .ldx => try emit.mirArithmetic3Op(inst),
9595
96 .@"and" => try emit.mirArithmetic3Op(inst),
96 .@"or" => try emit.mirArithmetic3Op(inst),97 .@"or" => try emit.mirArithmetic3Op(inst),
97 .xor => try emit.mirArithmetic3Op(inst),98 .xor => try emit.mirArithmetic3Op(inst),
98 .xnor => try emit.mirArithmetic3Op(inst),99 .xnor => try emit.mirArithmetic3Op(inst),
99100
101 .membar => try emit.mirMembar(inst),
102
100 .movcc => try emit.mirConditionalMove(inst),103 .movcc => try emit.mirConditionalMove(inst),
101104
105 .movr => try emit.mirConditionalMove(inst),
106
102 .mulx => try emit.mirArithmetic3Op(inst),107 .mulx => try emit.mirArithmetic3Op(inst),
108 .sdivx => try emit.mirArithmetic3Op(inst),
109 .udivx => try emit.mirArithmetic3Op(inst),
103110
104 .nop => try emit.mirNop(),111 .nop => try emit.mirNop(),
105112
...@@ -110,12 +117,12 @@ pub fn emitMir(...@@ -110,12 +117,12 @@ pub fn emitMir(
110117
111 .sethi => try emit.mirSethi(inst),118 .sethi => try emit.mirSethi(inst),
112119
113 .sll => @panic("TODO implement sparc64 sll"),120 .sll => try emit.mirShift(inst),
114 .srl => @panic("TODO implement sparc64 srl"),121 .srl => try emit.mirShift(inst),
115 .sra => @panic("TODO implement sparc64 sra"),122 .sra => try emit.mirShift(inst),
116 .sllx => @panic("TODO implement sparc64 sllx"),123 .sllx => try emit.mirShift(inst),
117 .srlx => @panic("TODO implement sparc64 srlx"),124 .srlx => try emit.mirShift(inst),
118 .srax => @panic("TODO implement sparc64 srax"),125 .srax => try emit.mirShift(inst),
119126
120 .stb => try emit.mirArithmetic3Op(inst),127 .stb => try emit.mirArithmetic3Op(inst),
121 .sth => try emit.mirArithmetic3Op(inst),128 .sth => try emit.mirArithmetic3Op(inst),
...@@ -201,7 +208,7 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -201,7 +208,7 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {
201 .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),208 .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),
202 .cmp => try emit.writeInstruction(Instruction.subcc(Register, rs1, rs2, .g0)),209 .cmp => try emit.writeInstruction(Instruction.subcc(Register, rs1, rs2, .g0)),
203 .mov => try emit.writeInstruction(Instruction.@"or"(Register, .g0, rs2, rs1)),210 .mov => try emit.writeInstruction(Instruction.@"or"(Register, .g0, rs2, rs1)),
204 .not => try emit.writeInstruction(Instruction.xnor(Register, .g0, rs2, rs1)),211 .not => try emit.writeInstruction(Instruction.xnor(Register, rs2, .g0, rs1)),
205 else => unreachable,212 else => unreachable,
206 }213 }
207 }214 }
...@@ -224,10 +231,13 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -224,10 +231,13 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
224 .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),231 .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
225 .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),232 .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
226 .ldx => try emit.writeInstruction(Instruction.ldx(i13, rs1, imm, rd)),233 .ldx => try emit.writeInstruction(Instruction.ldx(i13, rs1, imm, rd)),
234 .@"and" => try emit.writeInstruction(Instruction.@"and"(i13, rs1, imm, rd)),
227 .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),235 .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
228 .xor => try emit.writeInstruction(Instruction.xor(i13, rs1, imm, rd)),236 .xor => try emit.writeInstruction(Instruction.xor(i13, rs1, imm, rd)),
229 .xnor => try emit.writeInstruction(Instruction.xnor(i13, rs1, imm, rd)),237 .xnor => try emit.writeInstruction(Instruction.xnor(i13, rs1, imm, rd)),
230 .mulx => try emit.writeInstruction(Instruction.mulx(i13, rs1, imm, rd)),238 .mulx => try emit.writeInstruction(Instruction.mulx(i13, rs1, imm, rd)),
239 .sdivx => try emit.writeInstruction(Instruction.sdivx(i13, rs1, imm, rd)),
240 .udivx => try emit.writeInstruction(Instruction.udivx(i13, rs1, imm, rd)),
231 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),241 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
232 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),242 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
233 .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)),243 .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)),
...@@ -248,10 +258,13 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -248,10 +258,13 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
248 .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),258 .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
249 .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),259 .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
250 .ldx => try emit.writeInstruction(Instruction.ldx(Register, rs1, rs2, rd)),260 .ldx => try emit.writeInstruction(Instruction.ldx(Register, rs1, rs2, rd)),
261 .@"and" => try emit.writeInstruction(Instruction.@"and"(Register, rs1, rs2, rd)),
251 .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),262 .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
252 .xor => try emit.writeInstruction(Instruction.xor(Register, rs1, rs2, rd)),263 .xor => try emit.writeInstruction(Instruction.xor(Register, rs1, rs2, rd)),
253 .xnor => try emit.writeInstruction(Instruction.xnor(Register, rs1, rs2, rd)),264 .xnor => try emit.writeInstruction(Instruction.xnor(Register, rs1, rs2, rd)),
254 .mulx => try emit.writeInstruction(Instruction.mulx(Register, rs1, rs2, rd)),265 .mulx => try emit.writeInstruction(Instruction.mulx(Register, rs1, rs2, rd)),
266 .sdivx => try emit.writeInstruction(Instruction.sdivx(Register, rs1, rs2, rd)),
267 .udivx => try emit.writeInstruction(Instruction.udivx(Register, rs1, rs2, rd)),
255 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),268 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
256 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),269 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
257 .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)),270 .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)),
...@@ -314,7 +327,7 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -314,7 +327,7 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {
314327
315 switch (tag) {328 switch (tag) {
316 .movcc => {329 .movcc => {
317 const data = emit.mir.instructions.items(.data)[inst].conditional_move;330 const data = emit.mir.instructions.items(.data)[inst].conditional_move_int;
318 if (data.is_imm) {331 if (data.is_imm) {
319 try emit.writeInstruction(Instruction.movcc(332 try emit.writeInstruction(Instruction.movcc(
320 i11,333 i11,
...@@ -333,10 +346,41 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -333,10 +346,41 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void {
333 ));346 ));
334 }347 }
335 },348 },
349 .movr => {
350 const data = emit.mir.instructions.items(.data)[inst].conditional_move_reg;
351 if (data.is_imm) {
352 try emit.writeInstruction(Instruction.movr(
353 i10,
354 data.cond,
355 data.rs1,
356 data.rs2_or_imm.imm,
357 data.rd,
358 ));
359 } else {
360 try emit.writeInstruction(Instruction.movr(
361 Register,
362 data.cond,
363 data.rs1,
364 data.rs2_or_imm.rs2,
365 data.rd,
366 ));
367 }
368 },
336 else => unreachable,369 else => unreachable,
337 }370 }
338}371}
339372
373fn mirMembar(emit: *Emit, inst: Mir.Inst.Index) !void {
374 const tag = emit.mir.instructions.items(.tag)[inst];
375 const mask = emit.mir.instructions.items(.data)[inst].membar_mask;
376 assert(tag == .membar);
377
378 try emit.writeInstruction(Instruction.membar(
379 mask.cmask,
380 mask.mmask,
381 ));
382}
383
340fn mirNop(emit: *Emit) !void {384fn mirNop(emit: *Emit) !void {
341 try emit.writeInstruction(Instruction.nop());385 try emit.writeInstruction(Instruction.nop());
342}386}
...@@ -352,6 +396,38 @@ fn mirSethi(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -352,6 +396,38 @@ fn mirSethi(emit: *Emit, inst: Mir.Inst.Index) !void {
352 try emit.writeInstruction(Instruction.sethi(imm, rd));396 try emit.writeInstruction(Instruction.sethi(imm, rd));
353}397}
354398
399fn mirShift(emit: *Emit, inst: Mir.Inst.Index) !void {
400 const tag = emit.mir.instructions.items(.tag)[inst];
401 const data = emit.mir.instructions.items(.data)[inst].shift;
402
403 const rd = data.rd;
404 const rs1 = data.rs1;
405
406 if (data.is_imm) {
407 const imm = data.rs2_or_imm.imm;
408 switch (tag) {
409 .sll => try emit.writeInstruction(Instruction.sll(u5, rs1, @truncate(u5, imm), rd)),
410 .srl => try emit.writeInstruction(Instruction.srl(u5, rs1, @truncate(u5, imm), rd)),
411 .sra => try emit.writeInstruction(Instruction.sra(u5, rs1, @truncate(u5, imm), rd)),
412 .sllx => try emit.writeInstruction(Instruction.sllx(u6, rs1, imm, rd)),
413 .srlx => try emit.writeInstruction(Instruction.srlx(u6, rs1, imm, rd)),
414 .srax => try emit.writeInstruction(Instruction.srax(u6, rs1, imm, rd)),
415 else => unreachable,
416 }
417 } else {
418 const rs2 = data.rs2_or_imm.rs2;
419 switch (tag) {
420 .sll => try emit.writeInstruction(Instruction.sll(Register, rs1, rs2, rd)),
421 .srl => try emit.writeInstruction(Instruction.srl(Register, rs1, rs2, rd)),
422 .sra => try emit.writeInstruction(Instruction.sra(Register, rs1, rs2, rd)),
423 .sllx => try emit.writeInstruction(Instruction.sllx(Register, rs1, rs2, rd)),
424 .srlx => try emit.writeInstruction(Instruction.srlx(Register, rs1, rs2, rd)),
425 .srax => try emit.writeInstruction(Instruction.srax(Register, rs1, rs2, rd)),
426 else => unreachable,
427 }
428 }
429}
430
355fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {431fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
356 const tag = emit.mir.instructions.items(.tag)[inst];432 const tag = emit.mir.instructions.items(.tag)[inst];
357 const data = emit.mir.instructions.items(.data)[inst].trap;433 const data = emit.mir.instructions.items(.data)[inst].trap;
src/arch/sparc64/Mir.zig+40-7
...@@ -73,18 +73,28 @@ pub const Inst = struct {...@@ -73,18 +73,28 @@ pub const Inst = struct {
73 /// A.31 Logical Operations73 /// A.31 Logical Operations
74 /// This uses the arithmetic_3op field.74 /// This uses the arithmetic_3op field.
75 // TODO add other operations.75 // TODO add other operations.
76 @"and",
76 @"or",77 @"or",
77 xor,78 xor,
78 xnor,79 xnor,
7980
81 /// A.32 Memory Barrier
82 /// This uses the membar_mask field.
83 membar,
84
80 /// A.35 Move Integer Register on Condition (MOVcc)85 /// A.35 Move Integer Register on Condition (MOVcc)
81 /// This uses the conditional_move field.86 /// This uses the conditional_move_int field.
82 movcc,87 movcc,
8388
89 /// A.36 Move Integer Register on Register Condition (MOVr)
90 /// This uses the conditional_move_reg field.
91 movr,
92
84 /// A.37 Multiply and Divide (64-bit)93 /// A.37 Multiply and Divide (64-bit)
85 /// This uses the arithmetic_3op field.94 /// This uses the arithmetic_3op field.
86 // TODO add other operations.
87 mulx,95 mulx,
96 sdivx,
97 udivx,
8898
89 /// A.40 No Operation99 /// A.40 No Operation
90 /// This uses the nop field.100 /// This uses the nop field.
...@@ -154,8 +164,9 @@ pub const Inst = struct {...@@ -154,8 +164,9 @@ pub const Inst = struct {
154 /// This uses the arithmetic_2op field, with rs1164 /// This uses the arithmetic_2op field, with rs1
155 /// being the *destination* register.165 /// being the *destination* register.
156 // TODO is it okay to abuse rs1 in this way?166 // TODO is it okay to abuse rs1 in this way?
157 // TODO this differs from official encoding for convenience, fix it later167 // not rs2, rs1 -> xnor rs2, %g0, rs1
158 not, // not rs2/imm, rs1 -> xnor %g0, rs2/imm, rs1168 // not imm, rs1 -> xnor %g0, imm, rs1
169 not,
159 };170 };
160171
161 /// The position of an MIR instruction within the `Mir` instructions array.172 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -230,12 +241,19 @@ pub const Inst = struct {...@@ -230,12 +241,19 @@ pub const Inst = struct {
230 inst: Index,241 inst: Index,
231 },242 },
232243
233 /// Conditional move.244 /// Membar mask, controls the barrier behavior
245 /// Used by e.g. membar
246 membar_mask: struct {
247 mmask: Instruction.MemOrderingConstraint = .{},
248 cmask: Instruction.MemCompletionConstraint = .{},
249 },
250
251 /// Conditional move, checking the integer status code
234 /// if is_imm true then it uses the imm field of rs2_or_imm,252 /// if is_imm true then it uses the imm field of rs2_or_imm,
235 /// otherwise it uses rs2 field.253 /// otherwise it uses rs2 field.
236 ///254 ///
237 /// Used by e.g. movcc255 /// Used by e.g. movcc
238 conditional_move: struct {256 conditional_move_int: struct {
239 is_imm: bool,257 is_imm: bool,
240 ccr: Instruction.CCR,258 ccr: Instruction.CCR,
241 cond: Instruction.Condition,259 cond: Instruction.Condition,
...@@ -246,6 +264,22 @@ pub const Inst = struct {...@@ -246,6 +264,22 @@ pub const Inst = struct {
246 },264 },
247 },265 },
248266
267 /// Conditional move, comparing a register's content with zero
268 /// if is_imm true then it uses the imm field of rs2_or_imm,
269 /// otherwise it uses rs2 field.
270 ///
271 /// Used by e.g. movr
272 conditional_move_reg: struct {
273 is_imm: bool,
274 cond: Instruction.RCondition,
275 rd: Register,
276 rs1: Register,
277 rs2_or_imm: union {
278 rs2: Register,
279 imm: i10,
280 },
281 },
282
249 /// No additional data283 /// No additional data
250 ///284 ///
251 /// Used by e.g. flushw285 /// Used by e.g. flushw
...@@ -266,7 +300,6 @@ pub const Inst = struct {...@@ -266,7 +300,6 @@ pub const Inst = struct {
266 /// Used by e.g. sllx300 /// Used by e.g. sllx
267 shift: struct {301 shift: struct {
268 is_imm: bool,302 is_imm: bool,
269 width: Instruction.ShiftWidth,
270 rd: Register,303 rd: Register,
271 rs1: Register,304 rs1: Register,
272 rs2_or_imm: union {305 rs2_or_imm: union {
src/arch/sparc64/bits.zig+123-7
...@@ -475,6 +475,21 @@ pub const Instruction = union(enum) {...@@ -475,6 +475,21 @@ pub const Instruction = union(enum) {
475 ne_zero,475 ne_zero,
476 gt_zero,476 gt_zero,
477 ge_zero,477 ge_zero,
478
479 /// Returns the condition which is true iff the given condition is
480 /// false (if such a condition exists).
481 pub fn negate(cond: RCondition) RCondition {
482 return switch (cond) {
483 .eq_zero => .ne_zero,
484 .ne_zero => .eq_zero,
485 .lt_zero => .ge_zero,
486 .ge_zero => .lt_zero,
487 .le_zero => .gt_zero,
488 .gt_zero => .le_zero,
489 .reserved1 => unreachable,
490 .reserved2 => unreachable,
491 };
492 }
478 };493 };
479494
480 pub const ASI = enum(u8) {495 pub const ASI = enum(u8) {
...@@ -673,10 +688,27 @@ pub const Instruction = union(enum) {...@@ -673,10 +688,27 @@ pub const Instruction = union(enum) {
673 }688 }
674 };689 };
675690
676 pub const Condition = packed union {691 pub const ConditionTag = enum { fcond, icond };
692 pub const Condition = union(ConditionTag) {
677 fcond: FCondition,693 fcond: FCondition,
678 icond: ICondition,694 icond: ICondition,
679 encoded: u4,695
696 /// Encodes the condition into the instruction bit pattern.
697 pub fn enc(cond: Condition) u4 {
698 return switch (cond) {
699 .icond => |c| @enumToInt(c),
700 .fcond => |c| @enumToInt(c),
701 };
702 }
703
704 /// Returns the condition which is true iff the given condition is
705 /// false (if such a condition exists).
706 pub fn negate(cond: Condition) Condition {
707 return switch (cond) {
708 .icond => |c| .{ .icond = c.negate() },
709 .fcond => |c| .{ .fcond = c.negate() },
710 };
711 }
680 };712 };
681713
682 pub fn toU32(self: Instruction) u32 {714 pub fn toU32(self: Instruction) u32 {
...@@ -755,7 +787,7 @@ pub const Instruction = union(enum) {...@@ -755,7 +787,7 @@ pub const Instruction = union(enum) {
755 return Instruction{787 return Instruction{
756 .format_2b = .{788 .format_2b = .{
757 .a = @boolToInt(annul),789 .a = @boolToInt(annul),
758 .cond = cond.encoded,790 .cond = cond.enc(),
759 .op2 = op2,791 .op2 = op2,
760 .disp22 = udisp_truncated,792 .disp22 = udisp_truncated,
761 },793 },
...@@ -776,7 +808,7 @@ pub const Instruction = union(enum) {...@@ -776,7 +808,7 @@ pub const Instruction = union(enum) {
776 return Instruction{808 return Instruction{
777 .format_2c = .{809 .format_2c = .{
778 .a = @boolToInt(annul),810 .a = @boolToInt(annul),
779 .cond = cond.encoded,811 .cond = cond.enc(),
780 .op2 = op2,812 .op2 = op2,
781 .cc1 = ccr_cc1,813 .cc1 = ccr_cc1,
782 .cc0 = ccr_cc0,814 .cc0 = ccr_cc0,
...@@ -1057,7 +1089,7 @@ pub const Instruction = union(enum) {...@@ -1057,7 +1089,7 @@ pub const Instruction = union(enum) {
1057 .rd = rd.enc(),1089 .rd = rd.enc(),
1058 .op3 = op3,1090 .op3 = op3,
1059 .cc2 = ccr_cc2,1091 .cc2 = ccr_cc2,
1060 .cond = cond.encoded,1092 .cond = cond.enc(),
1061 .cc1 = ccr_cc1,1093 .cc1 = ccr_cc1,
1062 .cc0 = ccr_cc0,1094 .cc0 = ccr_cc0,
1063 .rs2 = rs2.enc(),1095 .rs2 = rs2.enc(),
...@@ -1074,7 +1106,7 @@ pub const Instruction = union(enum) {...@@ -1074,7 +1106,7 @@ pub const Instruction = union(enum) {
1074 .rd = rd.enc(),1106 .rd = rd.enc(),
1075 .op3 = op3,1107 .op3 = op3,
1076 .cc2 = ccr_cc2,1108 .cc2 = ccr_cc2,
1077 .cond = cond.encoded,1109 .cond = cond.enc(),
1078 .cc1 = ccr_cc1,1110 .cc1 = ccr_cc1,
1079 .cc0 = ccr_cc0,1111 .cc0 = ccr_cc0,
1080 .simm11 = @bitCast(u11, imm),1112 .simm11 = @bitCast(u11, imm),
...@@ -1122,7 +1154,7 @@ pub const Instruction = union(enum) {...@@ -1122,7 +1154,7 @@ pub const Instruction = union(enum) {
1122 .format_4g = .{1154 .format_4g = .{
1123 .rd = rd.enc(),1155 .rd = rd.enc(),
1124 .op3 = op3,1156 .op3 = op3,
1125 .cond = cond.encoded,1157 .cond = cond.enc(),
1126 .opf_cc = opf_cc,1158 .opf_cc = opf_cc,
1127 .opf_low = opf_low,1159 .opf_low = opf_low,
1128 .rs2 = rs2.enc(),1160 .rs2 = rs2.enc(),
...@@ -1197,6 +1229,14 @@ pub const Instruction = union(enum) {...@@ -1197,6 +1229,14 @@ pub const Instruction = union(enum) {
1197 };1229 };
1198 }1230 }
11991231
1232 pub fn @"and"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1233 return switch (s2) {
1234 Register => format3a(0b10, 0b00_0001, rs1, rs2, rd),
1235 i13 => format3b(0b10, 0b00_0001, rs1, rs2, rd),
1236 else => unreachable,
1237 };
1238 }
1239
1200 pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {1240 pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1201 return switch (s2) {1241 return switch (s2) {
1202 Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),1242 Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
...@@ -1221,6 +1261,10 @@ pub const Instruction = union(enum) {...@@ -1221,6 +1261,10 @@ pub const Instruction = union(enum) {
1221 };1261 };
1222 }1262 }
12231263
1264 pub fn membar(cmask: MemCompletionConstraint, mmask: MemOrderingConstraint) Instruction {
1265 return format3h(cmask, mmask);
1266 }
1267
1224 pub fn movcc(comptime s2: type, cond: Condition, ccr: CCR, rs2: s2, rd: Register) Instruction {1268 pub fn movcc(comptime s2: type, cond: Condition, ccr: CCR, rs2: s2, rd: Register) Instruction {
1225 return switch (s2) {1269 return switch (s2) {
1226 Register => format4c(0b10_1100, cond, ccr, rs2, rd),1270 Register => format4c(0b10_1100, cond, ccr, rs2, rd),
...@@ -1229,6 +1273,14 @@ pub const Instruction = union(enum) {...@@ -1229,6 +1273,14 @@ pub const Instruction = union(enum) {
1229 };1273 };
1230 }1274 }
12311275
1276 pub fn movr(comptime s2: type, cond: RCondition, rs1: Register, rs2: s2, rd: Register) Instruction {
1277 return switch (s2) {
1278 Register => format3e(0b10, 0b10_1111, cond, rs1, rs2, rd),
1279 i10 => format3f(0b10, 0b10_1111, cond, rs1, rs2, rd),
1280 else => unreachable,
1281 };
1282 }
1283
1232 pub fn mulx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {1284 pub fn mulx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1233 return switch (s2) {1285 return switch (s2) {
1234 Register => format3a(0b10, 0b00_1001, rs1, rs2, rd),1286 Register => format3a(0b10, 0b00_1001, rs1, rs2, rd),
...@@ -1237,6 +1289,22 @@ pub const Instruction = union(enum) {...@@ -1237,6 +1289,22 @@ pub const Instruction = union(enum) {
1237 };1289 };
1238 }1290 }
12391291
1292 pub fn sdivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1293 return switch (s2) {
1294 Register => format3a(0b10, 0b10_1101, rs1, rs2, rd),
1295 i13 => format3b(0b10, 0b10_1101, rs1, rs2, rd),
1296 else => unreachable,
1297 };
1298 }
1299
1300 pub fn udivx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1301 return switch (s2) {
1302 Register => format3a(0b10, 0b00_1101, rs1, rs2, rd),
1303 i13 => format3b(0b10, 0b00_1101, rs1, rs2, rd),
1304 else => unreachable,
1305 };
1306 }
1307
1240 pub fn nop() Instruction {1308 pub fn nop() Instruction {
1241 return sethi(0, .g0);1309 return sethi(0, .g0);
1242 }1310 }
...@@ -1269,6 +1337,54 @@ pub const Instruction = union(enum) {...@@ -1269,6 +1337,54 @@ pub const Instruction = union(enum) {
1269 return format2a(0b100, imm, rd);1337 return format2a(0b100, imm, rd);
1270 }1338 }
12711339
1340 pub fn sll(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1341 return switch (s2) {
1342 Register => format3k(0b11, 0b10_0101, .shift32, rs1, rs2, rd),
1343 u5 => format3l(0b11, 0b10_0101, rs1, rs2, rd),
1344 else => unreachable,
1345 };
1346 }
1347
1348 pub fn srl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1349 return switch (s2) {
1350 Register => format3k(0b11, 0b10_0110, .shift32, rs1, rs2, rd),
1351 u5 => format3l(0b11, 0b10_0110, rs1, rs2, rd),
1352 else => unreachable,
1353 };
1354 }
1355
1356 pub fn sra(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1357 return switch (s2) {
1358 Register => format3k(0b11, 0b10_0111, .shift32, rs1, rs2, rd),
1359 u5 => format3l(0b11, 0b10_0111, rs1, rs2, rd),
1360 else => unreachable,
1361 };
1362 }
1363
1364 pub fn sllx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1365 return switch (s2) {
1366 Register => format3k(0b11, 0b10_0101, .shift64, rs1, rs2, rd),
1367 u6 => format3m(0b11, 0b10_0101, rs1, rs2, rd),
1368 else => unreachable,
1369 };
1370 }
1371
1372 pub fn srlx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1373 return switch (s2) {
1374 Register => format3k(0b11, 0b10_0110, .shift64, rs1, rs2, rd),
1375 u6 => format3m(0b11, 0b10_0110, rs1, rs2, rd),
1376 else => unreachable,
1377 };
1378 }
1379
1380 pub fn srax(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1381 return switch (s2) {
1382 Register => format3k(0b11, 0b10_0111, .shift64, rs1, rs2, rd),
1383 u6 => format3m(0b11, 0b10_0111, rs1, rs2, rd),
1384 else => unreachable,
1385 };
1386 }
1387
1272 pub fn stb(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {1388 pub fn stb(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1273 return switch (s2) {1389 return switch (s2) {
1274 Register => format3a(0b11, 0b00_0101, rs1, rs2, rd),1390 Register => format3a(0b11, 0b00_0101, rs1, rs2, rd),
test/behavior/array.zig+1
...@@ -511,6 +511,7 @@ test "zero-sized array with recursive type definition" {...@@ -511,6 +511,7 @@ test "zero-sized array with recursive type definition" {
511511
512test "type coercion of anon struct literal to array" {512test "type coercion of anon struct literal to array" {
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO515 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516517
test/behavior/atomics.zig+13
...@@ -8,6 +8,7 @@ test "cmpxchg" {...@@ -8,6 +8,7 @@ test "cmpxchg" {
8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1213
13 try testCmpxchg();14 try testCmpxchg();
...@@ -48,6 +49,7 @@ test "atomicrmw and atomicload" {...@@ -48,6 +49,7 @@ test "atomicrmw and atomicload" {
48 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5254
53 var data: u8 = 200;55 var data: u8 = 200;
...@@ -77,6 +79,7 @@ test "cmpxchg with ptr" {...@@ -77,6 +79,7 @@ test "cmpxchg with ptr" {
77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO80 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8184
82 var data1: i32 = 1234;85 var data1: i32 = 1234;
...@@ -103,6 +106,7 @@ test "cmpxchg with ignored result" {...@@ -103,6 +106,7 @@ test "cmpxchg with ignored result" {
103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO106 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO107 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
107111
108 var x: i32 = 1234;112 var x: i32 = 1234;
...@@ -117,6 +121,7 @@ test "128-bit cmpxchg" {...@@ -117,6 +121,7 @@ test "128-bit cmpxchg" {
117 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO121 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121126
122 if (builtin.cpu.arch != .x86_64) return error.SkipZigTest;127 if (builtin.cpu.arch != .x86_64) return error.SkipZigTest;
...@@ -150,6 +155,7 @@ test "cmpxchg on a global variable" {...@@ -150,6 +155,7 @@ test "cmpxchg on a global variable" {
150 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO155 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
151 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO156 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
154160
155 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and161 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and
...@@ -168,6 +174,7 @@ test "atomic load and rmw with enum" {...@@ -168,6 +174,7 @@ test "atomic load and rmw with enum" {
168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO174 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO175 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
172179
173 const Value = enum(u8) { a, b, c };180 const Value = enum(u8) { a, b, c };
...@@ -186,6 +193,7 @@ test "atomic store" {...@@ -186,6 +193,7 @@ test "atomic store" {
186 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO193 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
187 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO194 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO195 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO197 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
190198
191 var x: u32 = 0;199 var x: u32 = 0;
...@@ -200,6 +208,7 @@ test "atomic store comptime" {...@@ -200,6 +208,7 @@ test "atomic store comptime" {
200 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO208 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO209 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO212 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204213
205 comptime try testAtomicStore();214 comptime try testAtomicStore();
...@@ -219,6 +228,7 @@ test "atomicrmw with floats" {...@@ -219,6 +228,7 @@ test "atomicrmw with floats" {
219 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
223233
224 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and234 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and
...@@ -247,6 +257,7 @@ test "atomicrmw with ints" {...@@ -247,6 +257,7 @@ test "atomicrmw with ints" {
247 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO257 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO258 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
251262
252 try testAtomicRmwInt();263 try testAtomicRmwInt();
...@@ -281,6 +292,7 @@ test "atomics with different types" {...@@ -281,6 +292,7 @@ test "atomics with different types" {
281 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO292 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO293 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO294 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285297
286 try testAtomicsWithType(bool, true, false);298 try testAtomicsWithType(bool, true, false);
...@@ -311,6 +323,7 @@ test "return @atomicStore, using it as a void value" {...@@ -311,6 +323,7 @@ test "return @atomicStore, using it as a void value" {
311 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO323 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
312 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
326 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315328
316 const S = struct {329 const S = struct {
test/behavior/basic.zig+5
...@@ -24,6 +24,8 @@ fn testTruncate(x: u32) u8 {...@@ -24,6 +24,8 @@ fn testTruncate(x: u32) u8 {
24}24}
2525
26test "truncate to non-power-of-two integers" {26test "truncate to non-power-of-two integers" {
27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
28
27 try testTrunc(u32, u1, 0b10101, 0b1);29 try testTrunc(u32, u1, 0b10101, 0b1);
28 try testTrunc(u32, u1, 0b10110, 0b0);30 try testTrunc(u32, u1, 0b10110, 0b0);
29 try testTrunc(u32, u2, 0b10101, 0b01);31 try testTrunc(u32, u2, 0b10101, 0b01);
...@@ -401,6 +403,7 @@ fn testPointerToVoidReturnType2() *const void {...@@ -401,6 +403,7 @@ fn testPointerToVoidReturnType2() *const void {
401403
402test "array 2D const double ptr" {404test "array 2D const double ptr" {
403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;407 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;408 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO409 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -414,6 +417,7 @@ test "array 2D const double ptr" {...@@ -414,6 +417,7 @@ test "array 2D const double ptr" {
414417
415test "array 2D const double ptr with offset" {418test "array 2D const double ptr with offset" {
416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
417 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;422 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;423 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
...@@ -427,6 +431,7 @@ test "array 2D const double ptr with offset" {...@@ -427,6 +431,7 @@ test "array 2D const double ptr with offset" {
427431
428test "array 3D const double ptr with offset" {432test "array 3D const double ptr with offset" {
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
431 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;436 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
432 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO437 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/bugs/9584.zig+1
...@@ -46,6 +46,7 @@ test {...@@ -46,6 +46,7 @@ test {
46 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5152
test/behavior/byteswap.zig+1
...@@ -7,6 +7,7 @@ test "@byteSwap integers" {...@@ -7,6 +7,7 @@ test "@byteSwap integers" {
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1011
11 const ByteSwapIntTest = struct {12 const ByteSwapIntTest = struct {
12 fn run() !void {13 fn run() !void {