diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b8d832c5cf..28c7cdc5ce 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1150,17 +1150,10 @@ fn airOptionalPayload(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: { const operand = try self.resolveInst(ty_op.operand); - const dst_mcv: MCValue = blk: { - if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { - break :blk operand; - } else { - break :blk try self.allocRegOrMem(inst, true); - } - }; - const ty = self.air.typeOf(ty_op.operand); - var buf: Type.Payload.ElemType = undefined; - try self.load(dst_mcv, operand, ty.optionalChild(&buf)); - break :result dst_mcv; + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :result operand; + } + break :result try self.copyToNewRegister(inst, operand); }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1253,19 +1246,31 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { /// E to E!T fn airWrapErrUnionErr(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 error for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const error_union_ty = self.air.getRefType(ty_op.ty); + const payload_ty = error_union_ty.errorUnionPayload(); + const mcv = try self.resolveInst(ty_op.operand); + if (!payload_ty.hasCodeGenBits()) break :result mcv; + + return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } fn airSlicePtr(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 slice_ptr for {}", .{self.target.cpu.arch}); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + const dst_mcv: MCValue = blk: { + switch (operand) { + .stack_offset => |off| { + break :blk MCValue{ .stack_offset = off + 8 }; + }, + else => return self.fail("TODO implement slice_ptr for {}", .{operand}), + } + }; + break :result dst_mcv; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -1273,9 +1278,13 @@ fn airSliceLen(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: { const operand = try self.resolveInst(ty_op.operand); - const dst_mcv: MCValue = switch (operand) { - .stack_offset => |off| MCValue{ .stack_offset = off + 8 }, - else => return self.fail("TODO implement slice_len for {}", .{operand}), + const dst_mcv: MCValue = blk: { + switch (operand) { + .stack_offset => |off| { + break :blk MCValue{ .stack_offset = off }; + }, + else => return self.fail("TODO implement slice_len for {}", .{operand}), + } }; break :result dst_mcv; }; @@ -1313,37 +1322,38 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { var buf: Type.SlicePtrFieldTypeBuffer = undefined; const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); - const index_ty = self.air.typeOf(bin_op.rhs); - const index_mcv: MCValue = blk: { - switch (try self.resolveInst(bin_op.rhs)) { - .register => |reg| { - if (reg.to64() != .rcx) { - try self.register_manager.getReg(.rcx, inst); - } - break :blk MCValue{ .register = .rcx }; - }, - else => return self.fail("TODO move index mcv into a register", .{}), - } + const offset_reg = blk: { + const index_ty = self.air.typeOf(bin_op.rhs); + const index_mcv = try self.resolveInst(bin_op.rhs); + const offset_reg = try self.register_manager.allocReg(null, &.{}); + try self.genSetReg(index_ty, offset_reg, index_mcv); + try self.genIMulOpMir(index_ty, .{ .register = offset_reg }, .{ .immediate = elem_size }); + break :blk offset_reg; }; - try self.genIMulOpMir(index_ty, index_mcv, .{ .immediate = elem_size }); - const dst_mcv = blk: { switch (slice_mcv) { - .stack_offset => |unadjusted_off| { + .stack_offset => |off| { const dst_mcv = try self.allocRegOrMem(inst, false); - const addr_reg = try self.register_manager.allocReg(null, &.{index_mcv.register}); - const slice_ptr_abi_size = @intCast(u32, slice_ptr_field_type.abiSize(self.target.*)); - const off = unadjusted_off + elem_size; - // lea reg, [rbp - 8 + rcx*1] + const addr_reg = try self.register_manager.allocReg(null, &.{offset_reg}); + // mov reg, [rbp - 8] _ = try self.addInst(.{ - .tag = .lea, + .tag = .mov, .ops = (Mir.Ops{ - .reg1 = registerAlias(addr_reg, slice_ptr_abi_size), + .reg1 = addr_reg.to64(), .reg2 = .rbp, - .flags = 0b11, + .flags = 0b01, }).encode(), - .data = .{ .imm = -@intCast(i32, off) }, + .data = .{ .imm = -@intCast(i32, off + 16) }, + }); + // add addr, offset + _ = try self.addInst(.{ + .tag = .add, + .ops = (Mir.Ops{ + .reg1 = addr_reg.to64(), + .reg2 = offset_reg.to64(), + }).encode(), + .data = undefined, }); try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); break :blk dst_mcv; @@ -1471,6 +1481,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { const elem_ty = ptr_ty.elemType(); + const abi_size = elem_ty.abiSize(self.target.*); switch (ptr) { .none => unreachable, .undef => unreachable, @@ -1478,7 +1489,9 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo .dead => unreachable, .compare_flags_unsigned => unreachable, .compare_flags_signed => unreachable, - .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), + .immediate => |imm| { + try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }); + }, .ptr_stack_offset => |off| { try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); }, @@ -1488,7 +1501,66 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo .embedded_in_code => { return self.fail("TODO implement loading from MCValue.embedded_in_code", .{}); }, - .register => |reg| try self.setRegOrMem(ptr_ty, dst_mcv, .{ .register = reg }), + .register => |reg| { + switch (dst_mcv) { + .dead => unreachable, + .undef => unreachable, + .compare_flags_unsigned => unreachable, + .compare_flags_signed => unreachable, + .embedded_in_code => unreachable, + .register => |dst_reg| { + // mov dst_reg, [reg] + _ = try self.addInst(.{ + .tag = .mov, + .ops = (Mir.Ops{ + .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)), + .reg2 = reg, + .flags = 0b01, + }).encode(), + .data = .{ .imm = 0 }, + }); + }, + .stack_offset => |off| { + if (abi_size <= 8) { + const tmp_reg = try self.register_manager.allocReg(null, &.{reg}); + try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); + return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }); + } + + const regs = try self.register_manager.allocRegs( + 3, + .{ null, null, null }, + &.{ reg, .rax, .rcx }, + ); + const addr_reg = regs[0]; + const count_reg = regs[1]; + const tmp_reg = regs[2]; + + _ = try self.addInst(.{ + .tag = .mov, + .ops = (Mir.Ops{ + .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)), + .reg2 = reg, + }).encode(), + .data = undefined, + }); + + try self.register_manager.getReg(.rax, null); + try self.register_manager.getReg(.rcx, null); + + // TODO allow for abi size to be u64 + try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); + + return self.genInlineMemcpy( + -@intCast(i32, off + abi_size), + registerAlias(addr_reg, @divExact(reg.size(), 8)), + count_reg.to64(), + tmp_reg.to8(), + ); + }, + else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), + } + }, .memory => |addr| { const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr }); try self.load(dst_mcv, .{ .register = reg }, ptr_ty); @@ -1525,11 +1597,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { 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); - const value = try self.resolveInst(bin_op.rhs); - const elem_ty = self.air.typeOf(bin_op.rhs); +fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { + _ = ptr_ty; switch (ptr) { .none => unreachable, .undef => unreachable, @@ -1538,19 +1607,58 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { .compare_flags_unsigned => unreachable, .compare_flags_signed => unreachable, .immediate => |imm| { - try self.setRegOrMem(elem_ty, .{ .memory = imm }, value); + try self.setRegOrMem(value_ty, .{ .memory = imm }, value); }, .ptr_stack_offset => |off| { - try self.genSetStack(elem_ty, off, value); + try self.genSetStack(value_ty, off, value); }, .ptr_embedded_in_code => |off| { - try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value); + try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value); }, .embedded_in_code => { return self.fail("TODO implement storing to MCValue.embedded_in_code", .{}); }, .register => |reg| { - try self.genSetPtrReg(elem_ty, reg, value); + switch (value) { + .none => unreachable, + .undef => unreachable, + .dead => unreachable, + .unreach => unreachable, + .compare_flags_unsigned => unreachable, + .compare_flags_signed => unreachable, + .immediate => |imm| { + const abi_size = value_ty.abiSize(self.target.*); + switch (abi_size) { + 1, 2, 4 => { + // TODO this is wasteful! + // introduce new MIR tag specifically for mov [reg + 0], imm + const payload = try self.addExtra(Mir.ImmPair{ + .dest_off = 0, + .operand = @bitCast(i32, @intCast(u32, imm)), + }); + _ = try self.addInst(.{ + .tag = .mov_mem_imm, + .ops = (Mir.Ops{ + .reg1 = reg.to64(), + .flags = switch (abi_size) { + 1 => 0b00, + 2 => 0b01, + 4 => 0b10, + else => unreachable, + }, + }).encode(), + .data = .{ .payload = payload }, + }); + }, + else => { + return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size}); + }, + } + }, + else => |other| { + return self.fail("TODO implement set pointee with {}", .{other}); + }, + } }, .memory => { return self.fail("TODO implement storing to MCValue.memory", .{}); @@ -1559,6 +1667,15 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { return self.fail("TODO implement storing to MCValue.stack_offset", .{}); }, } +} + +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); + const ptr_ty = self.air.typeOf(bin_op.lhs); + const value = try self.resolveInst(bin_op.rhs); + const value_ty = self.air.typeOf(bin_op.rhs); + try self.store(ptr, value, ptr_ty, value_ty); return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -1586,9 +1703,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde switch (mcv) { .ptr_stack_offset => |off| { - break :result MCValue{ - .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size, - }; + const ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size; + break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; }, else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), } @@ -1610,9 +1726,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { switch (mcv) { .stack_offset => |off| { - break :result MCValue{ - .stack_offset = off + struct_size - struct_field_offset - struct_field_size, - }; + const stack_offset = off + struct_size - struct_field_offset - struct_field_size; + break :result MCValue{ .stack_offset = stack_offset }; }, else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), } @@ -1785,6 +1900,15 @@ fn genBinMathOpMir( } }, .stack_offset => |off| { + if (off > math.maxInt(i32)) { + return self.fail("stack offset too large", .{}); + } + const abi_size = dst_ty.abiSize(self.target.*); + if (abi_size > 8) { + return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{}); + } + const adj_off = off + abi_size; + switch (src_mcv) { .none => unreachable, .undef => return self.genSetStack(dst_ty, off, .undef), @@ -1792,11 +1916,6 @@ fn genBinMathOpMir( .ptr_stack_offset => unreachable, .ptr_embedded_in_code => unreachable, .register => |src_reg| { - if (off > math.maxInt(i32)) { - return self.fail("stack offset too large", .{}); - } - const abi_size = dst_ty.abiSize(self.target.*); - const adj_off = off + abi_size; _ = try self.addInst(.{ .tag = mir_tag, .ops = (Mir.Ops{ @@ -1808,8 +1927,34 @@ fn genBinMathOpMir( }); }, .immediate => |imm| { - _ = imm; - return self.fail("TODO implement x86 ADD/SUB/CMP source immediate", .{}); + const tag: Mir.Inst.Tag = switch (mir_tag) { + .add => .add_mem_imm, + .@"or" => .or_mem_imm, + .@"and" => .and_mem_imm, + .sub => .sub_mem_imm, + .xor => .xor_mem_imm, + .cmp => .cmp_mem_imm, + else => unreachable, + }; + const flags: u2 = switch (abi_size) { + 1 => 0b00, + 2 => 0b01, + 4 => 0b10, + 8 => 0b11, + else => unreachable, + }; + const payload = try self.addExtra(Mir.ImmPair{ + .dest_off = -@intCast(i32, adj_off), + .operand = @bitCast(i32, @intCast(u32, imm)), + }); + _ = try self.addInst(.{ + .tag = tag, + .ops = (Mir.Ops{ + .reg1 = .rbp, + .flags = flags, + }).encode(), + .data = .{ .payload = payload }, + }); }, .embedded_in_code, .memory, .stack_offset => { return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); @@ -1859,7 +2004,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! .immediate => |imm| { // TODO take into account the type's ABI size when selecting the register alias // register, immediate - if (imm <= math.maxInt(i32)) { + if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) { _ = try self.addInst(.{ .tag = .imul_complex, .ops = (Mir.Ops{ @@ -2059,6 +2204,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { assert(ty.zigTypeTag() == .Pointer); const mcv = try self.resolveInst(callee); try self.genSetReg(Type.initTag(.usize), .rax, mcv); + _ = try self.addInst(.{ + .tag = .call, + .ops = (Mir.Ops{ + .reg1 = .rax, + .flags = 0b01, + }).encode(), + .data = undefined, + }); } } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { for (info.args) |mc_arg, arg_i| { @@ -2128,6 +2281,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { assert(ty.zigTypeTag() == .Pointer); const mcv = try self.resolveInst(callee); try self.genSetReg(Type.initTag(.usize), .rax, mcv); + _ = try self.addInst(.{ + .tag = .call, + .ops = (Mir.Ops{ + .reg1 = .rax, + .flags = 0b01, + }).encode(), + .data = undefined, + }); } } else if (self.bin_file.cast(link.File.Plan9)) |p9| { for (info.args) |mc_arg, arg_i| { @@ -2180,7 +2341,17 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { }); } else return self.fail("TODO implement calling extern fn on plan9", .{}); } else { - return self.fail("TODO implement calling runtime known function pointer", .{}); + assert(ty.zigTypeTag() == .Pointer); + const mcv = try self.resolveInst(callee); + try self.genSetReg(Type.initTag(.usize), .rax, mcv); + _ = try self.addInst(.{ + .tag = .call, + .ops = (Mir.Ops{ + .reg1 = .rax, + .flags = 0b01, + }).encode(), + .data = undefined, + }); } } else unreachable; @@ -3029,8 +3200,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro } return self.fail("TODO implement memcpy for setting stack from {}", .{mcv}); }, - .stack_offset => |unadjusted_off| { - if (stack_offset == unadjusted_off) { + .stack_offset => |off| { + if (stack_offset == off) { // Copy stack variable to itself; nothing to do. return; } @@ -3041,33 +3212,43 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); } - const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); + const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); const addr_reg = regs[0]; - const len_reg = regs[1]; + const count_reg = regs[1]; + const tmp_reg = regs[2]; + + try self.register_manager.getReg(.rax, null); + try self.register_manager.getReg(.rcx, null); - const off = unadjusted_off + abi_size; _ = try self.addInst(.{ .tag = .lea, .ops = (Mir.Ops{ .reg1 = addr_reg.to64(), .reg2 = .rbp, }).encode(), - .data = .{ .imm = -@intCast(i32, off) }, + .data = .{ .imm = -@intCast(i32, off + abi_size) }, }); // TODO allow for abi_size to be u64 - try self.genSetReg(Type.initTag(.u32), len_reg, .{ .immediate = @intCast(u32, abi_size) }); + try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); - return self.genInlineMemcpy(-@intCast(i32, off), addr_reg.to64(), len_reg.to64()); + return self.genInlineMemcpy( + -@intCast(i32, stack_offset + abi_size), + addr_reg.to64(), + count_reg.to64(), + tmp_reg.to8(), + ); }, } } -fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: Register) InnerError!void { - try self.register_manager.getReg(.rax, null); - try self.register_manager.getReg(.rcx, null); - const tmp_reg = try self.register_manager.allocReg(null, &.{ addr_reg, len_reg, .rax, .rcx }); - +fn genInlineMemcpy( + self: *Self, + stack_offset: i32, + addr_reg: Register, + count_reg: Register, + tmp_reg: Register, +) InnerError!void { // mov rcx, 0 _ = try self.addInst(.{ .tag = .mov, @@ -3087,20 +3268,19 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: }); // loop: - // cmp rcx, len + // cmp count, 0 const loop_start = try self.addInst(.{ .tag = .cmp, .ops = (Mir.Ops{ - .reg1 = .rcx, - .reg2 = len_reg, + .reg1 = count_reg, }).encode(), - .data = undefined, + .data = .{ .imm = 0 }, }); - // jge end + // je end const loop_reloc = try self.addInst(.{ - .tag = .cond_jmp_above_below, - .ops = (Mir.Ops{ .flags = 0b00 }).encode(), + .tag = .cond_jmp_eq_ne, + .ops = (Mir.Ops{ .flags = 0b01 }).encode(), .data = .{ .inst = undefined }, }); @@ -3142,6 +3322,15 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: .data = .{ .imm = 1 }, }); + // sub count, 1 + _ = try self.addInst(.{ + .tag = .sub, + .ops = (Mir.Ops{ + .reg1 = count_reg, + }).encode(), + .data = .{ .imm = 1 }, + }); + // jmp loop _ = try self.addInst(.{ .tag = .jmp, @@ -3153,47 +3342,6 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, addr_reg: Register, len_reg: try self.performReloc(loop_reloc); } -/// Set pointee via pointer stored in a register. -/// mov [reg], value -fn genSetPtrReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { - switch (mcv) { - .dead => unreachable, - .unreach, .none => return, // Nothing to do. - .immediate => |imm| { - const abi_size = ty.abiSize(self.target.*); - switch (abi_size) { - 1, 2, 4 => { - // TODO this is wasteful! - // introduce new MIR tag specifically for mov [reg + 0], imm - const payload = try self.addExtra(Mir.ImmPair{ - .dest_off = 0, - .operand = @bitCast(i32, @intCast(u32, imm)), - }); - _ = try self.addInst(.{ - .tag = .mov_mem_imm, - .ops = (Mir.Ops{ - .reg1 = reg.to64(), - .flags = switch (abi_size) { - 1 => 0b00, - 2 => 0b01, - 4 => 0b10, - else => unreachable, - }, - }).encode(), - .data = .{ .payload = payload }, - }); - }, - else => { - return self.fail("TODO implement set pointee with immediate of ABI size {d}", .{abi_size}); - }, - } - }, - else => |other| { - return self.fail("TODO implement set pointee with {}", .{other}); - }, - } -} - fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { switch (mcv) { .dead => unreachable, @@ -3616,7 +3764,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.tag() == .int_u64) { return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; } - return self.fail("TODO codegen more kinds of const pointers", .{}); + return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()}); }, }, .Int => { diff --git a/src/arch/x86_64/Isel.zig b/src/arch/x86_64/Isel.zig index e6d8278fdc..a446ca3e84 100644 --- a/src/arch/x86_64/Isel.zig +++ b/src/arch/x86_64/Isel.zig @@ -265,32 +265,43 @@ fn mirPushPopRegsFromCalleePreservedRegs(isel: *Isel, tag: Tag, inst: Mir.Inst.I fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void { const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); - const flag = @truncate(u1, ops.flags); - if (flag == 0) { - const target = isel.mir.instructions.items(.data)[inst].inst; - const source = isel.code.items.len; - lowerToDEnc(tag, 0, isel.code) catch |err| - return isel.failWithLoweringError(err); - try isel.relocs.append(isel.bin_file.allocator, .{ - .source = source, - .target = target, - .offset = isel.code.items.len - 4, - .length = 5, - }); - return; + switch (ops.flags) { + 0b00 => { + const target = isel.mir.instructions.items(.data)[inst].inst; + const source = isel.code.items.len; + lowerToDEnc(tag, 0, isel.code) catch |err| + return isel.failWithLoweringError(err); + try isel.relocs.append(isel.bin_file.allocator, .{ + .source = source, + .target = target, + .offset = isel.code.items.len - 4, + .length = 5, + }); + }, + 0b01 => { + if (ops.reg1 == .none) { + // JMP/CALL [imm] + const imm = isel.mir.instructions.items(.data)[inst].imm; + const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) { + 16 => .word_ptr, + else => .qword_ptr, + }; + return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err| + isel.failWithLoweringError(err); + } + // JMP/CALL reg + return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err); + }, + 0b10 => { + // JMP/CALL r/m64 + const imm = isel.mir.instructions.items(.data)[inst].imm; + return lowerToMEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ + .disp = imm, + .base = ops.reg1, + }), isel.code) catch |err| isel.failWithLoweringError(err); + }, + 0b11 => return isel.fail("TODO unused JMP/CALL variant 0b11", .{}), } - if (ops.reg1 == .none) { - // JMP/CALL [imm] - const imm = isel.mir.instructions.items(.data)[inst].imm; - const ptr_size: Memory.PtrSize = switch (immOpSize(imm)) { - 16 => .word_ptr, - else => .qword_ptr, - }; - return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err| - isel.failWithLoweringError(err); - } - // JMP/CALL reg - return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), isel.code) catch |err| isel.failWithLoweringError(err); } fn mirCondJmp(isel: *Isel, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { @@ -493,13 +504,14 @@ fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void const scale = ops.flags; const imm = isel.mir.instructions.items(.data)[inst].imm; // OP reg1, [reg2 + scale*rcx + imm32] + const scale_index = ScaleIndex{ + .scale = scale, + .index = .rcx, + }; return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ .disp = imm, .base = ops.reg2, - .scale_index = .{ - .scale = scale, - .index = .rcx, - }, + .scale_index = scale_index, }), isel.code) catch |err| isel.failWithLoweringError(err); } @@ -507,25 +519,23 @@ fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]); const scale = ops.flags; const imm = isel.mir.instructions.items(.data)[inst].imm; + const scale_index = ScaleIndex{ + .scale = scale, + .index = .rax, + }; if (ops.reg2 == .none) { // OP qword ptr [reg1 + scale*rax + 0], imm32 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = ops.reg1, - .scale_index = .{ - .scale = scale, - .index = .rax, - }, + .scale_index = scale_index, }), imm, isel.code) catch |err| isel.failWithLoweringError(err); } // OP [reg1 + scale*rax + imm32], reg2 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ .disp = imm, .base = ops.reg1, - .scale_index = .{ - .scale = scale, - .index = .rax, - }, + .scale_index = scale_index, }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err); } @@ -534,14 +544,15 @@ fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void const scale = ops.flags; const payload = isel.mir.instructions.items(.data)[inst].payload; const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data; + const scale_index = ScaleIndex{ + .scale = scale, + .index = .rax, + }; // OP qword ptr [reg1 + scale*rax + imm32], imm32 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{ .disp = imm_pair.dest_off, .base = ops.reg1, - .scale_index = .{ - .scale = scale, - .index = .rax, - }, + .scale_index = scale_index, }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err); } @@ -658,16 +669,17 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void { // lea reg, [rbp + rcx + imm32] const imm = isel.mir.instructions.items(.data)[inst].imm; const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2; + const scale_index = ScaleIndex{ + .scale = 0, + .index = .rcx, + }; return lowerToRmEnc( .lea, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ .disp = imm, .base = src_reg, - .scale_index = .{ - .scale = 0, - .index = .rcx, - }, + .scale_index = scale_index, }), isel.code, ) catch |err| isel.failWithLoweringError(err); @@ -1248,7 +1260,7 @@ const Memory = struct { const dst = base.lowId(); const src = operand; if (dst == 4 or mem_op.scale_index != null) { - if (mem_op.disp == 0) { + if (mem_op.disp == 0 and dst != 5) { encoder.modRm_SIBDisp0(src); if (mem_op.scale_index) |si| { encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst); @@ -1907,6 +1919,24 @@ test "lower RM encoding" { }, }), isel.code()); try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]"); + try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{ + .disp = -24, + .base = .rsi, + .scale_index = .{ + .scale = 0, + .index = .rcx, + }, + }), isel.code()); + try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", isel.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]"); + try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{ + .disp = 0, + .base = .rbp, + .scale_index = .{ + .scale = 0, + .index = .rcx, + }, + }), isel.code()); + try expectEqualHexStrings("\x48\x8D\x74\x0D\x00", isel.lowered(), "lea rsi, qword ptr [rbp + rcx*1 + 0]"); } test "lower MR encoding" { diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 828addabfa..c5f595a86e 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -199,12 +199,11 @@ pub const Inst = struct { /// TODO handle scaling movabs, - /// ops flags: 0bX0: - /// - Uses the `inst` Data tag as the jump target. - /// - reg1 and reg2 are ignored. - /// ops flags: 0bX1: - /// - reg1 is the jump target, reg2 and data are ignored. - /// - if reg1 is none, [imm] + /// ops flags: form: + /// 0b00 inst + /// 0b01 reg1 + /// 0b01 [imm32] if reg1 is none + /// 0b10 [reg1 + imm32] jmp, call, diff --git a/test/behavior.zig b/test/behavior.zig index b8b6acf146..0c4f2debb4 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -4,211 +4,207 @@ test { // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend. _ = @import("behavior/bugs/1111.zig"); _ = @import("behavior/bugs/2346.zig"); - _ = @import("behavior/bugs/3586.zig"); _ = @import("behavior/slice_sentinel_comptime.zig"); + _ = @import("behavior/bugs/679.zig"); + _ = @import("behavior/bugs/6850.zig"); + _ = @import("behavior/fn_in_struct_in_comptime.zig"); + _ = @import("behavior/hasfield.zig"); + _ = @import("behavior/hasdecl.zig"); + _ = @import("behavior/pub_enum.zig"); + _ = @import("behavior/type_info.zig"); + _ = @import("behavior/type.zig"); - if (builtin.zig_backend != .stage2_x86_64) { - // Tests that pass for stage1, llvm backend, C backend, wasm backend, and arm backend. - _ = @import("behavior/bugs/679.zig"); - _ = @import("behavior/bugs/6850.zig"); - _ = @import("behavior/fn_in_struct_in_comptime.zig"); - _ = @import("behavior/hasfield.zig"); - _ = @import("behavior/hasdecl.zig"); - _ = @import("behavior/pub_enum.zig"); - _ = @import("behavior/type_info.zig"); - _ = @import("behavior/type.zig"); + if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) { + // Tests that pass for stage1, llvm backend, C backend, wasm backend. + _ = @import("behavior/bugs/3586.zig"); + _ = @import("behavior/basic.zig"); + _ = @import("behavior/bitcast.zig"); + _ = @import("behavior/bool.zig"); + _ = @import("behavior/bugs/624.zig"); + _ = @import("behavior/bugs/655.zig"); + _ = @import("behavior/bugs/704.zig"); + _ = @import("behavior/bugs/1486.zig"); + _ = @import("behavior/bugs/2692.zig"); + _ = @import("behavior/bugs/2889.zig"); + _ = @import("behavior/bugs/3046.zig"); + _ = @import("behavior/bugs/4769_a.zig"); + _ = @import("behavior/bugs/4769_b.zig"); + _ = @import("behavior/bugs/4954.zig"); + _ = @import("behavior/byval_arg_var.zig"); + _ = @import("behavior/call.zig"); + _ = @import("behavior/defer.zig"); + _ = @import("behavior/enum.zig"); + _ = @import("behavior/error.zig"); + _ = @import("behavior/generics.zig"); + _ = @import("behavior/if.zig"); + _ = @import("behavior/import.zig"); + _ = @import("behavior/incomplete_struct_param_tld.zig"); + _ = @import("behavior/inttoptr.zig"); + _ = @import("behavior/member_func.zig"); + _ = @import("behavior/null.zig"); + _ = @import("behavior/pointers.zig"); + _ = @import("behavior/ptrcast.zig"); + _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); + _ = @import("behavior/struct.zig"); + _ = @import("behavior/this.zig"); + _ = @import("behavior/truncate.zig"); + _ = @import("behavior/underscore.zig"); + _ = @import("behavior/usingnamespace.zig"); + _ = @import("behavior/void.zig"); + _ = @import("behavior/while.zig"); - if (builtin.zig_backend != .stage2_arm) { - // Tests that pass for stage1, llvm backend, C backend, wasm backend. - _ = @import("behavior/basic.zig"); - _ = @import("behavior/bitcast.zig"); - _ = @import("behavior/bool.zig"); - _ = @import("behavior/bugs/624.zig"); - _ = @import("behavior/bugs/655.zig"); - _ = @import("behavior/bugs/704.zig"); - _ = @import("behavior/bugs/1486.zig"); - _ = @import("behavior/bugs/2692.zig"); - _ = @import("behavior/bugs/2889.zig"); - _ = @import("behavior/bugs/3046.zig"); - _ = @import("behavior/bugs/4769_a.zig"); - _ = @import("behavior/bugs/4769_b.zig"); - _ = @import("behavior/bugs/4954.zig"); - _ = @import("behavior/byval_arg_var.zig"); - _ = @import("behavior/call.zig"); - _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); - _ = @import("behavior/error.zig"); - _ = @import("behavior/generics.zig"); - _ = @import("behavior/if.zig"); - _ = @import("behavior/import.zig"); - _ = @import("behavior/incomplete_struct_param_tld.zig"); - _ = @import("behavior/inttoptr.zig"); - _ = @import("behavior/member_func.zig"); - _ = @import("behavior/null.zig"); - _ = @import("behavior/pointers.zig"); - _ = @import("behavior/ptrcast.zig"); - _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); - _ = @import("behavior/struct.zig"); - _ = @import("behavior/this.zig"); - _ = @import("behavior/truncate.zig"); - _ = @import("behavior/underscore.zig"); - _ = @import("behavior/usingnamespace.zig"); - _ = @import("behavior/void.zig"); - _ = @import("behavior/while.zig"); + if (builtin.zig_backend != .stage2_wasm) { + // Tests that pass for stage1, llvm backend, C backend + _ = @import("behavior/align.zig"); + _ = @import("behavior/array.zig"); + _ = @import("behavior/bugs/4560.zig"); + _ = @import("behavior/cast.zig"); + _ = @import("behavior/for.zig"); + _ = @import("behavior/int128.zig"); + _ = @import("behavior/optional.zig"); + _ = @import("behavior/translate_c_macros.zig"); - if (builtin.zig_backend != .stage2_wasm) { - // Tests that pass for stage1, llvm backend, C backend - _ = @import("behavior/align.zig"); - _ = @import("behavior/array.zig"); - _ = @import("behavior/bugs/4560.zig"); - _ = @import("behavior/cast.zig"); - _ = @import("behavior/for.zig"); - _ = @import("behavior/int128.zig"); - _ = @import("behavior/optional.zig"); - _ = @import("behavior/translate_c_macros.zig"); + if (builtin.zig_backend != .stage2_c) { + // Tests that pass for stage1 and the llvm backend. + _ = @import("behavior/align_llvm.zig"); + _ = @import("behavior/alignof.zig"); + _ = @import("behavior/array_llvm.zig"); + _ = @import("behavior/atomics.zig"); + _ = @import("behavior/basic_llvm.zig"); + _ = @import("behavior/bugs/394.zig"); + _ = @import("behavior/bugs/656.zig"); + _ = @import("behavior/bugs/1277.zig"); + _ = @import("behavior/bugs/1310.zig"); + _ = @import("behavior/bugs/1381.zig"); + _ = @import("behavior/bugs/1500.zig"); + _ = @import("behavior/bugs/1741.zig"); + _ = @import("behavior/bugs/2006.zig"); + _ = @import("behavior/bugs/2578.zig"); + _ = @import("behavior/bugs/3007.zig"); + _ = @import("behavior/bugs/3112.zig"); + _ = @import("behavior/bugs/3367.zig"); + _ = @import("behavior/bugs/7250.zig"); + _ = @import("behavior/bugs/9584.zig"); + _ = @import("behavior/cast_llvm.zig"); + _ = @import("behavior/enum_llvm.zig"); + _ = @import("behavior/eval.zig"); + _ = @import("behavior/floatop.zig"); + _ = @import("behavior/fn.zig"); + _ = @import("behavior/generics_llvm.zig"); + _ = @import("behavior/math.zig"); + _ = @import("behavior/maximum_minimum.zig"); + _ = @import("behavior/namespace_depends_on_compile_var.zig"); + _ = @import("behavior/null_llvm.zig"); + _ = @import("behavior/optional_llvm.zig"); + _ = @import("behavior/popcount.zig"); + _ = @import("behavior/saturating_arithmetic.zig"); + _ = @import("behavior/sizeof_and_typeof.zig"); + _ = @import("behavior/slice.zig"); + _ = @import("behavior/struct_llvm.zig"); + _ = @import("behavior/switch.zig"); + _ = @import("behavior/undefined.zig"); + _ = @import("behavior/union.zig"); + _ = @import("behavior/widening.zig"); - if (builtin.zig_backend != .stage2_c) { - // Tests that pass for stage1 and the llvm backend. - _ = @import("behavior/align_llvm.zig"); - _ = @import("behavior/alignof.zig"); - _ = @import("behavior/array_llvm.zig"); - _ = @import("behavior/atomics.zig"); - _ = @import("behavior/basic_llvm.zig"); - _ = @import("behavior/bugs/394.zig"); - _ = @import("behavior/bugs/656.zig"); - _ = @import("behavior/bugs/1277.zig"); - _ = @import("behavior/bugs/1310.zig"); - _ = @import("behavior/bugs/1381.zig"); - _ = @import("behavior/bugs/1500.zig"); - _ = @import("behavior/bugs/1741.zig"); - _ = @import("behavior/bugs/2006.zig"); - _ = @import("behavior/bugs/2578.zig"); - _ = @import("behavior/bugs/3007.zig"); - _ = @import("behavior/bugs/3112.zig"); - _ = @import("behavior/bugs/3367.zig"); - _ = @import("behavior/bugs/7250.zig"); - _ = @import("behavior/bugs/9584.zig"); - _ = @import("behavior/cast_llvm.zig"); - _ = @import("behavior/enum_llvm.zig"); - _ = @import("behavior/eval.zig"); - _ = @import("behavior/floatop.zig"); - _ = @import("behavior/fn.zig"); - _ = @import("behavior/generics_llvm.zig"); - _ = @import("behavior/math.zig"); - _ = @import("behavior/maximum_minimum.zig"); - _ = @import("behavior/namespace_depends_on_compile_var.zig"); - _ = @import("behavior/null_llvm.zig"); - _ = @import("behavior/optional_llvm.zig"); - _ = @import("behavior/popcount.zig"); - _ = @import("behavior/saturating_arithmetic.zig"); - _ = @import("behavior/sizeof_and_typeof.zig"); - _ = @import("behavior/slice.zig"); - _ = @import("behavior/struct_llvm.zig"); - _ = @import("behavior/switch.zig"); - _ = @import("behavior/undefined.zig"); - _ = @import("behavior/union.zig"); - _ = @import("behavior/widening.zig"); - - if (builtin.zig_backend != .stage1) { - // When all comptime_memory.zig tests pass, #9646 can be closed. - // _ = @import("behavior/comptime_memory.zig"); - _ = @import("behavior/slice_stage2.zig"); - } else { - // Tests that only pass for the stage1 backend. - _ = @import("behavior/align_stage1.zig"); - _ = @import("behavior/array_stage1.zig"); - if (builtin.os.tag != .wasi) { - _ = @import("behavior/asm.zig"); - _ = @import("behavior/async_fn.zig"); - } - _ = @import("behavior/await_struct.zig"); - _ = @import("behavior/bit_shifting.zig"); - _ = @import("behavior/bitcast_stage1.zig"); - _ = @import("behavior/bitreverse.zig"); - _ = @import("behavior/bugs/421.zig"); - _ = @import("behavior/bugs/529.zig"); - _ = @import("behavior/bugs/718.zig"); - _ = @import("behavior/bugs/726.zig"); - _ = @import("behavior/bugs/828.zig"); - _ = @import("behavior/bugs/920.zig"); - _ = @import("behavior/bugs/1025.zig"); - _ = @import("behavior/bugs/1076.zig"); - _ = @import("behavior/bugs/1120.zig"); - _ = @import("behavior/bugs/1421.zig"); - _ = @import("behavior/bugs/1442.zig"); - _ = @import("behavior/bugs/1607.zig"); - _ = @import("behavior/bugs/1735.zig"); - _ = @import("behavior/bugs/1851.zig"); - _ = @import("behavior/bugs/1914.zig"); - _ = @import("behavior/bugs/2114.zig"); - _ = @import("behavior/bugs/3384.zig"); - _ = @import("behavior/bugs/3742.zig"); - _ = @import("behavior/bugs/3779.zig"); - _ = @import("behavior/bugs/4328.zig"); - _ = @import("behavior/bugs/5398.zig"); - _ = @import("behavior/bugs/5413.zig"); - _ = @import("behavior/bugs/5474.zig"); - _ = @import("behavior/bugs/5487.zig"); - _ = @import("behavior/bugs/6456.zig"); - _ = @import("behavior/bugs/6781.zig"); - _ = @import("behavior/bugs/7003.zig"); - _ = @import("behavior/bugs/7027.zig"); - _ = @import("behavior/bugs/7047.zig"); - _ = @import("behavior/bugs/10147.zig"); - _ = @import("behavior/byteswap.zig"); - _ = @import("behavior/call_stage1.zig"); - _ = @import("behavior/cast_stage1.zig"); - _ = @import("behavior/const_slice_child.zig"); - _ = @import("behavior/defer_stage1.zig"); - _ = @import("behavior/enum_stage1.zig"); - _ = @import("behavior/error_stage1.zig"); - _ = @import("behavior/eval_stage1.zig"); - _ = @import("behavior/field_parent_ptr.zig"); - _ = @import("behavior/floatop_stage1.zig"); - _ = @import("behavior/fn_stage1.zig"); - _ = @import("behavior/fn_delegation.zig"); - _ = @import("behavior/for_stage1.zig"); - _ = @import("behavior/if_stage1.zig"); - _ = @import("behavior/ir_block_deps.zig"); - _ = @import("behavior/math_stage1.zig"); - _ = @import("behavior/merge_error_sets.zig"); - _ = @import("behavior/misc.zig"); - _ = @import("behavior/muladd.zig"); - _ = @import("behavior/null_stage1.zig"); - _ = @import("behavior/optional_stage1.zig"); - _ = @import("behavior/pointers_stage1.zig"); - _ = @import("behavior/popcount_stage1.zig"); - _ = @import("behavior/prefetch.zig"); - _ = @import("behavior/ptrcast_stage1.zig"); - _ = @import("behavior/reflection.zig"); - _ = @import("behavior/saturating_arithmetic_stage1.zig"); - _ = @import("behavior/select.zig"); - _ = @import("behavior/shuffle.zig"); - _ = @import("behavior/sizeof_and_typeof_stage1.zig"); - _ = @import("behavior/slice_stage1.zig"); - _ = @import("behavior/struct_contains_null_ptr_itself.zig"); - _ = @import("behavior/struct_contains_slice_of_itself.zig"); - _ = @import("behavior/struct_stage1.zig"); - _ = @import("behavior/switch_prong_err_enum.zig"); - _ = @import("behavior/switch_prong_implicit_cast.zig"); - _ = @import("behavior/switch_stage1.zig"); - _ = @import("behavior/truncate_stage1.zig"); - _ = @import("behavior/try.zig"); - _ = @import("behavior/tuple.zig"); - _ = @import("behavior/type_stage1.zig"); - _ = @import("behavior/type_info_stage1.zig"); - _ = @import("behavior/typename.zig"); - _ = @import("behavior/union_stage1.zig"); - _ = @import("behavior/union_with_members.zig"); - _ = @import("behavior/var_args.zig"); - _ = @import("behavior/vector.zig"); - if (builtin.target.cpu.arch == .wasm32) { - _ = @import("behavior/wasm.zig"); - } - _ = @import("behavior/while_stage1.zig"); - _ = @import("behavior/src.zig"); - _ = @import("behavior/translate_c_macros_stage1.zig"); + if (builtin.zig_backend != .stage1) { + // When all comptime_memory.zig tests pass, #9646 can be closed. + // _ = @import("behavior/comptime_memory.zig"); + _ = @import("behavior/slice_stage2.zig"); + } else { + // Tests that only pass for the stage1 backend. + _ = @import("behavior/align_stage1.zig"); + _ = @import("behavior/array_stage1.zig"); + if (builtin.os.tag != .wasi) { + _ = @import("behavior/asm.zig"); + _ = @import("behavior/async_fn.zig"); } + _ = @import("behavior/await_struct.zig"); + _ = @import("behavior/bit_shifting.zig"); + _ = @import("behavior/bitcast_stage1.zig"); + _ = @import("behavior/bitreverse.zig"); + _ = @import("behavior/bugs/421.zig"); + _ = @import("behavior/bugs/529.zig"); + _ = @import("behavior/bugs/718.zig"); + _ = @import("behavior/bugs/726.zig"); + _ = @import("behavior/bugs/828.zig"); + _ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/bugs/1025.zig"); + _ = @import("behavior/bugs/1076.zig"); + _ = @import("behavior/bugs/1120.zig"); + _ = @import("behavior/bugs/1421.zig"); + _ = @import("behavior/bugs/1442.zig"); + _ = @import("behavior/bugs/1607.zig"); + _ = @import("behavior/bugs/1735.zig"); + _ = @import("behavior/bugs/1851.zig"); + _ = @import("behavior/bugs/1914.zig"); + _ = @import("behavior/bugs/2114.zig"); + _ = @import("behavior/bugs/3384.zig"); + _ = @import("behavior/bugs/3742.zig"); + _ = @import("behavior/bugs/3779.zig"); + _ = @import("behavior/bugs/4328.zig"); + _ = @import("behavior/bugs/5398.zig"); + _ = @import("behavior/bugs/5413.zig"); + _ = @import("behavior/bugs/5474.zig"); + _ = @import("behavior/bugs/5487.zig"); + _ = @import("behavior/bugs/6456.zig"); + _ = @import("behavior/bugs/6781.zig"); + _ = @import("behavior/bugs/7003.zig"); + _ = @import("behavior/bugs/7027.zig"); + _ = @import("behavior/bugs/7047.zig"); + _ = @import("behavior/bugs/10147.zig"); + _ = @import("behavior/byteswap.zig"); + _ = @import("behavior/call_stage1.zig"); + _ = @import("behavior/cast_stage1.zig"); + _ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/defer_stage1.zig"); + _ = @import("behavior/enum_stage1.zig"); + _ = @import("behavior/error_stage1.zig"); + _ = @import("behavior/eval_stage1.zig"); + _ = @import("behavior/field_parent_ptr.zig"); + _ = @import("behavior/floatop_stage1.zig"); + _ = @import("behavior/fn_stage1.zig"); + _ = @import("behavior/fn_delegation.zig"); + _ = @import("behavior/for_stage1.zig"); + _ = @import("behavior/if_stage1.zig"); + _ = @import("behavior/ir_block_deps.zig"); + _ = @import("behavior/math_stage1.zig"); + _ = @import("behavior/merge_error_sets.zig"); + _ = @import("behavior/misc.zig"); + _ = @import("behavior/muladd.zig"); + _ = @import("behavior/null_stage1.zig"); + _ = @import("behavior/optional_stage1.zig"); + _ = @import("behavior/pointers_stage1.zig"); + _ = @import("behavior/popcount_stage1.zig"); + _ = @import("behavior/prefetch.zig"); + _ = @import("behavior/ptrcast_stage1.zig"); + _ = @import("behavior/reflection.zig"); + _ = @import("behavior/saturating_arithmetic_stage1.zig"); + _ = @import("behavior/select.zig"); + _ = @import("behavior/shuffle.zig"); + _ = @import("behavior/sizeof_and_typeof_stage1.zig"); + _ = @import("behavior/slice_stage1.zig"); + _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/struct_contains_slice_of_itself.zig"); + _ = @import("behavior/struct_stage1.zig"); + _ = @import("behavior/switch_prong_err_enum.zig"); + _ = @import("behavior/switch_prong_implicit_cast.zig"); + _ = @import("behavior/switch_stage1.zig"); + _ = @import("behavior/truncate_stage1.zig"); + _ = @import("behavior/try.zig"); + _ = @import("behavior/tuple.zig"); + _ = @import("behavior/type_stage1.zig"); + _ = @import("behavior/type_info_stage1.zig"); + _ = @import("behavior/typename.zig"); + _ = @import("behavior/union_stage1.zig"); + _ = @import("behavior/union_with_members.zig"); + _ = @import("behavior/var_args.zig"); + _ = @import("behavior/vector.zig"); + if (builtin.target.cpu.arch == .wasm32) { + _ = @import("behavior/wasm.zig"); + } + _ = @import("behavior/while_stage1.zig"); + _ = @import("behavior/src.zig"); + _ = @import("behavior/translate_c_macros_stage1.zig"); } } } diff --git a/test/stage2/x86_64.zig b/test/stage2/x86_64.zig index 7abbbad255..878964e8a2 100644 --- a/test/stage2/x86_64.zig +++ b/test/stage2/x86_64.zig @@ -2014,6 +2014,26 @@ fn addLinuxTestCases(ctx: *TestContext) !void { \\} , ""); } + + { + // TODO fixing this will enable zig test on macOS + var case = ctx.exe("access slice element by index - slice_elem_val", linux_x64); + case.addCompareOutput( + \\var array = [_]usize{ 0, 42, 123, 34 }; + \\var slice: []const usize = &array; + \\ + \\pub fn main() void { + \\ assert(slice[0] == 0); + \\ assert(slice[1] == 42); + \\ assert(slice[2] == 123); + \\ assert(slice[3] == 34); + \\} + \\ + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + , ""); + } } fn addMacOsTestCases(ctx: *TestContext) !void {