Merge pull request #10518 from ziglang/stage2-x86_64-zig-test-fixes
stage2: fix x86_64 backend to actually correctly run Zig tests!
This commit is contained in:
@@ -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 => {
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user