From 4ddedb388560afe2458fff6e1cca26ba6e70add2 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 14 Oct 2022 20:25:09 +0700 Subject: stage2: sparc64: Implement get/setUnionTag --- src/arch/sparc64/CodeGen.zig | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index cb5df697f5..af6cb8b466 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -601,8 +601,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .atomic_load => @panic("TODO try self.airAtomicLoad(inst)"), .memcpy => @panic("TODO try self.airMemcpy(inst)"), .memset => try self.airMemset(inst), - .set_union_tag => @panic("TODO try self.airSetUnionTag(inst)"), - .get_union_tag => @panic("TODO try self.airGetUnionTag(inst)"), + .set_union_tag => try self.airSetUnionTag(inst), + .get_union_tag => try self.airGetUnionTag(inst), .clz => try self.airClz(inst), .ctz => try self.airCtz(inst), .popcount => try self.airPopcount(inst), @@ -1556,6 +1556,12 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airGetUnionTag for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; if (self.liveness.isUnused(inst)) @@ -2071,6 +2077,12 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); } +fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + _ = bin_op; + return self.fail("TODO implement airSetUnionTag for {}", .{self.target.cpu.arch}); +} + fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch}); -- cgit v1.2.3 From 0bc936685bbba38759b8029bada3c21b0ae2c353 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 14 Oct 2022 22:14:43 +0700 Subject: stage2: sparc64: Implement airErrorName --- src/arch/sparc64/CodeGen.zig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index af6cb8b466..bec70fb7d8 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -609,7 +609,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .byte_swap => @panic("TODO try self.airByteSwap(inst)"), .bit_reverse => @panic("TODO try self.airBitReverse(inst)"), .tag_name => try self.airTagName(inst), - .error_name => @panic("TODO try self.airErrorName(inst)"), + .error_name => try self.airErrorName(inst), .splat => @panic("TODO try self.airSplat(inst)"), .select => @panic("TODO try self.airSelect(inst)"), .shuffle => @panic("TODO try self.airShuffle(inst)"), @@ -1519,6 +1519,16 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); } +fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { + const un_op = self.air.instructions.items(.data)[inst].un_op; + const operand = try self.resolveInst(un_op); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else { + _ = operand; + return self.fail("TODO implement airErrorName for {}", .{self.target.cpu.arch}); + }; + return self.finishAir(inst, result, .{ un_op, .none, .none }); +} + fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); -- cgit v1.2.3 From 4687bc2730c36e46b0edbc36ce18576fb8f3e1f4 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 14 Oct 2022 22:26:48 +0700 Subject: stage2: sparc64: Implement airUnionInit --- src/arch/sparc64/CodeGen.zig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index bec70fb7d8..8dfa30750b 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -615,7 +615,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .shuffle => @panic("TODO try self.airShuffle(inst)"), .reduce => @panic("TODO try self.airReduce(inst)"), .aggregate_init => try self.airAggregateInit(inst), - .union_init => @panic("TODO try self.airUnionInit(inst)"), + .union_init => try self.airUnionInit(inst), .prefetch => try self.airPrefetch(inst), .mul_add => @panic("TODO try self.airMulAdd(inst)"), .addrspace_cast => @panic("TODO try self.airAddrSpaceCast(int)"), @@ -2427,6 +2427,13 @@ fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; + _ = extra; + return self.fail("TODO implement airUnionInit for {}", .{self.target.cpu.arch}); +} + fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { -- cgit v1.2.3 From ef532ada8ada987a5b66db630b374520d04553d8 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 14 Oct 2022 22:28:03 +0700 Subject: stage2: sparc64: Implement airSplat --- src/arch/sparc64/CodeGen.zig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 8dfa30750b..2e8b186909 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -610,7 +610,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .bit_reverse => @panic("TODO try self.airBitReverse(inst)"), .tag_name => try self.airTagName(inst), .error_name => try self.airErrorName(inst), - .splat => @panic("TODO try self.airSplat(inst)"), + .splat => try self.airSplat(inst), .select => @panic("TODO try self.airSelect(inst)"), .shuffle => @panic("TODO try self.airShuffle(inst)"), .reduce => @panic("TODO try self.airReduce(inst)"), @@ -2292,6 +2292,12 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airSplat(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSplat for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airStore(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const ptr = try self.resolveInst(bin_op.lhs); -- cgit v1.2.3 From 57616debf9708e61decba96134f89d2305da055b Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Dec 2022 20:44:13 +0700 Subject: stage2: sparc64: Implement airTrunc --- src/arch/sparc64/CodeGen.zig | 62 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 2e8b186909..575622ea4c 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -573,7 +573,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .fptrunc => @panic("TODO try self.airFptrunc(inst)"), .fpext => @panic("TODO try self.airFpext(inst)"), .intcast => try self.airIntCast(inst), - .trunc => @panic("TODO try self.airTrunc(inst)"), + .trunc => try self.airTrunc(inst), .bool_to_int => try self.airBoolToInt(inst), .is_non_null => try self.airIsNonNull(inst), .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"), @@ -2406,6 +2406,19 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); + const dest_ty = self.air.typeOfIndex(inst); + + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { + break :blk try self.trunc(inst, operand, operand_ty, dest_ty); + }; + + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airTry(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const extra = self.air.extraData(Air.Try, pl_op.payload); @@ -4369,6 +4382,53 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde }; } +fn trunc( + self: *Self, + maybe_inst: ?Air.Inst.Index, + operand: MCValue, + operand_ty: Type, + dest_ty: Type, +) !MCValue { + const info_a = operand_ty.intInfo(self.target.*); + const info_b = dest_ty.intInfo(self.target.*); + + if (info_b.bits <= 64) { + const operand_reg = switch (operand) { + .register => |r| r, + else => operand_reg: { + if (info_a.bits <= 64) { + const reg = try self.copyToTmpRegister(operand_ty, operand); + break :operand_reg reg; + } else { + return self.fail("TODO load least significant word into register", .{}); + } + }, + }; + const lock = self.register_manager.lockReg(operand_reg); + defer if (lock) |reg| self.register_manager.unlockReg(reg); + + const dest_reg = if (maybe_inst) |inst| blk: { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + + if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :blk operand_reg; + } else { + const reg = try self.register_manager.allocReg(inst, gp); + break :blk reg; + } + } else blk: { + const reg = try self.register_manager.allocReg(null, gp); + break :blk reg; + }; + + try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits); + + return MCValue{ .register = dest_reg }; + } else { + return self.fail("TODO: truncate to ints > 64 bits", .{}); + } +} + fn truncRegister( self: *Self, operand_reg: Register, -- cgit v1.2.3 From 1b5b9eb365dc5f5d5f9387ab25e128fb507f91f3 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 16 Oct 2022 10:55:47 +0700 Subject: stage2: sparc64: Add extra note about stack_offset MCV --- src/arch/sparc64/CodeGen.zig | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 575622ea4c..80fbf75ce2 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -144,6 +144,7 @@ const MCValue = union(enum) { memory: u64, /// The value is one of the stack variables. /// If the type is a pointer, it means the pointer address is in the stack at this offset. + /// Note that this stores the plain value (i.e without the effects of the stack bias). stack_offset: u32, /// The value is a pointer to one of the stack variables (payload is stack offset). ptr_stack_offset: u32, -- cgit v1.2.3 From a72362f3953d38a108ba1c4dc265e22fb11cf8f6 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 27 Oct 2022 20:03:26 +0700 Subject: stage2: sparc64: Implement airWrapErrUnionPayload --- src/arch/sparc64/CodeGen.zig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 80fbf75ce2..470a5226bf 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -683,7 +683,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .save_err_return_trace_index=> @panic("TODO try self.airSaveErrReturnTraceIndex(inst)"), .wrap_optional => try self.airWrapOptional(inst), - .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), + .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), .add_optimized, @@ -2493,6 +2493,13 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +/// T to E!T +fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { -- cgit v1.2.3 From 219b5f0ad6eada2174c20147a34b51986c8f44d5 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Dec 2022 20:55:57 +0700 Subject: stage2: sparc64: Implement stack argument --- src/arch/sparc64/CodeGen.zig | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 470a5226bf..347c86dbb7 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -992,12 +992,21 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { self.arg_index += 1; const ty = self.air.typeOfIndex(inst); - _ = ty; - const result = self.args[arg_index]; - // TODO support stack-only arguments - // TODO Copy registers to the stack - const mcv = result; + const arg = self.args[arg_index]; + const mcv = blk: { + switch (arg) { + .stack_offset => |off| { + const mod = self.bin_file.options.module.?; + const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { + return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); + }; + const offset = off + abi_size; + break :blk MCValue{ .stack_offset = offset }; + }, + else => break :blk arg, + } + }; try self.genArgDbgInfo(inst, mcv, @intCast(u32, arg_index)); @@ -4182,7 +4191,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { const ref_int = @enumToInt(inst); if (ref_int < Air.Inst.Ref.typed_value_map.len) { const tv = Air.Inst.Ref.typed_value_map[ref_int]; - if (!tv.ty.hasRuntimeBits() and !tv.ty.isError()) { + if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { return MCValue{ .none = {} }; } return self.genTypedValue(tv); @@ -4190,7 +4199,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { // If the type has no codegen bits, no need to store it. const inst_ty = self.air.typeOf(inst); - if (!inst_ty.hasRuntimeBits() and !inst_ty.isError()) + if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) return MCValue{ .none = {} }; const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); -- cgit v1.2.3 From fb9357f06c39622534e5a85fa3f1442deec84dc3 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sun, 13 Nov 2022 14:35:55 +0700 Subject: stage2: sparc64: Implement atomic ops --- src/arch/sparc64/CodeGen.zig | 77 ++++++++++++++++++++++++++++++++++++++++---- test/behavior/bugs/13159.zig | 1 + test/behavior/type.zig | 1 + 3 files changed, 72 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 347c86dbb7..692192b465 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -596,10 +596,11 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .array_to_slice => try self.airArrayToSlice(inst), .int_to_float => try self.airIntToFloat(inst), .float_to_int => try self.airFloatToInt(inst), - .cmpxchg_strong => @panic("TODO try self.airCmpxchg(inst)"), - .cmpxchg_weak => @panic("TODO try self.airCmpxchg(inst)"), - .atomic_rmw => @panic("TODO try self.airAtomicRmw(inst)"), - .atomic_load => @panic("TODO try self.airAtomicLoad(inst)"), + .cmpxchg_strong, + .cmpxchg_weak, + => try self.airCmpxchg(inst), + .atomic_rmw => try self.airAtomicRmw(inst), + .atomic_load => try self.airAtomicLoad(inst), .memcpy => @panic("TODO try self.airMemcpy(inst)"), .memset => try self.airMemset(inst), .set_union_tag => try self.airSetUnionTag(inst), @@ -1023,6 +1024,22 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, mcv, .{ .none, .none, .none }); } +fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { + _ = self.air.instructions.items(.data)[inst].atomic_load; + + return self.fail("TODO implement airAtomicLoad for {}", .{ + self.target.cpu.arch, + }); +} + +fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { + _ = self.air.instructions.items(.data)[inst].pl_op; + + return self.fail("TODO implement airAtomicRmw for {}", .{ + self.target.cpu.arch, + }); +} + fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const lhs = try self.resolveInst(bin_op.lhs); @@ -1332,6 +1349,16 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ un_op, .none, .none }); } +fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.Block, ty_pl.payload); + _ = extra; + + return self.fail("TODO implement airCmpxchg for {}", .{ + self.target.cpu.arch, + }); +} + fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const condition = try self.resolveInst(pl_op.operand); @@ -1416,6 +1443,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { const else_value = else_values[else_idx]; const canon_mcv = if (saved_then_branch.inst_table.fetchSwapRemove(else_key)) |then_entry| blk: { // The instruction's MCValue is overridden in both branches. + log.debug("condBr put branch table (key = %{d}, value = {})", .{ else_key, then_entry.value }); parent_branch.inst_table.putAssumeCapacity(else_key, then_entry.value); if (else_value == .dead) { assert(then_entry.value == .dead); @@ -2908,7 +2936,18 @@ fn binOpImmediate( const reg = try self.register_manager.allocReg(track_inst, gp); - if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); + if (track_inst) |inst| { + const mcv = .{ .register = reg }; + log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv }); + branch.inst_table.putAssumeCapacity(inst, mcv); + + // If we're moving a condition flag MCV to register, + // mark it as free. + if (lhs == .condition_flags) { + assert(self.condition_flags_inst.? == inst); + self.condition_flags_inst = null; + } + } break :blk reg; }; @@ -3035,7 +3074,18 @@ fn binOpRegister( } else null; const reg = try self.register_manager.allocReg(track_inst, gp); - if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); + if (track_inst) |inst| { + const mcv = .{ .register = reg }; + log.debug("binOpRegister move lhs %{d} to register: {} -> {}", .{ inst, lhs, mcv }); + branch.inst_table.putAssumeCapacity(inst, mcv); + + // If we're moving a condition flag MCV to register, + // mark it as free. + if (lhs == .condition_flags) { + assert(self.condition_flags_inst.? == inst); + self.condition_flags_inst = null; + } + } break :blk reg; }; @@ -3048,7 +3098,18 @@ fn binOpRegister( } else null; const reg = try self.register_manager.allocReg(track_inst, gp); - if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg }); + if (track_inst) |inst| { + const mcv = .{ .register = reg }; + log.debug("binOpRegister move rhs %{d} to register: {} -> {}", .{ inst, rhs, mcv }); + branch.inst_table.putAssumeCapacity(inst, mcv); + + // If we're moving a condition flag MCV to register, + // mark it as free. + if (rhs == .condition_flags) { + assert(self.condition_flags_inst.? == inst); + self.condition_flags_inst = null; + } + } break :blk reg; }; @@ -3867,6 +3928,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { while (true) { i -= 1; if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| { + log.debug("getResolvedInstValue %{} => {}", .{ inst, mcv }); assert(mcv != .dead); return mcv; } @@ -4082,6 +4144,7 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { const prev_value = self.getResolvedInstValue(inst); const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; branch.inst_table.putAssumeCapacity(inst, .dead); + log.debug("%{} death: {} -> .dead", .{ inst, prev_value }); switch (prev_value) { .register => |reg| { self.register_manager.freeReg(reg); diff --git a/test/behavior/bugs/13159.zig b/test/behavior/bugs/13159.zig index 6119c498a9..71418f4907 100644 --- a/test/behavior/bugs/13159.zig +++ b/test/behavior/bugs/13159.zig @@ -9,6 +9,7 @@ const Bar = packed struct { }; test { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var foo = Bar.Baz.fizz; try expect(foo == .fizz); } diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 48c1e90812..ea135efc2e 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -261,6 +261,7 @@ test "Type.Struct" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const A = @Type(@typeInfo(struct { x: u8, y: u32 })); const infoA = @typeInfo(A).Struct; -- cgit v1.2.3 From e9204f84ad7a6e319139562b7cdc4a95a38edfa0 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Tue, 15 Nov 2022 21:56:17 +0700 Subject: stage2: sparc64: Log generated function name for debug purposes --- src/arch/sparc64/CodeGen.zig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 692192b465..d5ddc2fd1c 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -275,6 +275,8 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; + log.debug("fn {s}", .{fn_owner_decl.name}); + var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); defer { assert(branch_stack.items.len == 1); -- cgit v1.2.3 From a369e8af9ed9e385b6125085073a50fbce109817 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Dec 2022 20:57:42 +0700 Subject: stage2: sparc64: Add more types for genTypedValue --- src/arch/sparc64/CodeGen.zig | 101 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index d5ddc2fd1c..11885d9fe7 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -3862,27 +3862,48 @@ fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_t } fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { - if (typed_value.val.isUndef()) + var tv = typed_value; + log.debug("genTypedValue: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); + + if (tv.val.castTag(.runtime_value)) |rt| { + tv.val = rt.data; + } + + if (tv.val.isUndef()) return MCValue{ .undef = {} }; - if (typed_value.val.castTag(.decl_ref)) |payload| { - return self.lowerDeclRef(typed_value, payload.data); + if (tv.val.castTag(.decl_ref)) |payload| { + return self.lowerDeclRef(tv, payload.data); } - if (typed_value.val.castTag(.decl_ref_mut)) |payload| { - return self.lowerDeclRef(typed_value, payload.data.decl_index); + if (tv.val.castTag(.decl_ref_mut)) |payload| { + return self.lowerDeclRef(tv, payload.data.decl_index); } const target = self.target.*; - switch (typed_value.ty.zigTypeTag()) { + switch (tv.ty.zigTypeTag()) { + .Pointer => switch (tv.ty.ptrSize()) { + .Slice => {}, + else => { + switch (tv.val.tag()) { + .int_u64 => { + return MCValue{ .immediate = tv.val.toUnsignedInt(target) }; + }, + else => {}, + } + }, + }, + .Bool => { + return MCValue{ .immediate = @boolToInt(tv.val.toBool()) }; + }, .Int => { - const info = typed_value.ty.intInfo(self.target.*); + const info = tv.ty.intInfo(self.target.*); if (info.bits <= 64) { const unsigned = switch (info.signedness) { .signed => blk: { - const signed = typed_value.val.toSignedInt(target); + const signed = tv.val.toSignedInt(target); break :blk @bitCast(u64, signed); }, - .unsigned => typed_value.val.toUnsignedInt(target), + .unsigned => tv.val.toUnsignedInt(target), }; return MCValue{ .immediate = unsigned }; @@ -3890,38 +3911,84 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { return self.fail("TODO implement int genTypedValue of > 64 bits", .{}); } }, + .Optional => { + if (tv.ty.isPtrLikeOptional()) { + if (tv.val.isNull()) + return MCValue{ .immediate = 0 }; + + var buf: Type.Payload.ElemType = undefined; + return self.genTypedValue(.{ + .ty = tv.ty.optionalChild(&buf), + .val = tv.val, + }); + } else if (tv.ty.abiSize(self.target.*) == 1) { + return MCValue{ .immediate = @boolToInt(tv.val.isNull()) }; + } + }, + .Enum => { + if (tv.val.castTag(.enum_field_index)) |field_index| { + switch (tv.ty.tag()) { + .enum_simple => { + return MCValue{ .immediate = field_index.data }; + }, + .enum_full, .enum_nonexhaustive => { + const enum_full = tv.ty.cast(Type.Payload.EnumFull).?.data; + if (enum_full.values.count() != 0) { + const tag_val = enum_full.values.keys()[field_index.data]; + return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); + } else { + return MCValue{ .immediate = field_index.data }; + } + }, + else => unreachable, + } + } else { + var int_tag_buffer: Type.Payload.Bits = undefined; + const int_tag_ty = tv.ty.intTagType(&int_tag_buffer); + return self.genTypedValue(.{ .ty = int_tag_ty, .val = tv.val }); + } + }, .ErrorSet => { - const err_name = typed_value.val.castTag(.@"error").?.data.name; + const err_name = tv.val.castTag(.@"error").?.data.name; const module = self.bin_file.options.module.?; const global_error_set = module.global_error_set; const error_index = global_error_set.get(err_name).?; return MCValue{ .immediate = error_index }; }, .ErrorUnion => { - const error_type = typed_value.ty.errorUnionSet(); - const payload_type = typed_value.ty.errorUnionPayload(); + const error_type = tv.ty.errorUnionSet(); + const payload_type = tv.ty.errorUnionPayload(); - if (typed_value.val.castTag(.eu_payload)) |pl| { + if (tv.val.castTag(.eu_payload)) |pl| { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. return MCValue{ .immediate = 0 }; } _ = pl; - return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()}); + return self.fail("TODO implement error union const of type '{}' (non-error)", .{tv.ty.fmtDebug()}); } else { if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. - return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); + return self.genTypedValue(.{ .ty = error_type, .val = tv.val }); } - return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()}); + return self.fail("TODO implement error union const of type '{}' (error)", .{tv.ty.fmtDebug()}); } }, .ComptimeInt => unreachable, // semantic analysis prevents this .ComptimeFloat => unreachable, // semantic analysis prevents this - else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty.fmtDebug()}), + .Type => unreachable, + .EnumLiteral => unreachable, + .Void => unreachable, + .NoReturn => unreachable, + .Undefined => unreachable, + .Null => unreachable, + .Opaque => unreachable, + else => {}, } + + return self.fail("TODO implement const of type '{}'", .{tv.ty.fmtDebug()}); } fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { -- cgit v1.2.3 From b4b7a404cfa0cfdc212fa66351789a199acb6e0c Mon Sep 17 00:00:00 2001 From: Koakuma Date: Sat, 10 Dec 2022 20:58:22 +0700 Subject: stage2: sparc64: Implement airBitReverse --- src/arch/sparc64/CodeGen.zig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 11885d9fe7..00e08a0964 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -611,7 +611,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .ctz => try self.airCtz(inst), .popcount => try self.airPopcount(inst), .byte_swap => @panic("TODO try self.airByteSwap(inst)"), - .bit_reverse => @panic("TODO try self.airBitReverse(inst)"), + .bit_reverse => try self.airBitReverse(inst), .tag_name => try self.airTagName(inst), .error_name => try self.airErrorName(inst), .splat => try self.airSplat(inst), @@ -1090,6 +1090,12 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airBitReverse for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airBlock(self: *Self, inst: Air.Inst.Index) !void { try self.blocks.putNoClobber(self.gpa, inst, .{ // A block is a setup to be able to jump to the end. -- cgit v1.2.3 From 644593ab18a2150a5b412d586fde2fcfbb1461ea Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 24 Nov 2022 19:35:28 +0700 Subject: stage2: sparc64: Implement airMinMax --- src/arch/sparc64/CodeGen.zig | 96 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 00e08a0964..604fd3e69f 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -521,8 +521,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .sub_sat => try self.airSubSat(inst), .mul_sat => try self.airMulSat(inst), .shl_sat => try self.airShlSat(inst), - .min => @panic("TODO try self.airMin(inst)"), - .max => @panic("TODO try self.airMax(inst)"), + .min, .max => try self.airMinMax(inst), .rem => try self.airRem(inst), .mod => try self.airMod(inst), .slice => try self.airSlice(inst), @@ -1737,6 +1736,22 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch}); } +fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { + const tag = self.air.instructions.items(.tag)[inst]; + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.air.typeOf(bin_op.lhs); + const rhs_ty = self.air.typeOf(bin_op.rhs); + + const result: MCValue = if (self.liveness.isUnused(inst)) + .dead + else + try self.minMax(tag, lhs, rhs, lhs_ty, rhs_ty); + + return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); +} + fn airMod(self: *Self, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const lhs = try self.resolveInst(bin_op.lhs); @@ -4195,6 +4210,83 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne } } +fn minMax( + self: *Self, + tag: Air.Inst.Tag, + lhs: MCValue, + rhs: MCValue, + lhs_ty: Type, + rhs_ty: Type, +) InnerError!MCValue { + const mod = self.bin_file.options.module.?; + assert(lhs_ty.eql(rhs_ty, mod)); + switch (lhs_ty.zigTypeTag()) { + .Float => return self.fail("TODO min/max on floats", .{}), + .Vector => return self.fail("TODO min/max on vectors", .{}), + .Int => { + const int_info = lhs_ty.intInfo(self.target.*); + if (int_info.bits <= 64) { + // TODO skip register setting when one of the operands + // is a small (fits in i13) immediate. + const rhs_is_register = rhs == .register; + const rhs_reg = if (rhs_is_register) + rhs.register + else + try self.register_manager.allocReg(null, gp); + const rhs_lock = self.register_manager.lockReg(rhs_reg); + defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); + if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); + + const result_reg = try self.register_manager.allocReg(null, gp); + const result_lock = self.register_manager.lockReg(result_reg); + defer if (result_lock) |reg| self.register_manager.unlockReg(reg); + try self.genSetReg(lhs_ty, result_reg, lhs); + + const cond_choose_rhs: Instruction.ICondition = switch (tag) { + .max => switch (int_info.signedness) { + .signed => Instruction.ICondition.gt, + .unsigned => Instruction.ICondition.gu, + }, + .min => switch (int_info.signedness) { + .signed => Instruction.ICondition.lt, + .unsigned => Instruction.ICondition.cs, + }, + else => unreachable, + }; + + _ = try self.addInst(.{ + .tag = .cmp, + .data = .{ + .arithmetic_2op = .{ + .is_imm = false, + .rs1 = result_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + _ = try self.addInst(.{ + .tag = .movcc, + .data = .{ + .conditional_move_int = .{ + .is_imm = false, + .ccr = .xcc, + .cond = .{ .icond = cond_choose_rhs }, + .rd = result_reg, + .rs2_or_imm = .{ .rs2 = rhs_reg }, + }, + }, + }); + + return MCValue{ .register = result_reg }; + } else { + return self.fail("TODO min/max on integers > u64/i64", .{}); + } + }, + else => unreachable, + } +} + fn parseRegName(name: []const u8) ?Register { if (@hasDecl(Register, "parseRegName")) { return Register.parseRegName(name); -- cgit v1.2.3