| author | |
| committer | |
| log | 7baf0de807afc8c2c56cc1278e624e9103c30cfb |
| tree | 8fd39ab072376b73f2e62147a7e1bd9d75293432 |
| parent | 13aaa16ab2cac5c07a970a3b49f5dd0ffd4d3539 |
| parent | ccc9b8caf632bf97f7765c1b1d7821118cf34008 |
| signature |
stage2: sparc64: Yet another patchset for the selfhosted backend14 files changed, 331 insertions(+), 12 deletions(-)
src/arch/sparc64/CodeGen.zig+205-11| ... | @@ -22,6 +22,7 @@ const Type = @import("../../type.zig").Type; | ... | @@ -22,6 +22,7 @@ const Type = @import("../../type.zig").Type; |
| 22 | const CodeGenError = codegen.CodeGenError; | 22 | const CodeGenError = codegen.CodeGenError; |
| 23 | const Result = @import("../../codegen.zig").Result; | 23 | const Result = @import("../../codegen.zig").Result; |
| 24 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 24 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 25 | const Endian = std.builtin.Endian; | ||
| 25 | 26 | ||
| 26 | const build_options = @import("build_options"); | 27 | const build_options = @import("build_options"); |
| 27 | 28 | ||
| ... | @@ -30,6 +31,7 @@ const abi = @import("abi.zig"); | ... | @@ -30,6 +31,7 @@ const abi = @import("abi.zig"); |
| 30 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 31 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 31 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 32 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 32 | const Instruction = bits.Instruction; | 33 | const Instruction = bits.Instruction; |
| 34 | const ASI = Instruction.ASI; | ||
| 33 | const ShiftWidth = Instruction.ShiftWidth; | 35 | const ShiftWidth = Instruction.ShiftWidth; |
| 34 | const RegisterManager = abi.RegisterManager; | 36 | const RegisterManager = abi.RegisterManager; |
| 35 | const RegisterLock = RegisterManager.RegisterLock; | 37 | const RegisterLock = RegisterManager.RegisterLock; |
| ... | @@ -141,6 +143,8 @@ const MCValue = union(enum) { | ... | @@ -141,6 +143,8 @@ const MCValue = union(enum) { |
| 141 | /// The value is one of the stack variables. | 143 | /// The value is one of the stack variables. |
| 142 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 144 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 143 | /// Note that this stores the plain value (i.e without the effects of the stack bias). | 145 | /// Note that this stores the plain value (i.e without the effects of the stack bias). |
| 146 | /// Always convert this value into machine offsets with realStackOffset() before | ||
| 147 | /// lowering into asm! | ||
| 144 | stack_offset: u32, | 148 | stack_offset: u32, |
| 145 | /// The value is a pointer to one of the stack variables (payload is stack offset). | 149 | /// The value is a pointer to one of the stack variables (payload is stack offset). |
| 146 | ptr_stack_offset: u32, | 150 | ptr_stack_offset: u32, |
| ... | @@ -595,7 +599,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -595,7 +599,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 595 | .ret_load => try self.airRetLoad(inst), | 599 | .ret_load => try self.airRetLoad(inst), |
| 596 | .store => try self.airStore(inst, false), | 600 | .store => try self.airStore(inst, false), |
| 597 | .store_safe => try self.airStore(inst, true), | 601 | .store_safe => try self.airStore(inst, true), |
| 598 | .struct_field_ptr=> @panic("TODO try self.airStructFieldPtr(inst)"), | 602 | .struct_field_ptr=> try self.airStructFieldPtr(inst), |
| 599 | .struct_field_val=> try self.airStructFieldVal(inst), | 603 | .struct_field_val=> try self.airStructFieldVal(inst), |
| 600 | .array_to_slice => try self.airArrayToSlice(inst), | 604 | .array_to_slice => try self.airArrayToSlice(inst), |
| 601 | .int_to_float => try self.airIntToFloat(inst), | 605 | .int_to_float => try self.airIntToFloat(inst), |
| ... | @@ -613,7 +617,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -613,7 +617,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 613 | .clz => try self.airClz(inst), | 617 | .clz => try self.airClz(inst), |
| 614 | .ctz => try self.airCtz(inst), | 618 | .ctz => try self.airCtz(inst), |
| 615 | .popcount => try self.airPopcount(inst), | 619 | .popcount => try self.airPopcount(inst), |
| 616 | .byte_swap => @panic("TODO try self.airByteSwap(inst)"), | 620 | .byte_swap => try self.airByteSwap(inst), |
| 617 | .bit_reverse => try self.airBitReverse(inst), | 621 | .bit_reverse => try self.airBitReverse(inst), |
| 618 | .tag_name => try self.airTagName(inst), | 622 | .tag_name => try self.airTagName(inst), |
| 619 | .error_name => try self.airErrorName(inst), | 623 | .error_name => try self.airErrorName(inst), |
| ... | @@ -663,8 +667,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -663,8 +667,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 663 | .slice_ptr => try self.airSlicePtr(inst), | 667 | .slice_ptr => try self.airSlicePtr(inst), |
| 664 | .slice_len => try self.airSliceLen(inst), | 668 | .slice_len => try self.airSliceLen(inst), |
| 665 | 669 | ||
| 666 | .ptr_slice_len_ptr => @panic("TODO try self.airPtrSliceLenPtr(inst)"), | 670 | .ptr_slice_len_ptr => try self.airPtrSliceLenPtr(inst), |
| 667 | .ptr_slice_ptr_ptr => @panic("TODO try self.airPtrSlicePtrPtr(inst)"), | 671 | .ptr_slice_ptr_ptr => try self.airPtrSlicePtrPtr(inst), |
| 668 | 672 | ||
| 669 | .array_elem_val => try self.airArrayElemVal(inst), | 673 | .array_elem_val => try self.airArrayElemVal(inst), |
| 670 | .slice_elem_val => try self.airSliceElemVal(inst), | 674 | .slice_elem_val => try self.airSliceElemVal(inst), |
| ... | @@ -720,10 +724,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -720,10 +724,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 720 | .error_set_has_value => @panic("TODO implement error_set_has_value"), | 724 | .error_set_has_value => @panic("TODO implement error_set_has_value"), |
| 721 | .vector_store_elem => @panic("TODO implement vector_store_elem"), | 725 | .vector_store_elem => @panic("TODO implement vector_store_elem"), |
| 722 | 726 | ||
| 723 | .c_va_arg => @panic("TODO implement c_va_arg"), | 727 | .c_va_arg => return self.fail("TODO implement c_va_arg", .{}), |
| 724 | .c_va_copy => @panic("TODO implement c_va_copy"), | 728 | .c_va_copy => return self.fail("TODO implement c_va_copy", .{}), |
| 725 | .c_va_end => @panic("TODO implement c_va_end"), | 729 | .c_va_end => return self.fail("TODO implement c_va_end", .{}), |
| 726 | .c_va_start => @panic("TODO implement c_va_start"), | 730 | .c_va_start => return self.fail("TODO implement c_va_start", .{}), |
| 727 | 731 | ||
| 728 | .wasm_memory_size => unreachable, | 732 | .wasm_memory_size => unreachable, |
| 729 | .wasm_memory_grow => unreachable, | 733 | .wasm_memory_grow => unreachable, |
| ... | @@ -1198,6 +1202,90 @@ fn airBreakpoint(self: *Self) !void { | ... | @@ -1198,6 +1202,90 @@ fn airBreakpoint(self: *Self) !void { |
| 1198 | return self.finishAirBookkeeping(); | 1202 | return self.finishAirBookkeeping(); |
| 1199 | } | 1203 | } |
| 1200 | 1204 | ||
| 1205 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | ||
| 1206 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 1207 | |||
| 1208 | // We have hardware byteswapper in SPARCv9, don't let mainstream compilers mislead you. | ||
| 1209 | // That being said, the strategy to lower this is: | ||
| 1210 | // - If src is an immediate, comptime-swap it. | ||
| 1211 | // - If src is in memory then issue an LD*A with #ASI_P_[oppposite-endian] | ||
| 1212 | // - If src is a register then issue an ST*A with #ASI_P_[oppposite-endian] | ||
| 1213 | // to a stack slot, then follow with a normal load from said stack slot. | ||
| 1214 | // This is because on some implementations, ASI-tagged memory operations are non-piplelinable | ||
| 1215 | // and loads tend to have longer latency than stores, so the sequence will minimize stall. | ||
| 1216 | // The result will always be either another immediate or stored in a register. | ||
| 1217 | // TODO: Fold byteswap+store into a single ST*A and load+byteswap into a single LD*A. | ||
| 1218 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | ||
| 1219 | const operand = try self.resolveInst(ty_op.operand); | ||
| 1220 | const operand_ty = self.air.typeOf(ty_op.operand); | ||
| 1221 | switch (operand_ty.zigTypeTag()) { | ||
| 1222 | .Vector => return self.fail("TODO byteswap for vectors", .{}), | ||
| 1223 | .Int => { | ||
| 1224 | const int_info = operand_ty.intInfo(self.target.*); | ||
| 1225 | if (int_info.bits == 8) break :result operand; | ||
| 1226 | |||
| 1227 | const abi_size = int_info.bits >> 3; | ||
| 1228 | const abi_align = operand_ty.abiAlignment(self.target.*); | ||
| 1229 | const opposite_endian_asi = switch (self.target.cpu.arch.endian()) { | ||
| 1230 | Endian.Big => ASI.asi_primary_little, | ||
| 1231 | Endian.Little => ASI.asi_primary, | ||
| 1232 | }; | ||
| 1233 | |||
| 1234 | switch (operand) { | ||
| 1235 | .immediate => |imm| { | ||
| 1236 | const swapped = switch (int_info.bits) { | ||
| 1237 | 16 => @byteSwap(@intCast(u16, imm)), | ||
| 1238 | 24 => @byteSwap(@intCast(u24, imm)), | ||
| 1239 | 32 => @byteSwap(@intCast(u32, imm)), | ||
| 1240 | 40 => @byteSwap(@intCast(u40, imm)), | ||
| 1241 | 48 => @byteSwap(@intCast(u48, imm)), | ||
| 1242 | 56 => @byteSwap(@intCast(u56, imm)), | ||
| 1243 | 64 => @byteSwap(@intCast(u64, imm)), | ||
| 1244 | else => return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}), | ||
| 1245 | }; | ||
| 1246 | break :result .{ .immediate = swapped }; | ||
| 1247 | }, | ||
| 1248 | .register => |reg| { | ||
| 1249 | if (int_info.bits > 64 or @popCount(int_info.bits) != 1) | ||
| 1250 | return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); | ||
| 1251 | |||
| 1252 | const off = try self.allocMem(inst, abi_size, abi_align); | ||
| 1253 | const off_reg = try self.copyToTmpRegister(operand_ty, .{ .immediate = realStackOffset(off) }); | ||
| 1254 | |||
| 1255 | try self.genStoreASI(reg, .sp, off_reg, abi_size, opposite_endian_asi); | ||
| 1256 | try self.genLoad(reg, .sp, Register, off_reg, abi_size); | ||
| 1257 | break :result .{ .register = reg }; | ||
| 1258 | }, | ||
| 1259 | .memory => { | ||
| 1260 | if (int_info.bits > 64 or @popCount(int_info.bits) != 1) | ||
| 1261 | return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); | ||
| 1262 | |||
| 1263 | const addr_reg = try self.copyToTmpRegister(operand_ty, operand); | ||
| 1264 | const dst_reg = try self.register_manager.allocReg(null, gp); | ||
| 1265 | |||
| 1266 | try self.genLoadASI(dst_reg, addr_reg, .g0, abi_size, opposite_endian_asi); | ||
| 1267 | break :result .{ .register = dst_reg }; | ||
| 1268 | }, | ||
| 1269 | .stack_offset => |off| { | ||
| 1270 | if (int_info.bits > 64 or @popCount(int_info.bits) != 1) | ||
| 1271 | return self.fail("TODO synthesize SPARCv9 byteswap for other integer sizes", .{}); | ||
| 1272 | |||
| 1273 | const off_reg = try self.copyToTmpRegister(operand_ty, .{ .immediate = realStackOffset(off) }); | ||
| 1274 | const dst_reg = try self.register_manager.allocReg(null, gp); | ||
| 1275 | |||
| 1276 | try self.genLoadASI(dst_reg, .sp, off_reg, abi_size, opposite_endian_asi); | ||
| 1277 | break :result .{ .register = dst_reg }; | ||
| 1278 | }, | ||
| 1279 | else => unreachable, | ||
| 1280 | } | ||
| 1281 | }, | ||
| 1282 | else => unreachable, | ||
| 1283 | } | ||
| 1284 | }; | ||
| 1285 | |||
| 1286 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | ||
| 1287 | } | ||
| 1288 | |||
| 1201 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 1289 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 1202 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); | 1290 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); |
| 1203 | 1291 | ||
| ... | @@ -2150,6 +2238,38 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2150,6 +2238,38 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2150 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 2238 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 2151 | } | 2239 | } |
| 2152 | 2240 | ||
| 2241 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ||
| 2242 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 2243 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | ||
| 2244 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 2245 | const ptr_bytes = @divExact(ptr_bits, 8); | ||
| 2246 | const mcv = try self.resolveInst(ty_op.operand); | ||
| 2247 | switch (mcv) { | ||
| 2248 | .dead, .unreach, .none => unreachable, | ||
| 2249 | .ptr_stack_offset => |off| { | ||
| 2250 | break :result MCValue{ .ptr_stack_offset = off - ptr_bytes }; | ||
| 2251 | }, | ||
| 2252 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), | ||
| 2253 | } | ||
| 2254 | }; | ||
| 2255 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | ||
| 2256 | } | ||
| 2257 | |||
| 2258 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ||
| 2259 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | ||
| 2260 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | ||
| 2261 | const mcv = try self.resolveInst(ty_op.operand); | ||
| 2262 | switch (mcv) { | ||
| 2263 | .dead, .unreach, .none => unreachable, | ||
| 2264 | .ptr_stack_offset => |off| { | ||
| 2265 | break :result MCValue{ .ptr_stack_offset = off }; | ||
| 2266 | }, | ||
| 2267 | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), | ||
| 2268 | } | ||
| 2269 | }; | ||
| 2270 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | ||
| 2271 | } | ||
| 2272 | |||
| 2153 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | 2273 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 2154 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2274 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2155 | const result = try self.resolveInst(un_op); | 2275 | const result = try self.resolveInst(un_op); |
| ... | @@ -2425,6 +2545,13 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -2425,6 +2545,13 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 2425 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 2545 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2426 | } | 2546 | } |
| 2427 | 2547 | ||
| 2548 | fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { | ||
| 2549 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | ||
| 2550 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | ||
| 2551 | const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); | ||
| 2552 | return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); | ||
| 2553 | } | ||
| 2554 | |||
| 2428 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | 2555 | fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 2429 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2556 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2430 | const result = try self.structFieldPtr(inst, ty_op.operand, index); | 2557 | const result = try self.structFieldPtr(inst, ty_op.operand, index); |
| ... | @@ -3574,6 +3701,34 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty | ... | @@ -3574,6 +3701,34 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty |
| 3574 | } | 3701 | } |
| 3575 | } | 3702 | } |
| 3576 | 3703 | ||
| 3704 | fn genLoadASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Register, abi_size: u64, asi: ASI) !void { | ||
| 3705 | switch (abi_size) { | ||
| 3706 | 1, 2, 4, 8 => { | ||
| 3707 | const tag: Mir.Inst.Tag = switch (abi_size) { | ||
| 3708 | 1 => .lduba, | ||
| 3709 | 2 => .lduha, | ||
| 3710 | 4 => .lduwa, | ||
| 3711 | 8 => .ldxa, | ||
| 3712 | else => unreachable, // unexpected abi size | ||
| 3713 | }; | ||
| 3714 | |||
| 3715 | _ = try self.addInst(.{ | ||
| 3716 | .tag = tag, | ||
| 3717 | .data = .{ | ||
| 3718 | .mem_asi = .{ | ||
| 3719 | .rd = value_reg, | ||
| 3720 | .rs1 = addr_reg, | ||
| 3721 | .rs2 = off_reg, | ||
| 3722 | .asi = asi, | ||
| 3723 | }, | ||
| 3724 | }, | ||
| 3725 | }); | ||
| 3726 | }, | ||
| 3727 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), | ||
| 3728 | else => unreachable, | ||
| 3729 | } | ||
| 3730 | } | ||
| 3731 | |||
| 3577 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 3732 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3578 | switch (mcv) { | 3733 | switch (mcv) { |
| 3579 | .dead => unreachable, | 3734 | .dead => unreachable, |
| ... | @@ -3644,7 +3799,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3644,7 +3799,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3644 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); | 3799 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| 3645 | }, | 3800 | }, |
| 3646 | .ptr_stack_offset => |off| { | 3801 | .ptr_stack_offset => |off| { |
| 3647 | const real_offset = off + abi.stack_bias + abi.stack_reserved_area; | 3802 | const real_offset = realStackOffset(off); |
| 3648 | const simm13 = math.cast(i13, real_offset) orelse | 3803 | const simm13 = math.cast(i13, real_offset) orelse |
| 3649 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); | 3804 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 3650 | 3805 | ||
| ... | @@ -3776,7 +3931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3776,7 +3931,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3776 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); | 3931 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); |
| 3777 | }, | 3932 | }, |
| 3778 | .stack_offset => |off| { | 3933 | .stack_offset => |off| { |
| 3779 | const real_offset = off + abi.stack_bias + abi.stack_reserved_area; | 3934 | const real_offset = realStackOffset(off); |
| 3780 | const simm13 = math.cast(i13, real_offset) orelse | 3935 | const simm13 = math.cast(i13, real_offset) orelse |
| 3781 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); | 3936 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 3782 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); | 3937 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); |
| ... | @@ -3810,7 +3965,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3810,7 +3965,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3810 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 3965 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3811 | }, | 3966 | }, |
| 3812 | .register => |reg| { | 3967 | .register => |reg| { |
| 3813 | const real_offset = stack_offset + abi.stack_bias + abi.stack_reserved_area; | 3968 | const real_offset = realStackOffset(stack_offset); |
| 3814 | const simm13 = math.cast(i13, real_offset) orelse | 3969 | const simm13 = math.cast(i13, real_offset) orelse |
| 3815 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); | 3970 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 3816 | return self.genStore(reg, .sp, i13, simm13, abi_size); | 3971 | return self.genStore(reg, .sp, i13, simm13, abi_size); |
| ... | @@ -3933,6 +4088,34 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t | ... | @@ -3933,6 +4088,34 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t |
| 3933 | } | 4088 | } |
| 3934 | } | 4089 | } |
| 3935 | 4090 | ||
| 4091 | fn genStoreASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Register, abi_size: u64, asi: ASI) !void { | ||
| 4092 | switch (abi_size) { | ||
| 4093 | 1, 2, 4, 8 => { | ||
| 4094 | const tag: Mir.Inst.Tag = switch (abi_size) { | ||
| 4095 | 1 => .stba, | ||
| 4096 | 2 => .stha, | ||
| 4097 | 4 => .stwa, | ||
| 4098 | 8 => .stxa, | ||
| 4099 | else => unreachable, // unexpected abi size | ||
| 4100 | }; | ||
| 4101 | |||
| 4102 | _ = try self.addInst(.{ | ||
| 4103 | .tag = tag, | ||
| 4104 | .data = .{ | ||
| 4105 | .mem_asi = .{ | ||
| 4106 | .rd = value_reg, | ||
| 4107 | .rs1 = addr_reg, | ||
| 4108 | .rs2 = off_reg, | ||
| 4109 | .asi = asi, | ||
| 4110 | }, | ||
| 4111 | }, | ||
| 4112 | }); | ||
| 4113 | }, | ||
| 4114 | 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), | ||
| 4115 | else => unreachable, | ||
| 4116 | } | ||
| 4117 | } | ||
| 4118 | |||
| 3936 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 4119 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3937 | const mcv: MCValue = switch (try codegen.genTypedValue( | 4120 | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 3938 | self.bin_file, | 4121 | self.bin_file, |
| ... | @@ -4245,6 +4428,17 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -4245,6 +4428,17 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 4245 | } | 4428 | } |
| 4246 | } | 4429 | } |
| 4247 | 4430 | ||
| 4431 | /// Turns stack_offset MCV into a real SPARCv9 stack offset usable for asm. | ||
| 4432 | fn realStackOffset(off: u32) u32 { | ||
| 4433 | return off | ||
| 4434 | // SPARCv9 %sp points away from the stack by some amount. | ||
| 4435 | + abi.stack_bias | ||
| 4436 | // The first couple bytes of each stack frame is reserved | ||
| 4437 | // for ABI and hardware purposes. | ||
| 4438 | + abi.stack_reserved_area; | ||
| 4439 | // Only after that we have the usable stack frame portion. | ||
| 4440 | } | ||
| 4441 | |||
| 4248 | /// Caller must call `CallMCValues.deinit`. | 4442 | /// Caller must call `CallMCValues.deinit`. |
| 4249 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { | 4443 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { |
| 4250 | const cc = fn_ty.fnCallingConvention(); | 4444 | const cc = fn_ty.fnCallingConvention(); |
src/arch/sparc64/Emit.zig+33| ... | @@ -91,6 +91,11 @@ pub fn emitMir( | ... | @@ -91,6 +91,11 @@ pub fn emitMir( |
| 91 | .lduw => try emit.mirArithmetic3Op(inst), | 91 | .lduw => try emit.mirArithmetic3Op(inst), |
| 92 | .ldx => try emit.mirArithmetic3Op(inst), | 92 | .ldx => try emit.mirArithmetic3Op(inst), |
| 93 | 93 | ||
| 94 | .lduba => try emit.mirMemASI(inst), | ||
| 95 | .lduha => try emit.mirMemASI(inst), | ||
| 96 | .lduwa => try emit.mirMemASI(inst), | ||
| 97 | .ldxa => try emit.mirMemASI(inst), | ||
| 98 | |||
| 94 | .@"and" => try emit.mirArithmetic3Op(inst), | 99 | .@"and" => try emit.mirArithmetic3Op(inst), |
| 95 | .@"or" => try emit.mirArithmetic3Op(inst), | 100 | .@"or" => try emit.mirArithmetic3Op(inst), |
| 96 | .xor => try emit.mirArithmetic3Op(inst), | 101 | .xor => try emit.mirArithmetic3Op(inst), |
| ... | @@ -127,6 +132,11 @@ pub fn emitMir( | ... | @@ -127,6 +132,11 @@ pub fn emitMir( |
| 127 | .stw => try emit.mirArithmetic3Op(inst), | 132 | .stw => try emit.mirArithmetic3Op(inst), |
| 128 | .stx => try emit.mirArithmetic3Op(inst), | 133 | .stx => try emit.mirArithmetic3Op(inst), |
| 129 | 134 | ||
| 135 | .stba => try emit.mirMemASI(inst), | ||
| 136 | .stha => try emit.mirMemASI(inst), | ||
| 137 | .stwa => try emit.mirMemASI(inst), | ||
| 138 | .stxa => try emit.mirMemASI(inst), | ||
| 139 | |||
| 130 | .sub => try emit.mirArithmetic3Op(inst), | 140 | .sub => try emit.mirArithmetic3Op(inst), |
| 131 | .subcc => try emit.mirArithmetic3Op(inst), | 141 | .subcc => try emit.mirArithmetic3Op(inst), |
| 132 | 142 | ||
| ... | @@ -368,6 +378,29 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -368,6 +378,29 @@ fn mirConditionalMove(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 368 | } | 378 | } |
| 369 | } | 379 | } |
| 370 | 380 | ||
| 381 | fn mirMemASI(emit: *Emit, inst: Mir.Inst.Index) !void { | ||
| 382 | const tag = emit.mir.instructions.items(.tag)[inst]; | ||
| 383 | const data = emit.mir.instructions.items(.data)[inst].mem_asi; | ||
| 384 | |||
| 385 | const rd = data.rd; | ||
| 386 | const rs1 = data.rs1; | ||
| 387 | const rs2 = data.rs2; | ||
| 388 | const asi = data.asi; | ||
| 389 | |||
| 390 | switch (tag) { | ||
| 391 | .lduba => try emit.writeInstruction(Instruction.lduba(rs1, rs2, asi, rd)), | ||
| 392 | .lduha => try emit.writeInstruction(Instruction.lduha(rs1, rs2, asi, rd)), | ||
| 393 | .lduwa => try emit.writeInstruction(Instruction.lduwa(rs1, rs2, asi, rd)), | ||
| 394 | .ldxa => try emit.writeInstruction(Instruction.ldxa(rs1, rs2, asi, rd)), | ||
| 395 | |||
| 396 | .stba => try emit.writeInstruction(Instruction.stba(rs1, rs2, asi, rd)), | ||
| 397 | .stha => try emit.writeInstruction(Instruction.stha(rs1, rs2, asi, rd)), | ||
| 398 | .stwa => try emit.writeInstruction(Instruction.stwa(rs1, rs2, asi, rd)), | ||
| 399 | .stxa => try emit.writeInstruction(Instruction.stxa(rs1, rs2, asi, rd)), | ||
| 400 | else => unreachable, | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 371 | fn mirMembar(emit: *Emit, inst: Mir.Inst.Index) !void { | 404 | fn mirMembar(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 372 | const tag = emit.mir.instructions.items(.tag)[inst]; | 405 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 373 | const mask = emit.mir.instructions.items(.data)[inst].membar_mask; | 406 | const mask = emit.mir.instructions.items(.data)[inst].membar_mask; |
src/arch/sparc64/Mir.zig+30| ... | @@ -15,6 +15,7 @@ const bits = @import("bits.zig"); | ... | @@ -15,6 +15,7 @@ const bits = @import("bits.zig"); |
| 15 | const Air = @import("../../Air.zig"); | 15 | const Air = @import("../../Air.zig"); |
| 16 | 16 | ||
| 17 | const Instruction = bits.Instruction; | 17 | const Instruction = bits.Instruction; |
| 18 | const ASI = bits.Instruction.ASI; | ||
| 18 | const Register = bits.Register; | 19 | const Register = bits.Register; |
| 19 | 20 | ||
| 20 | instructions: std.MultiArrayList(Inst).Slice, | 21 | instructions: std.MultiArrayList(Inst).Slice, |
| ... | @@ -70,6 +71,16 @@ pub const Inst = struct { | ... | @@ -70,6 +71,16 @@ pub const Inst = struct { |
| 70 | lduw, | 71 | lduw, |
| 71 | ldx, | 72 | ldx, |
| 72 | 73 | ||
| 74 | /// A.28 Load Integer from Alternate Space | ||
| 75 | /// This uses the mem_asi field. | ||
| 76 | /// Note that the ldda variant of this instruction is deprecated, so do not emit | ||
| 77 | /// it unless specifically requested (e.g. by inline assembly). | ||
| 78 | // TODO add other operations. | ||
| 79 | lduba, | ||
| 80 | lduha, | ||
| 81 | lduwa, | ||
| 82 | ldxa, | ||
| 83 | |||
| 73 | /// A.31 Logical Operations | 84 | /// A.31 Logical Operations |
| 74 | /// This uses the arithmetic_3op field. | 85 | /// This uses the arithmetic_3op field. |
| 75 | // TODO add other operations. | 86 | // TODO add other operations. |
| ... | @@ -132,6 +143,16 @@ pub const Inst = struct { | ... | @@ -132,6 +143,16 @@ pub const Inst = struct { |
| 132 | stw, | 143 | stw, |
| 133 | stx, | 144 | stx, |
| 134 | 145 | ||
| 146 | /// A.55 Store Integer into Alternate Space | ||
| 147 | /// This uses the mem_asi field. | ||
| 148 | /// Note that the stda variant of this instruction is deprecated, so do not emit | ||
| 149 | /// it unless specifically requested (e.g. by inline assembly). | ||
| 150 | // TODO add other operations. | ||
| 151 | stba, | ||
| 152 | stha, | ||
| 153 | stwa, | ||
| 154 | stxa, | ||
| 155 | |||
| 135 | /// A.56 Subtract | 156 | /// A.56 Subtract |
| 136 | /// This uses the arithmetic_3op field. | 157 | /// This uses the arithmetic_3op field. |
| 137 | // TODO add other operations. | 158 | // TODO add other operations. |
| ... | @@ -241,6 +262,15 @@ pub const Inst = struct { | ... | @@ -241,6 +262,15 @@ pub const Inst = struct { |
| 241 | inst: Index, | 262 | inst: Index, |
| 242 | }, | 263 | }, |
| 243 | 264 | ||
| 265 | /// ASI-tagged memory operations. | ||
| 266 | /// Used by e.g. ldxa, stxa | ||
| 267 | mem_asi: struct { | ||
| 268 | rd: Register, | ||
| 269 | rs1: Register, | ||
| 270 | rs2: Register = .g0, | ||
| 271 | asi: ASI, | ||
| 272 | }, | ||
| 273 | |||
| 244 | /// Membar mask, controls the barrier behavior | 274 | /// Membar mask, controls the barrier behavior |
| 245 | /// Used by e.g. membar | 275 | /// Used by e.g. membar |
| 246 | membar_mask: struct { | 276 | membar_mask: struct { |
src/arch/sparc64/bits.zig+32| ... | @@ -1229,6 +1229,22 @@ pub const Instruction = union(enum) { | ... | @@ -1229,6 +1229,22 @@ pub const Instruction = union(enum) { |
| 1229 | }; | 1229 | }; |
| 1230 | } | 1230 | } |
| 1231 | 1231 | ||
| 1232 | pub fn lduba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1233 | return format3i(0b11, 0b01_0001, rs1, rs2, rd, asi); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | pub fn lduha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1237 | return format3i(0b11, 0b01_0010, rs1, rs2, rd, asi); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | pub fn lduwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1241 | return format3i(0b11, 0b01_0000, rs1, rs2, rd, asi); | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | pub fn ldxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1245 | return format3i(0b11, 0b01_1011, rs1, rs2, rd, asi); | ||
| 1246 | } | ||
| 1247 | |||
| 1232 | pub fn @"and"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { | 1248 | pub fn @"and"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { |
| 1233 | return switch (s2) { | 1249 | return switch (s2) { |
| 1234 | Register => format3a(0b10, 0b00_0001, rs1, rs2, rd), | 1250 | Register => format3a(0b10, 0b00_0001, rs1, rs2, rd), |
| ... | @@ -1417,6 +1433,22 @@ pub const Instruction = union(enum) { | ... | @@ -1417,6 +1433,22 @@ pub const Instruction = union(enum) { |
| 1417 | }; | 1433 | }; |
| 1418 | } | 1434 | } |
| 1419 | 1435 | ||
| 1436 | pub fn stba(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1437 | return format3i(0b11, 0b01_0101, rs1, rs2, rd, asi); | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | pub fn stha(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1441 | return format3i(0b11, 0b01_0110, rs1, rs2, rd, asi); | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | pub fn stwa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1445 | return format3i(0b11, 0b01_0100, rs1, rs2, rd, asi); | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | pub fn stxa(rs1: Register, rs2: Register, asi: ASI, rd: Register) Instruction { | ||
| 1449 | return format3i(0b11, 0b01_1110, rs1, rs2, rd, asi); | ||
| 1450 | } | ||
| 1451 | |||
| 1420 | pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { | 1452 | pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { |
| 1421 | return switch (s2) { | 1453 | return switch (s2) { |
| 1422 | Register => format3a(0b10, 0b00_0100, rs1, rs2, rd), | 1454 | Register => format3a(0b10, 0b00_0100, rs1, rs2, rd), |
test/behavior/array.zig+4| ... | @@ -47,6 +47,7 @@ fn getArrayLen(a: []const u32) usize { | ... | @@ -47,6 +47,7 @@ fn getArrayLen(a: []const u32) usize { |
| 47 | 47 | ||
| 48 | test "array concat with undefined" { | 48 | test "array concat with undefined" { |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 50 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 50 | 51 | ||
| 51 | const S = struct { | 52 | const S = struct { |
| 52 | fn doTheTest() !void { | 53 | fn doTheTest() !void { |
| ... | @@ -70,6 +71,7 @@ test "array concat with undefined" { | ... | @@ -70,6 +71,7 @@ test "array concat with undefined" { |
| 70 | test "array concat with tuple" { | 71 | test "array concat with tuple" { |
| 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 72 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 72 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 73 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 74 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 73 | 75 | ||
| 74 | const array: [2]u8 = .{ 1, 2 }; | 76 | const array: [2]u8 = .{ 1, 2 }; |
| 75 | { | 77 | { |
| ... | @@ -103,6 +105,7 @@ test "array init with mult" { | ... | @@ -103,6 +105,7 @@ test "array init with mult" { |
| 103 | 105 | ||
| 104 | test "array literal with explicit type" { | 106 | test "array literal with explicit type" { |
| 105 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 107 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 106 | 109 | ||
| 107 | const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; | 110 | const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; |
| 108 | 111 | ||
| ... | @@ -203,6 +206,7 @@ test "nested arrays of strings" { | ... | @@ -203,6 +206,7 @@ test "nested arrays of strings" { |
| 203 | 206 | ||
| 204 | test "nested arrays of integers" { | 207 | test "nested arrays of integers" { |
| 205 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 206 | 210 | ||
| 207 | const array_of_numbers = [_][2]u8{ | 211 | const array_of_numbers = [_][2]u8{ |
| 208 | [2]u8{ 1, 2 }, | 212 | [2]u8{ 1, 2 }, |
test/behavior/bugs/12051.zig+1| ... | @@ -6,6 +6,7 @@ test { | ... | @@ -6,6 +6,7 @@ test { |
| 6 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO | 6 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 9 | const x = X{}; | 10 | const x = X{}; |
| 10 | try std.testing.expectEqual(@as(u16, 0), x.y.a); | 11 | try std.testing.expectEqual(@as(u16, 0), x.y.a); |
| 11 | try std.testing.expectEqual(false, x.y.b); | 12 | try std.testing.expectEqual(false, x.y.b); |
test/behavior/bugs/12450.zig+1| ... | @@ -13,6 +13,7 @@ test { | ... | @@ -13,6 +13,7 @@ test { |
| 13 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO | 13 | if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO |
| 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 16 | var f1: *align(16) Foo = @alignCast(16, @ptrCast(*align(1) Foo, &buffer[0])); | 17 | var f1: *align(16) Foo = @alignCast(16, @ptrCast(*align(1) Foo, &buffer[0])); |
| 17 | try expect(@typeInfo(@TypeOf(f1)).Pointer.alignment == 16); | 18 | try expect(@typeInfo(@TypeOf(f1)).Pointer.alignment == 16); |
| 18 | try expect(@ptrToInt(f1) == @ptrToInt(&f1.a)); | 19 | try expect(@ptrToInt(f1) == @ptrToInt(&f1.a)); |
test/behavior/comptime_memory.zig+3| ... | @@ -76,6 +76,7 @@ fn bigToNativeEndian(comptime T: type, v: T) T { | ... | @@ -76,6 +76,7 @@ fn bigToNativeEndian(comptime T: type, v: T) T { |
| 76 | } | 76 | } |
| 77 | test "type pun endianness" { | 77 | test "type pun endianness" { |
| 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 79 | 80 | ||
| 80 | comptime { | 81 | comptime { |
| 81 | const StructOfBytes = extern struct { x: [4]u8 }; | 82 | const StructOfBytes = extern struct { x: [4]u8 }; |
| ... | @@ -376,6 +377,8 @@ test "offset field ptr by enclosing array element size" { | ... | @@ -376,6 +377,8 @@ test "offset field ptr by enclosing array element size" { |
| 376 | 377 | ||
| 377 | test "accessing reinterpreted memory of parent object" { | 378 | test "accessing reinterpreted memory of parent object" { |
| 378 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 380 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 381 | |||
| 379 | const S = extern struct { | 382 | const S = extern struct { |
| 380 | a: f32, | 383 | a: f32, |
| 381 | b: [4]u8, | 384 | b: [4]u8, |
test/behavior/packed-struct.zig+3-1| ... | @@ -563,7 +563,7 @@ test "packed struct passed to callconv(.C) function" { | ... | @@ -563,7 +563,7 @@ test "packed struct passed to callconv(.C) function" { |
| 563 | test "overaligned pointer to packed struct" { | 563 | test "overaligned pointer to packed struct" { |
| 564 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 564 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 566 | 566 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 567 | const S = packed struct { a: u32, b: u32 }; | 567 | const S = packed struct { a: u32, b: u32 }; |
| 568 | var foo: S align(4) = .{ .a = 123, .b = 456 }; | 568 | var foo: S align(4) = .{ .a = 123, .b = 456 }; |
| 569 | const ptr: *align(4) S = &foo; | 569 | const ptr: *align(4) S = &foo; |
| ... | @@ -583,6 +583,7 @@ test "overaligned pointer to packed struct" { | ... | @@ -583,6 +583,7 @@ test "overaligned pointer to packed struct" { |
| 583 | test "packed struct initialized in bitcast" { | 583 | test "packed struct initialized in bitcast" { |
| 584 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 584 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 586 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 586 | 587 | ||
| 587 | const T = packed struct { val: u8 }; | 588 | const T = packed struct { val: u8 }; |
| 588 | var val: u8 = 123; | 589 | var val: u8 = 123; |
| ... | @@ -595,6 +596,7 @@ test "pointer to container level packed struct field" { | ... | @@ -595,6 +596,7 @@ test "pointer to container level packed struct field" { |
| 595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 596 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 596 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 597 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 597 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 598 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 599 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 598 | 600 | ||
| 599 | const S = packed struct(u32) { | 601 | const S = packed struct(u32) { |
| 600 | test_bit: bool, | 602 | test_bit: bool, |
test/behavior/ptrcast.zig+10| ... | @@ -4,6 +4,8 @@ const expect = std.testing.expect; | ... | @@ -4,6 +4,8 @@ const expect = std.testing.expect; |
| 4 | const native_endian = builtin.target.cpu.arch.endian(); | 4 | const native_endian = builtin.target.cpu.arch.endian(); |
| 5 | 5 | ||
| 6 | test "reinterpret bytes as integer with nonzero offset" { | 6 | test "reinterpret bytes as integer with nonzero offset" { |
| 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 8 | |||
| 7 | try testReinterpretBytesAsInteger(); | 9 | try testReinterpretBytesAsInteger(); |
| 8 | comptime try testReinterpretBytesAsInteger(); | 10 | comptime try testReinterpretBytesAsInteger(); |
| 9 | } | 11 | } |
| ... | @@ -74,6 +76,8 @@ fn testReinterpretBytesAsExternStruct() !void { | ... | @@ -74,6 +76,8 @@ fn testReinterpretBytesAsExternStruct() !void { |
| 74 | } | 76 | } |
| 75 | 77 | ||
| 76 | test "reinterpret bytes of an extern struct (with under-aligned fields) into another" { | 78 | test "reinterpret bytes of an extern struct (with under-aligned fields) into another" { |
| 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 80 | |||
| 77 | try testReinterpretExternStructAsExternStruct(); | 81 | try testReinterpretExternStructAsExternStruct(); |
| 78 | comptime try testReinterpretExternStructAsExternStruct(); | 82 | comptime try testReinterpretExternStructAsExternStruct(); |
| 79 | } | 83 | } |
| ... | @@ -96,6 +100,8 @@ fn testReinterpretExternStructAsExternStruct() !void { | ... | @@ -96,6 +100,8 @@ fn testReinterpretExternStructAsExternStruct() !void { |
| 96 | } | 100 | } |
| 97 | 101 | ||
| 98 | test "reinterpret bytes of an extern struct into another" { | 102 | test "reinterpret bytes of an extern struct into another" { |
| 103 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 104 | |||
| 99 | try testReinterpretOverAlignedExternStructAsExternStruct(); | 105 | try testReinterpretOverAlignedExternStructAsExternStruct(); |
| 100 | comptime try testReinterpretOverAlignedExternStructAsExternStruct(); | 106 | comptime try testReinterpretOverAlignedExternStructAsExternStruct(); |
| 101 | } | 107 | } |
| ... | @@ -191,6 +197,8 @@ const Bytes = struct { | ... | @@ -191,6 +197,8 @@ const Bytes = struct { |
| 191 | }; | 197 | }; |
| 192 | 198 | ||
| 193 | test "comptime ptrcast keeps larger alignment" { | 199 | test "comptime ptrcast keeps larger alignment" { |
| 200 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 201 | |||
| 194 | comptime { | 202 | comptime { |
| 195 | const a: u32 = 1234; | 203 | const a: u32 = 1234; |
| 196 | const p = @ptrCast([*]const u8, &a); | 204 | const p = @ptrCast([*]const u8, &a); |
| ... | @@ -199,6 +207,8 @@ test "comptime ptrcast keeps larger alignment" { | ... | @@ -199,6 +207,8 @@ test "comptime ptrcast keeps larger alignment" { |
| 199 | } | 207 | } |
| 200 | 208 | ||
| 201 | test "ptrcast of const integer has the correct object size" { | 209 | test "ptrcast of const integer has the correct object size" { |
| 210 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 211 | |||
| 202 | const is_value = ~@intCast(isize, std.math.minInt(isize)); | 212 | const is_value = ~@intCast(isize, std.math.minInt(isize)); |
| 203 | const is_bytes = @ptrCast([*]const u8, &is_value)[0..@sizeOf(isize)]; | 213 | const is_bytes = @ptrCast([*]const u8, &is_value)[0..@sizeOf(isize)]; |
| 204 | if (@sizeOf(isize) == 8) { | 214 | if (@sizeOf(isize) == 8) { |
test/behavior/tuple.zig+5| ... | @@ -296,6 +296,7 @@ test "coerce tuple to tuple" { | ... | @@ -296,6 +296,7 @@ test "coerce tuple to tuple" { |
| 296 | test "tuple type with void field" { | 296 | test "tuple type with void field" { |
| 297 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 297 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 298 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 298 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 299 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 299 | 300 | ||
| 300 | const T = std.meta.Tuple(&[_]type{void}); | 301 | const T = std.meta.Tuple(&[_]type{void}); |
| 301 | const x = T{{}}; | 302 | const x = T{{}}; |
| ... | @@ -341,6 +342,7 @@ test "tuple type with void field and a runtime field" { | ... | @@ -341,6 +342,7 @@ test "tuple type with void field and a runtime field" { |
| 341 | test "branching inside tuple literal" { | 342 | test "branching inside tuple literal" { |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 343 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 343 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 344 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 345 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 344 | 346 | ||
| 345 | const S = struct { | 347 | const S = struct { |
| 346 | fn foo(a: anytype) !void { | 348 | fn foo(a: anytype) !void { |
| ... | @@ -355,6 +357,7 @@ test "tuple initialized with a runtime known value" { | ... | @@ -355,6 +357,7 @@ test "tuple initialized with a runtime known value" { |
| 355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 358 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 357 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 359 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 360 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 358 | 361 | ||
| 359 | const E = union(enum) { e: []const u8 }; | 362 | const E = union(enum) { e: []const u8 }; |
| 360 | const W = union(enum) { w: E }; | 363 | const W = union(enum) { w: E }; |
| ... | @@ -368,6 +371,7 @@ test "tuple of struct concatenation and coercion to array" { | ... | @@ -368,6 +371,7 @@ test "tuple of struct concatenation and coercion to array" { |
| 368 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 371 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 369 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 372 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 370 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 373 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 371 | 375 | ||
| 372 | const StructWithDefault = struct { value: f32 = 42 }; | 376 | const StructWithDefault = struct { value: f32 = 42 }; |
| 373 | const SomeStruct = struct { array: [4]StructWithDefault }; | 377 | const SomeStruct = struct { array: [4]StructWithDefault }; |
| ... | @@ -381,6 +385,7 @@ test "tuple of struct concatenation and coercion to array" { | ... | @@ -381,6 +385,7 @@ test "tuple of struct concatenation and coercion to array" { |
| 381 | test "nested runtime conditionals in tuple initializer" { | 385 | test "nested runtime conditionals in tuple initializer" { |
| 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 386 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 384 | 389 | ||
| 385 | var data: u8 = 0; | 390 | var data: u8 = 0; |
| 386 | const x = .{ | 391 | const x = .{ |
test/behavior/union.zig+1| ... | @@ -1495,6 +1495,7 @@ test "packed union with zero-bit field" { | ... | @@ -1495,6 +1495,7 @@ test "packed union with zero-bit field" { |
| 1495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1496 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1496 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1497 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1497 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 1498 | 1499 | ||
| 1499 | const S = packed struct { | 1500 | const S = packed struct { |
| 1500 | nested: packed union { | 1501 | nested: packed union { |
test/behavior/var_args.zig+2| ... | @@ -95,6 +95,7 @@ fn doNothingWithFirstArg(args: anytype) void { | ... | @@ -95,6 +95,7 @@ fn doNothingWithFirstArg(args: anytype) void { |
| 95 | 95 | ||
| 96 | test "simple variadic function" { | 96 | test "simple variadic function" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 98 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 98 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 99 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 99 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 100 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 100 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 101 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | @@ -143,6 +144,7 @@ test "simple variadic function" { | ... | @@ -143,6 +144,7 @@ test "simple variadic function" { |
| 143 | 144 | ||
| 144 | test "variadic functions" { | 145 | test "variadic functions" { |
| 145 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 146 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 148 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 147 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 149 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 148 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 150 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
test/behavior/vector.zig+1| ... | @@ -1282,6 +1282,7 @@ test "store to vector in slice" { | ... | @@ -1282,6 +1282,7 @@ test "store to vector in slice" { |
| 1282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1283 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1283 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1284 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1284 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1285 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 1285 | 1286 | ||
| 1286 | var v = [_]@Vector(3, f32){ | 1287 | var v = [_]@Vector(3, f32){ |
| 1287 | .{ 1, 1, 1 }, | 1288 | .{ 1, 1, 1 }, |