mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 08:45:52 +00:00
Merge pull request #22386 from jacobly0/x86_64-rewrite
x86_64: begin rewriting instruction selection
This commit is contained in:
commit
4bace0f621
@ -6,13 +6,13 @@
|
||||
/// `null` means native.
|
||||
cpu_arch: ?Target.Cpu.Arch = null,
|
||||
|
||||
cpu_model: CpuModel = CpuModel.determined_by_arch_os,
|
||||
cpu_model: CpuModel = .determined_by_arch_os,
|
||||
|
||||
/// Sparse set of CPU features to add to the set from `cpu_model`.
|
||||
cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
|
||||
cpu_features_add: Target.Cpu.Feature.Set = .empty,
|
||||
|
||||
/// Sparse set of CPU features to remove from the set from `cpu_model`.
|
||||
cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty,
|
||||
cpu_features_sub: Target.Cpu.Feature.Set = .empty,
|
||||
|
||||
/// `null` means native.
|
||||
os_tag: ?Target.Os.Tag = null,
|
||||
@ -38,7 +38,7 @@ abi: ?Target.Abi = null,
|
||||
|
||||
/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
|
||||
/// based on the `os_tag`.
|
||||
dynamic_linker: Target.DynamicLinker = Target.DynamicLinker.none,
|
||||
dynamic_linker: Target.DynamicLinker = .none,
|
||||
|
||||
/// `null` means default for the cpu/arch/os combo.
|
||||
ofmt: ?Target.ObjectFormat = null,
|
||||
|
||||
@ -47,6 +47,7 @@ pub const Feature = enum {
|
||||
bmi2,
|
||||
branch_hint,
|
||||
branchfusion,
|
||||
bsf_bsr_0_clobbers_result,
|
||||
ccmp,
|
||||
cf,
|
||||
cldemote,
|
||||
@ -167,6 +168,8 @@ pub const Feature = enum {
|
||||
slow_unaligned_mem_32,
|
||||
sm3,
|
||||
sm4,
|
||||
smap,
|
||||
smep,
|
||||
soft_float,
|
||||
sse,
|
||||
sse2,
|
||||
@ -497,6 +500,11 @@ pub const all_features = blk: {
|
||||
.description = "CMP/TEST can be fused with conditional branches",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.bsf_bsr_0_clobbers_result)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "BSF/BSR may clobber the lower 32-bits of the result register when the source is zero",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.ccmp)] = .{
|
||||
.llvm_name = "ccmp",
|
||||
.description = "Support conditional cmp & test instructions",
|
||||
@ -1127,6 +1135,16 @@ pub const all_features = blk: {
|
||||
.avx2,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.smap)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Supervisor Mode Access Prevention",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.smep)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Supervisor Mode Execution Prevention",
|
||||
.dependencies = featureSet(&[_]Feature{}),
|
||||
};
|
||||
result[@intFromEnum(Feature.soft_float)] = .{
|
||||
.llvm_name = "soft-float",
|
||||
.description = "Use software floating point features",
|
||||
@ -1371,6 +1389,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -1467,6 +1487,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.uintr,
|
||||
.vaes,
|
||||
@ -1545,6 +1567,8 @@ pub const cpu = struct {
|
||||
.slow_3ops_lea,
|
||||
.sm3,
|
||||
.sm4,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.uintr,
|
||||
.vaes,
|
||||
@ -1783,6 +1807,8 @@ pub const cpu = struct {
|
||||
.sahf,
|
||||
.sbb_dep_breaking,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -1995,6 +2021,8 @@ pub const cpu = struct {
|
||||
.rdseed,
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
.xsaveopt,
|
||||
@ -2136,6 +2164,8 @@ pub const cpu = struct {
|
||||
.sahf,
|
||||
.sha,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -2195,6 +2225,8 @@ pub const cpu = struct {
|
||||
.rdseed,
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -2450,6 +2482,8 @@ pub const cpu = struct {
|
||||
.serialize,
|
||||
.sha,
|
||||
.shstk,
|
||||
.smap,
|
||||
.smep,
|
||||
.tsxldtrk,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.uintr,
|
||||
@ -2519,6 +2553,8 @@ pub const cpu = struct {
|
||||
.slow_incdec,
|
||||
.slow_lea,
|
||||
.slow_two_mem_ops,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4_2,
|
||||
.use_glm_div_sqrt_costs,
|
||||
.vzeroupper,
|
||||
@ -2898,6 +2934,7 @@ pub const cpu = struct {
|
||||
.rdrnd,
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.smep,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
.xsaveopt,
|
||||
@ -2907,6 +2944,7 @@ pub const cpu = struct {
|
||||
.name = "i386",
|
||||
.llvm_name = "i386",
|
||||
.features = featureSet(&[_]Feature{
|
||||
.bsf_bsr_0_clobbers_result,
|
||||
.slow_unaligned_mem_16,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -2916,6 +2954,7 @@ pub const cpu = struct {
|
||||
.name = "i486",
|
||||
.llvm_name = "i486",
|
||||
.features = featureSet(&[_]Feature{
|
||||
.bsf_bsr_0_clobbers_result,
|
||||
.slow_unaligned_mem_16,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -3096,6 +3135,7 @@ pub const cpu = struct {
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.slow_unaligned_mem_32,
|
||||
.smep,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
.xsaveopt,
|
||||
@ -3403,6 +3443,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -3766,6 +3808,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -3831,6 +3875,8 @@ pub const cpu = struct {
|
||||
.rdseed,
|
||||
.sahf,
|
||||
.sha,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -3939,6 +3985,8 @@ pub const cpu = struct {
|
||||
.serialize,
|
||||
.sha,
|
||||
.shstk,
|
||||
.smap,
|
||||
.smep,
|
||||
.tsxldtrk,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.uintr,
|
||||
@ -4042,6 +4090,7 @@ pub const cpu = struct {
|
||||
.slow_lea,
|
||||
.slow_pmulld,
|
||||
.slow_two_mem_ops,
|
||||
.smep,
|
||||
.sse4_2,
|
||||
.use_slm_arith_costs,
|
||||
.vzeroupper,
|
||||
@ -4098,6 +4147,8 @@ pub const cpu = struct {
|
||||
.rdseed,
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -4150,6 +4201,8 @@ pub const cpu = struct {
|
||||
.rdseed,
|
||||
.sahf,
|
||||
.slow_3ops_lea,
|
||||
.smap,
|
||||
.smep,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
.xsavec,
|
||||
@ -4305,6 +4358,8 @@ pub const cpu = struct {
|
||||
.sahf,
|
||||
.sha,
|
||||
.shstk,
|
||||
.smap,
|
||||
.smep,
|
||||
.tuning_fast_imm_vector_shift,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -4574,6 +4629,8 @@ pub const cpu = struct {
|
||||
.sbb_dep_breaking,
|
||||
.sha,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vzeroupper,
|
||||
.x87,
|
||||
@ -4629,6 +4686,8 @@ pub const cpu = struct {
|
||||
.sbb_dep_breaking,
|
||||
.sha,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vzeroupper,
|
||||
.wbnoinvd,
|
||||
@ -4686,6 +4745,8 @@ pub const cpu = struct {
|
||||
.sbb_dep_breaking,
|
||||
.sha,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -4757,6 +4818,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
@ -4833,6 +4896,8 @@ pub const cpu = struct {
|
||||
.sha,
|
||||
.shstk,
|
||||
.slow_shld,
|
||||
.smap,
|
||||
.smep,
|
||||
.sse4a,
|
||||
.vaes,
|
||||
.vpclmulqdq,
|
||||
|
||||
@ -372,9 +372,11 @@ pub const SpawnConfig = struct {
|
||||
// https://github.com/ziglang/zig/issues/157
|
||||
|
||||
/// Size in bytes of the Thread's stack
|
||||
stack_size: usize = 16 * 1024 * 1024,
|
||||
stack_size: usize = default_stack_size,
|
||||
/// The allocator to be used to allocate memory for the to-be-spawned thread
|
||||
allocator: ?std.mem.Allocator = null,
|
||||
|
||||
pub const default_stack_size = 16 * 1024 * 1024;
|
||||
};
|
||||
|
||||
pub const SpawnError = error{
|
||||
|
||||
@ -161,17 +161,17 @@ const WindowsImpl = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (comptime builtin.mode == .Debug) {
|
||||
if (builtin.mode == .Debug) {
|
||||
// The internal state of the DebugMutex needs to be handled here as well.
|
||||
mutex.impl.locking_thread.store(0, .unordered);
|
||||
}
|
||||
const rc = os.windows.kernel32.SleepConditionVariableSRW(
|
||||
&self.condition,
|
||||
if (comptime builtin.mode == .Debug) &mutex.impl.impl.srwlock else &mutex.impl.srwlock,
|
||||
if (builtin.mode == .Debug) &mutex.impl.impl.srwlock else &mutex.impl.srwlock,
|
||||
timeout_ms,
|
||||
0, // the srwlock was assumed to acquired in exclusive mode not shared
|
||||
);
|
||||
if (comptime builtin.mode == .Debug) {
|
||||
if (builtin.mode == .Debug) {
|
||||
// The internal state of the DebugMutex needs to be handled here as well.
|
||||
mutex.impl.locking_thread.store(std.Thread.getCurrentId(), .unordered);
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ const FutexImpl = struct {
|
||||
// On x86, use `lock bts` instead of `lock cmpxchg` as:
|
||||
// - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
|
||||
// - `lock bts` is smaller instruction-wise which makes it better for inlining
|
||||
if (comptime builtin.target.cpu.arch.isX86()) {
|
||||
if (builtin.target.cpu.arch.isX86()) {
|
||||
const locked_bit = @ctz(locked);
|
||||
return self.state.bitSet(locked_bit, .acquire) == 0;
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ pub const Options = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
n_jobs: ?usize = null,
|
||||
track_ids: bool = false,
|
||||
stack_size: usize = std.Thread.SpawnConfig.default_stack_size,
|
||||
};
|
||||
|
||||
pub fn init(pool: *Pool, options: Options) !void {
|
||||
@ -54,7 +55,10 @@ pub fn init(pool: *Pool, options: Options) !void {
|
||||
errdefer pool.join(spawned);
|
||||
|
||||
for (pool.threads) |*thread| {
|
||||
thread.* = try std.Thread.spawn(.{}, worker, .{pool});
|
||||
thread.* = try std.Thread.spawn(.{
|
||||
.stack_size = options.stack_size,
|
||||
.allocator = allocator,
|
||||
}, worker, .{pool});
|
||||
spawned += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ const mem = std.mem;
|
||||
const debug = std.debug;
|
||||
|
||||
const has_vaes = builtin.cpu.arch == .x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .vaes);
|
||||
const has_avx512f = builtin.cpu.arch == .x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f);
|
||||
const has_avx512f = builtin.cpu.arch == .x86_64 and builtin.zig_backend != .stage2_x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f);
|
||||
|
||||
/// A single AES block.
|
||||
pub const Block = struct {
|
||||
|
||||
@ -499,11 +499,9 @@ fn ChaChaNonVecImpl(comptime rounds_nb: usize) type {
|
||||
fn ChaChaImpl(comptime rounds_nb: usize) type {
|
||||
switch (builtin.cpu.arch) {
|
||||
.x86_64 => {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return ChaChaNonVecImpl(rounds_nb);
|
||||
|
||||
const has_avx2 = std.Target.x86.featureSetHas(builtin.cpu.features, .avx2);
|
||||
const has_avx512f = std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f);
|
||||
if (has_avx512f) return ChaChaVecImpl(rounds_nb, 4);
|
||||
if (builtin.zig_backend != .stage2_x86_64 and has_avx512f) return ChaChaVecImpl(rounds_nb, 4);
|
||||
if (has_avx2) return ChaChaVecImpl(rounds_nb, 2);
|
||||
return ChaChaVecImpl(rounds_nb, 1);
|
||||
},
|
||||
|
||||
@ -356,14 +356,7 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
|
||||
if (ciphertext.len > cleartext_fragment_buf.len) return error.TlsRecordOverflow;
|
||||
const cleartext = cleartext_fragment_buf[0..ciphertext.len];
|
||||
const auth_tag = record_decoder.array(P.AEAD.tag_length).*;
|
||||
const nonce = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.server_handshake_iv;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ read_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ @as([8]u8, @bitCast(big(read_seq)));
|
||||
@ -400,14 +393,7 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
|
||||
const record_iv = record_decoder.array(P.record_iv_length).*;
|
||||
const masked_read_seq = read_seq &
|
||||
comptime std.math.shl(u64, std.math.maxInt(u64), 8 * P.record_iv_length);
|
||||
const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.app_cipher.server_write_IV ++ record_iv;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ masked_read_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce: [P.AEAD.nonce_length]u8 = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq)));
|
||||
@ -750,14 +736,7 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
|
||||
.app_cipher = std.mem.bytesToValue(P.Tls_1_2, &key_block),
|
||||
} };
|
||||
const pv = &p.version.tls_1_2;
|
||||
const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ write_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce: [P.AEAD.nonce_length]u8 = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ @as([8]u8, @bitCast(big(write_seq)));
|
||||
@ -1043,14 +1022,7 @@ fn prepareCiphertextRecord(
|
||||
ciphertext_end += ciphertext_len;
|
||||
const auth_tag = ciphertext_buf[ciphertext_end..][0..P.AEAD.tag_length];
|
||||
ciphertext_end += auth_tag.len;
|
||||
const nonce = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.client_iv;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.write_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ std.mem.toBytes(big(c.write_seq));
|
||||
@ -1098,14 +1070,7 @@ fn prepareCiphertextRecord(
|
||||
const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int(u16, message_len);
|
||||
const record_iv = ciphertext_buf[ciphertext_end..][0..P.record_iv_length];
|
||||
ciphertext_end += P.record_iv_length;
|
||||
const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.client_write_IV ++ pv.client_salt;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.write_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce: [P.AEAD.nonce_length]u8 = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ @as([8]u8, @bitCast(big(c.write_seq)));
|
||||
@ -1374,14 +1339,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove
|
||||
const ciphertext = frag[in..][0..ciphertext_len];
|
||||
in += ciphertext_len;
|
||||
const auth_tag = frag[in..][0..P.AEAD.tag_length].*;
|
||||
const nonce = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.server_iv;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.read_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ std.mem.toBytes(big(c.read_seq));
|
||||
@ -1409,14 +1367,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove
|
||||
in += P.record_iv_length;
|
||||
const masked_read_seq = c.read_seq &
|
||||
comptime std.math.shl(u64, std.math.maxInt(u64), 8 * P.record_iv_length);
|
||||
const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
|
||||
P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
|
||||
nonce: {
|
||||
var nonce = pv.server_write_IV ++ record_iv;
|
||||
const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
|
||||
std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ masked_read_seq, .big);
|
||||
break :nonce nonce;
|
||||
} else nonce: {
|
||||
const nonce: [P.AEAD.nonce_length]u8 = nonce: {
|
||||
const V = @Vector(P.AEAD.nonce_length, u8);
|
||||
const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
|
||||
const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq)));
|
||||
|
||||
@ -23,6 +23,7 @@ pub const Coverage = @import("debug/Coverage.zig");
|
||||
|
||||
pub const FormattedPanic = @import("debug/FormattedPanic.zig");
|
||||
pub const SimplePanic = @import("debug/SimplePanic.zig");
|
||||
pub const NoPanic = @import("debug/NoPanic.zig");
|
||||
|
||||
/// Unresolved source locations can be represented with a single `usize` that
|
||||
/// corresponds to a virtual memory address of the program counter. Combined
|
||||
@ -179,7 +180,7 @@ pub fn dumpHexFallible(bytes: []const u8) !void {
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
nosuspend {
|
||||
if (comptime builtin.target.isWasm()) {
|
||||
if (builtin.target.isWasm()) {
|
||||
if (native_os == .wasi) {
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
|
||||
@ -267,7 +268,7 @@ pub inline fn getContext(context: *ThreadContext) bool {
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpStackTraceFromBase(context: *ThreadContext) void {
|
||||
nosuspend {
|
||||
if (comptime builtin.target.isWasm()) {
|
||||
if (builtin.target.isWasm()) {
|
||||
if (native_os == .wasi) {
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
|
||||
@ -365,7 +366,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
|
||||
/// TODO multithreaded awareness
|
||||
pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
|
||||
nosuspend {
|
||||
if (comptime builtin.target.isWasm()) {
|
||||
if (builtin.target.isWasm()) {
|
||||
if (native_os == .wasi) {
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
|
||||
|
||||
59
lib/std/debug/NoPanic.zig
Normal file
59
lib/std/debug/NoPanic.zig
Normal file
@ -0,0 +1,59 @@
|
||||
//! This namespace can be used with `pub const Panic = std.debug.NoPanic;` in the root file.
|
||||
//! It emits as little code as possible, for testing purposes.
|
||||
//!
|
||||
//! For a functional alternative, see `std.debug.FormattedPanic`.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
|
||||
pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub inline fn sentinelMismatch(_: anytype, _: anytype) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub inline fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub inline fn outOfBounds(_: usize, _: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub inline fn startGreaterThanEnd(_: usize, _: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub inline fn inactiveUnionField(_: anytype, _: anytype) noreturn {
|
||||
@branchHint(.cold);
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub const messages = struct {
|
||||
pub const reached_unreachable = "";
|
||||
pub const unwrap_null = "";
|
||||
pub const cast_to_null = "";
|
||||
pub const incorrect_alignment = "";
|
||||
pub const invalid_error_code = "";
|
||||
pub const cast_truncated_data = "";
|
||||
pub const negative_to_unsigned = "";
|
||||
pub const integer_overflow = "";
|
||||
pub const shl_overflow = "";
|
||||
pub const shr_overflow = "";
|
||||
pub const divide_by_zero = "";
|
||||
pub const exact_division_remainder = "";
|
||||
pub const integer_part_out_of_bounds = "";
|
||||
pub const corrupt_switch = "";
|
||||
pub const shift_rhs_too_big = "";
|
||||
pub const invalid_enum_value = "";
|
||||
pub const for_len_mismatch = "";
|
||||
pub const memcpy_len_mismatch = "";
|
||||
pub const memcpy_alias = "";
|
||||
pub const noreturn_returned = "";
|
||||
};
|
||||
@ -121,13 +121,13 @@ pub fn deinit(self: *SelfInfo) void {
|
||||
}
|
||||
|
||||
pub fn getModuleForAddress(self: *SelfInfo, address: usize) !*Module {
|
||||
if (comptime builtin.target.isDarwin()) {
|
||||
if (builtin.target.isDarwin()) {
|
||||
return self.lookupModuleDyld(address);
|
||||
} else if (native_os == .windows) {
|
||||
return self.lookupModuleWin32(address);
|
||||
} else if (native_os == .haiku) {
|
||||
return self.lookupModuleHaiku(address);
|
||||
} else if (comptime builtin.target.isWasm()) {
|
||||
} else if (builtin.target.isWasm()) {
|
||||
return self.lookupModuleWasm(address);
|
||||
} else {
|
||||
return self.lookupModuleDl(address);
|
||||
@ -138,13 +138,13 @@ pub fn getModuleForAddress(self: *SelfInfo, address: usize) !*Module {
|
||||
// This can be called when getModuleForAddress fails, so implementations should provide
|
||||
// a path that doesn't rely on any side-effects of a prior successful module lookup.
|
||||
pub fn getModuleNameForAddress(self: *SelfInfo, address: usize) ?[]const u8 {
|
||||
if (comptime builtin.target.isDarwin()) {
|
||||
if (builtin.target.isDarwin()) {
|
||||
return self.lookupModuleNameDyld(address);
|
||||
} else if (native_os == .windows) {
|
||||
return self.lookupModuleNameWin32(address);
|
||||
} else if (native_os == .haiku) {
|
||||
return null;
|
||||
} else if (comptime builtin.target.isWasm()) {
|
||||
} else if (builtin.target.isWasm()) {
|
||||
return null;
|
||||
} else {
|
||||
return self.lookupModuleNameDl(address);
|
||||
|
||||
@ -890,7 +890,7 @@ test {
|
||||
_ = @import("heap/memory_pool.zig");
|
||||
_ = ArenaAllocator;
|
||||
_ = GeneralPurposeAllocator;
|
||||
if (comptime builtin.target.isWasm()) {
|
||||
if (builtin.target.isWasm()) {
|
||||
_ = WasmAllocator;
|
||||
_ = WasmPageAllocator;
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const use_vectors = builtin.zig_backend != .stage2_x86_64;
|
||||
|
||||
pub const State = enum {
|
||||
invalid,
|
||||
|
||||
@ -2520,12 +2520,13 @@ pub const Const = struct {
|
||||
return order(a, b) == .eq;
|
||||
}
|
||||
|
||||
/// Returns the number of leading zeros in twos-complement form.
|
||||
pub fn clz(a: Const, bits: Limb) Limb {
|
||||
// Limbs are stored in little-endian order but we need
|
||||
// to iterate big-endian.
|
||||
// Limbs are stored in little-endian order but we need to iterate big-endian.
|
||||
if (!a.positive and !a.eqlZero()) return 0;
|
||||
var total_limb_lz: Limb = 0;
|
||||
var i: usize = a.limbs.len;
|
||||
const bits_per_limb = @sizeOf(Limb) * 8;
|
||||
const bits_per_limb = @bitSizeOf(Limb);
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
const limb = a.limbs[i];
|
||||
@ -2537,13 +2538,15 @@ pub const Const = struct {
|
||||
return total_limb_lz + bits - total_limb_bits;
|
||||
}
|
||||
|
||||
/// Returns the number of trailing zeros in twos-complement form.
|
||||
pub fn ctz(a: Const, bits: Limb) Limb {
|
||||
// Limbs are stored in little-endian order.
|
||||
// Limbs are stored in little-endian order. Converting a negative number to twos-complement
|
||||
// flips all bits above the lowest set bit, which does not affect the trailing zero count.
|
||||
var result: Limb = 0;
|
||||
for (a.limbs) |limb| {
|
||||
const limb_tz = @ctz(limb);
|
||||
result += limb_tz;
|
||||
if (limb_tz != @sizeOf(Limb) * 8) break;
|
||||
if (limb_tz != @bitSizeOf(Limb)) break;
|
||||
}
|
||||
return @min(result, bits);
|
||||
}
|
||||
|
||||
@ -883,8 +883,8 @@ fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type {
|
||||
@compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T));
|
||||
}
|
||||
|
||||
/// Takes an array, a pointer to an array, a sentinel-terminated pointer, or a slice and
|
||||
/// iterates searching for the first occurrence of `end`, returning the scanned slice.
|
||||
/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice and iterates searching for
|
||||
/// the first occurrence of `end`, returning the scanned slice.
|
||||
/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned.
|
||||
/// If the pointer type is sentinel terminated and `end` matches that terminator, the
|
||||
/// resulting slice is also sentinel terminated.
|
||||
|
||||
@ -157,7 +157,7 @@ pub fn getFdPath(fd: std.posix.fd_t, out_buffer: *[max_path_bytes]u8) std.posix.
|
||||
return target;
|
||||
},
|
||||
.freebsd => {
|
||||
if (comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false) {
|
||||
if (builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false) {
|
||||
var kfile: std.c.kinfo_file = undefined;
|
||||
kfile.structsize = std.c.KINFO_FILE_SIZE;
|
||||
switch (posix.errno(std.c.fcntl(fd, std.c.F.KINFO, @intFromPtr(&kfile)))) {
|
||||
|
||||
@ -1061,7 +1061,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
|
||||
// us INVALID_PARAMETER.
|
||||
// The same reasoning for win10_rs5 as in os.renameatW() applies (FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE requires >= win10_rs5).
|
||||
var need_fallback = true;
|
||||
if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs5)) {
|
||||
if (builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs5)) {
|
||||
// Deletion with posix semantics if the filesystem supports it.
|
||||
var info = FILE_DISPOSITION_INFORMATION_EX{
|
||||
.Flags = FILE_DISPOSITION_DELETE |
|
||||
|
||||
@ -6819,7 +6819,7 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
|
||||
}
|
||||
},
|
||||
.freebsd => {
|
||||
if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt)
|
||||
if (builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt)
|
||||
@compileError("memfd_create is unavailable on FreeBSD < 13.0");
|
||||
const rc = system.memfd_create(name, flags);
|
||||
switch (errno(rc)) {
|
||||
|
||||
@ -804,7 +804,7 @@ test "getrlimit and setrlimit" {
|
||||
//
|
||||
// This happens for example if RLIMIT_MEMLOCK is bigger than ~2GiB.
|
||||
// In that case the following the limit would be RLIM_INFINITY and the following setrlimit fails with EPERM.
|
||||
if (comptime builtin.cpu.arch.isMIPS() and builtin.link_libc) {
|
||||
if (builtin.cpu.arch.isMIPS() and builtin.link_libc) {
|
||||
if (limit.cur != linux.RLIM.INFINITY) {
|
||||
try posix.setrlimit(resource, limit);
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ pub fn interlace(vecs: anytype) @Vector(vectorLength(@TypeOf(vecs[0])) * vecs.le
|
||||
// The indices are correct. The problem seems to be with the @shuffle builtin.
|
||||
// On MIPS, the test that interlaces small_base gives { 0, 2, 0, 0, 64, 255, 248, 200, 0, 0 }.
|
||||
// Calling this with two inputs seems to work fine, but I'll let the compile error trigger for all inputs, just to be safe.
|
||||
comptime if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why interlace() doesn't work on MIPS");
|
||||
if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why interlace() doesn't work on MIPS");
|
||||
|
||||
const VecType = @TypeOf(vecs[0]);
|
||||
const vecs_arr = @as([vecs.len]VecType, vecs);
|
||||
@ -248,7 +248,7 @@ test "vector patterns" {
|
||||
try std.testing.expectEqual([8]u32{ 10, 20, 30, 40, 55, 66, 77, 88 }, join(base, other_base));
|
||||
try std.testing.expectEqual([2]u32{ 20, 30 }, extract(base, 1, 2));
|
||||
|
||||
if (comptime !builtin.cpu.arch.isMIPS()) {
|
||||
if (!builtin.cpu.arch.isMIPS()) {
|
||||
try std.testing.expectEqual([8]u32{ 10, 55, 20, 66, 30, 77, 40, 88 }, interlace(.{ base, other_base }));
|
||||
|
||||
const small_braid = interlace(small_bases);
|
||||
@ -390,7 +390,7 @@ pub fn prefixScanWithFunc(
|
||||
comptime identity: std.meta.Child(@TypeOf(vec)),
|
||||
) if (ErrorType == void) @TypeOf(vec) else ErrorType!@TypeOf(vec) {
|
||||
// I haven't debugged this, but it might be a cousin of sorts to what's going on with interlace.
|
||||
comptime if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why prefixScan doesn't work on MIPS");
|
||||
if (builtin.cpu.arch.isMIPS()) @compileError("TODO: Find out why prefixScan doesn't work on MIPS");
|
||||
|
||||
const len = vectorLength(@TypeOf(vec));
|
||||
|
||||
@ -465,9 +465,7 @@ test "vector prefix scan" {
|
||||
if ((builtin.cpu.arch == .armeb or builtin.cpu.arch == .thumbeb) and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22060
|
||||
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21893
|
||||
|
||||
if (comptime builtin.cpu.arch.isMIPS()) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
|
||||
|
||||
const int_base = @Vector(4, i32){ 11, 23, 9, -21 };
|
||||
const float_base = @Vector(4, f32){ 2, 0.5, -10, 6.54321 };
|
||||
|
||||
@ -83,7 +83,7 @@ pub fn detect(arena: Allocator, native_target: std.Target) !NativePaths {
|
||||
|
||||
// TODO: consider also adding homebrew paths
|
||||
// TODO: consider also adding macports paths
|
||||
if (comptime builtin.target.isDarwin()) {
|
||||
if (builtin.target.isDarwin()) {
|
||||
if (std.zig.system.darwin.isSdkInstalled(arena)) sdk: {
|
||||
const sdk = std.zig.system.darwin.getSdk(arena, native_target) orelse break :sdk;
|
||||
try self.addLibDir(try std.fs.path.join(arena, &.{ sdk, "usr/lib" }));
|
||||
|
||||
@ -369,6 +369,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
|
||||
setFeature(cpu, .bmi, bit(leaf.ebx, 3));
|
||||
// AVX2 is only supported if we have the OS save support from AVX.
|
||||
setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx_save);
|
||||
setFeature(cpu, .smep, bit(leaf.ebx, 7));
|
||||
setFeature(cpu, .bmi2, bit(leaf.ebx, 8));
|
||||
setFeature(cpu, .invpcid, bit(leaf.ebx, 10));
|
||||
setFeature(cpu, .rtm, bit(leaf.ebx, 11));
|
||||
@ -377,6 +378,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
|
||||
setFeature(cpu, .avx512dq, bit(leaf.ebx, 17) and has_avx512_save);
|
||||
setFeature(cpu, .rdseed, bit(leaf.ebx, 18));
|
||||
setFeature(cpu, .adx, bit(leaf.ebx, 19));
|
||||
setFeature(cpu, .smap, bit(leaf.ebx, 20));
|
||||
setFeature(cpu, .avx512ifma, bit(leaf.ebx, 21) and has_avx512_save);
|
||||
setFeature(cpu, .clflushopt, bit(leaf.ebx, 23));
|
||||
setFeature(cpu, .clwb, bit(leaf.ebx, 24));
|
||||
|
||||
46
src/Air.zig
46
src/Air.zig
@ -893,14 +893,38 @@ pub const Inst = struct {
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn toRef(i: Index) Inst.Ref {
|
||||
assert(@intFromEnum(i) >> 31 == 0);
|
||||
return @enumFromInt((1 << 31) | @intFromEnum(i));
|
||||
pub fn unwrap(index: Index) union(enum) { ref: Inst.Ref, target: u31 } {
|
||||
const low_index: u31 = @truncate(@intFromEnum(index));
|
||||
return switch (@as(u1, @intCast(@intFromEnum(index) >> 31))) {
|
||||
0 => .{ .ref = @enumFromInt(@as(u32, 1 << 31) | low_index) },
|
||||
1 => .{ .target = low_index },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toTargetIndex(i: Index) u31 {
|
||||
assert(@intFromEnum(i) >> 31 == 1);
|
||||
return @truncate(@intFromEnum(i));
|
||||
pub fn toRef(index: Index) Inst.Ref {
|
||||
return index.unwrap().ref;
|
||||
}
|
||||
|
||||
pub fn fromTargetIndex(index: u31) Index {
|
||||
return @enumFromInt((1 << 31) | @as(u32, index));
|
||||
}
|
||||
|
||||
pub fn toTargetIndex(index: Index) u31 {
|
||||
return index.unwrap().target;
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
index: Index,
|
||||
comptime _: []const u8,
|
||||
_: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
try writer.writeByte('%');
|
||||
switch (index.unwrap()) {
|
||||
.ref => {},
|
||||
.target => try writer.writeByte('t'),
|
||||
}
|
||||
try writer.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))});
|
||||
}
|
||||
};
|
||||
|
||||
@ -1205,7 +1229,7 @@ pub const VectorCmp = struct {
|
||||
op: u32,
|
||||
|
||||
pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {
|
||||
return @as(std.math.CompareOperator, @enumFromInt(@as(u3, @truncate(self.op))));
|
||||
return @enumFromInt(@as(u3, @intCast(self.op)));
|
||||
}
|
||||
|
||||
pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
|
||||
@ -1250,11 +1274,11 @@ pub const Cmpxchg = struct {
|
||||
flags: u32,
|
||||
|
||||
pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder {
|
||||
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags))));
|
||||
return @enumFromInt(@as(u3, @truncate(self.flags)));
|
||||
}
|
||||
|
||||
pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder {
|
||||
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags >> 3))));
|
||||
return @enumFromInt(@as(u3, @intCast(self.flags >> 3)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1265,11 +1289,11 @@ pub const AtomicRmw = struct {
|
||||
flags: u32,
|
||||
|
||||
pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder {
|
||||
return @as(std.builtin.AtomicOrder, @enumFromInt(@as(u3, @truncate(self.flags))));
|
||||
return @enumFromInt(@as(u3, @truncate(self.flags)));
|
||||
}
|
||||
|
||||
pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp {
|
||||
return @as(std.builtin.AtomicRmwOp, @enumFromInt(@as(u4, @truncate(self.flags >> 3))));
|
||||
return @enumFromInt(@as(u4, @intCast(self.flags >> 3)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -3067,6 +3067,7 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
// linker state
|
||||
switch (lf.tag) {
|
||||
.wasm => {
|
||||
dev.check(link.File.Tag.wasm.devFeature());
|
||||
const wasm = lf.cast(.wasm).?;
|
||||
const is_obj = comp.config.output_mode == .Obj;
|
||||
try bufs.ensureUnusedCapacity(85);
|
||||
|
||||
@ -202,14 +202,6 @@ pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool
|
||||
return (l.tomb_bits[usize_index] & mask) != 0;
|
||||
}
|
||||
|
||||
pub fn clearOperandDeath(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) void {
|
||||
assert(operand < bpi - 1);
|
||||
const usize_index = (@intFromEnum(inst) * bpi) / @bitSizeOf(usize);
|
||||
const mask = @as(usize, 1) <<
|
||||
@as(Log2Int(usize), @intCast((@intFromEnum(inst) % (@bitSizeOf(usize) / bpi)) * bpi + operand));
|
||||
l.tomb_bits[usize_index] &= ~mask;
|
||||
}
|
||||
|
||||
const OperandCategory = enum {
|
||||
/// The operand lives on, but this instruction cannot possibly mutate memory.
|
||||
none,
|
||||
@ -727,32 +719,25 @@ pub const SwitchBrTable = struct {
|
||||
|
||||
/// Caller owns the memory.
|
||||
pub fn getSwitchBr(l: Liveness, gpa: Allocator, inst: Air.Inst.Index, cases_len: u32) Allocator.Error!SwitchBrTable {
|
||||
var index: usize = l.special.get(inst) orelse return SwitchBrTable{
|
||||
.deaths = &.{},
|
||||
};
|
||||
var index: usize = l.special.get(inst) orelse return .{ .deaths = &.{} };
|
||||
const else_death_count = l.extra[index];
|
||||
index += 1;
|
||||
|
||||
var deaths = std.ArrayList([]const Air.Inst.Index).init(gpa);
|
||||
defer deaths.deinit();
|
||||
try deaths.ensureTotalCapacity(cases_len + 1);
|
||||
var deaths = try gpa.alloc([]const Air.Inst.Index, cases_len);
|
||||
errdefer gpa.free(deaths);
|
||||
|
||||
var case_i: u32 = 0;
|
||||
while (case_i < cases_len - 1) : (case_i += 1) {
|
||||
const case_death_count: u32 = l.extra[index];
|
||||
index += 1;
|
||||
const case_deaths: []const Air.Inst.Index = @ptrCast(l.extra[index..][0..case_death_count]);
|
||||
deaths[case_i] = @ptrCast(l.extra[index..][0..case_death_count]);
|
||||
index += case_death_count;
|
||||
deaths.appendAssumeCapacity(case_deaths);
|
||||
}
|
||||
{
|
||||
// Else
|
||||
const else_deaths: []const Air.Inst.Index = @ptrCast(l.extra[index..][0..else_death_count]);
|
||||
deaths.appendAssumeCapacity(else_deaths);
|
||||
deaths[case_i] = @ptrCast(l.extra[index..][0..else_death_count]);
|
||||
}
|
||||
return SwitchBrTable{
|
||||
.deaths = try deaths.toOwnedSlice(),
|
||||
};
|
||||
return .{ .deaths = deaths };
|
||||
}
|
||||
|
||||
/// Note that this information is technically redundant, but is useful for
|
||||
@ -844,12 +829,6 @@ const Analysis = struct {
|
||||
special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
|
||||
fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
|
||||
const usize_index = (inst * bpi) / @bitSizeOf(usize);
|
||||
a.tomb_bits[usize_index] |= @as(usize, tomb_bits) <<
|
||||
@as(Log2Int(usize), @intCast((inst % (@bitSizeOf(usize) / bpi)) * bpi));
|
||||
}
|
||||
|
||||
fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 {
|
||||
const fields = std.meta.fields(@TypeOf(extra));
|
||||
try a.extra.ensureUnusedCapacity(a.gpa, fields.len);
|
||||
|
||||
47
src/Type.zig
47
src/Type.zig
@ -962,7 +962,6 @@ pub fn abiAlignmentInner(
|
||||
) SemaError!AbiAlignmentInner {
|
||||
const pt = strat.pt(zcu, tid);
|
||||
const target = zcu.getTarget();
|
||||
const use_llvm = zcu.comp.config.use_llvm;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
switch (ty.toIntern()) {
|
||||
@ -970,7 +969,7 @@ pub fn abiAlignmentInner(
|
||||
else => switch (ip.indexToKey(ty.toIntern())) {
|
||||
.int_type => |int_type| {
|
||||
if (int_type.bits == 0) return .{ .scalar = .@"1" };
|
||||
return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiAlignment(int_type.bits, target) };
|
||||
},
|
||||
.ptr_type, .anyframe_type => {
|
||||
return .{ .scalar = ptrAbiAlignment(target) };
|
||||
@ -1023,7 +1022,7 @@ pub fn abiAlignmentInner(
|
||||
.error_set_type, .inferred_error_set_type => {
|
||||
const bits = zcu.errorSetBits();
|
||||
if (bits == 0) return .{ .scalar = .@"1" };
|
||||
return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiAlignment(bits, target) };
|
||||
},
|
||||
|
||||
// represents machine code; not a pointer
|
||||
@ -1036,7 +1035,7 @@ pub fn abiAlignmentInner(
|
||||
|
||||
.usize,
|
||||
.isize,
|
||||
=> return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
|
||||
=> return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
|
||||
|
||||
.c_char => return .{ .scalar = cTypeAlign(target, .char) },
|
||||
.c_short => return .{ .scalar = cTypeAlign(target, .short) },
|
||||
@ -1067,7 +1066,7 @@ pub fn abiAlignmentInner(
|
||||
.anyerror, .adhoc_inferred_error_set => {
|
||||
const bits = zcu.errorSetBits();
|
||||
if (bits == 0) return .{ .scalar = .@"1" };
|
||||
return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiAlignment(bits, target) };
|
||||
},
|
||||
|
||||
.void,
|
||||
@ -1291,7 +1290,6 @@ pub fn abiSizeInner(
|
||||
tid: strat.Tid(),
|
||||
) SemaError!AbiSizeInner {
|
||||
const target = zcu.getTarget();
|
||||
const use_llvm = zcu.comp.config.use_llvm;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
switch (ty.toIntern()) {
|
||||
@ -1300,7 +1298,7 @@ pub fn abiSizeInner(
|
||||
else => switch (ip.indexToKey(ty.toIntern())) {
|
||||
.int_type => |int_type| {
|
||||
if (int_type.bits == 0) return .{ .scalar = 0 };
|
||||
return .{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiSize(int_type.bits, target) };
|
||||
},
|
||||
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
|
||||
.slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
|
||||
@ -1362,7 +1360,7 @@ pub fn abiSizeInner(
|
||||
.error_set_type, .inferred_error_set_type => {
|
||||
const bits = zcu.errorSetBits();
|
||||
if (bits == 0) return .{ .scalar = 0 };
|
||||
return .{ .scalar = intAbiSize(bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiSize(bits, target) };
|
||||
},
|
||||
|
||||
.error_union_type => |error_union_type| {
|
||||
@ -1455,7 +1453,7 @@ pub fn abiSizeInner(
|
||||
.anyerror, .adhoc_inferred_error_set => {
|
||||
const bits = zcu.errorSetBits();
|
||||
if (bits == 0) return .{ .scalar = 0 };
|
||||
return .{ .scalar = intAbiSize(bits, target, use_llvm) };
|
||||
return .{ .scalar = intAbiSize(bits, target) };
|
||||
},
|
||||
|
||||
.noreturn => unreachable,
|
||||
@ -1609,11 +1607,11 @@ pub fn ptrAbiAlignment(target: Target) Alignment {
|
||||
return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
|
||||
}
|
||||
|
||||
pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
|
||||
return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
|
||||
pub fn intAbiSize(bits: u16, target: Target) u64 {
|
||||
return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
|
||||
}
|
||||
|
||||
pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
|
||||
pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
|
||||
return switch (target.cpu.arch) {
|
||||
.x86 => switch (bits) {
|
||||
0 => .none,
|
||||
@ -1632,19 +1630,16 @@ pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
|
||||
9...16 => .@"2",
|
||||
17...32 => .@"4",
|
||||
33...64 => .@"8",
|
||||
else => switch (target_util.zigBackend(target, use_llvm)) {
|
||||
.stage2_x86_64 => .@"8",
|
||||
else => .@"16",
|
||||
},
|
||||
else => .@"16",
|
||||
},
|
||||
else => return Alignment.fromByteUnits(@min(
|
||||
std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
|
||||
maxIntAlignment(target, use_llvm),
|
||||
maxIntAlignment(target),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
|
||||
pub fn maxIntAlignment(target: std.Target) u16 {
|
||||
return switch (target.cpu.arch) {
|
||||
.avr => 1,
|
||||
.msp430 => 2,
|
||||
@ -1685,10 +1680,7 @@ pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
|
||||
else => 8,
|
||||
},
|
||||
|
||||
.x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
|
||||
.stage2_x86_64 => 8,
|
||||
else => 16,
|
||||
},
|
||||
.x86_64 => 16,
|
||||
|
||||
// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
|
||||
.x86,
|
||||
@ -1928,6 +1920,17 @@ pub fn isSlice(ty: Type, zcu: *const Zcu) bool {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {
|
||||
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
|
||||
.ptr_type => |ptr_type| ptr_type.flags.size == .slice,
|
||||
.opt_type => |child| switch (zcu.intern_pool.indexToKey(child)) {
|
||||
.ptr_type => |ptr_type| !ptr_type.flags.is_allowzero and ptr_type.flags.size == .slice,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {
|
||||
return Type.fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern()));
|
||||
}
|
||||
|
||||
@ -71,6 +71,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// We postpone the creation of debug info for function args and locals
|
||||
/// until after all Mir instructions have been generated. Only then we
|
||||
/// will know saved_regs_stack_space which is necessary in order to
|
||||
@ -646,6 +648,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.add => try self.airBinOp(inst, .add),
|
||||
@ -927,16 +930,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -3614,7 +3614,7 @@ fn reuseOperand(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
@ -72,6 +72,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// We postpone the creation of debug info for function args and locals
|
||||
/// until after all Mir instructions have been generated. Only then we
|
||||
/// will know saved_regs_stack_space which is necessary in order to
|
||||
@ -635,6 +637,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.add, => try self.airBinOp(inst, .add),
|
||||
@ -918,16 +921,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -2650,7 +2650,7 @@ fn reuseOperand(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
@ -82,6 +82,8 @@ scope_generation: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// Whenever there is a runtime branch, we push a Branch onto this stack,
|
||||
/// and pop it off when the runtime branch joins. This provides an "overlay"
|
||||
/// of the table of mappings from instructions to `MCValue` from within the branch.
|
||||
@ -1443,8 +1445,11 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
|
||||
verbose_tracking_log.debug("{}", .{func.fmtTracking()});
|
||||
|
||||
const old_air_bookkeeping = func.air_bookkeeping;
|
||||
try func.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
func.reused_operands = @TypeOf(func.reused_operands).initEmpty();
|
||||
try func.inst_tracking.ensureUnusedCapacity(func.gpa, 1);
|
||||
const tag: Air.Inst.Tag = air_tags[@intFromEnum(inst)];
|
||||
const tag = air_tags[@intFromEnum(inst)];
|
||||
switch (tag) {
|
||||
// zig fmt: off
|
||||
.add,
|
||||
@ -1783,11 +1788,10 @@ fn finishAir(
|
||||
result: MCValue,
|
||||
operands: [Liveness.bpi - 1]Air.Inst.Ref,
|
||||
) !void {
|
||||
var tomb_bits = func.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const tomb_bits = func.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (func.reused_operands.isSet(op_index)) continue;
|
||||
try func.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
func.finishAirResult(inst, result);
|
||||
@ -4424,7 +4428,7 @@ fn reuseOperandAdvanced(
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
func.liveness.clearOperandDeath(inst, op_index);
|
||||
func.reused_operands.set(op_index);
|
||||
const op_inst = operand.toIndex().?;
|
||||
func.getResolvedInstValue(op_inst).reuse(func, maybe_tracked_inst, op_inst);
|
||||
|
||||
|
||||
@ -78,6 +78,8 @@ end_di_column: u32,
|
||||
/// which is a relative jump, based on the address following the reloc.
|
||||
exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .empty,
|
||||
|
||||
reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
|
||||
|
||||
/// Whenever there is a runtime branch, we push a Branch onto this stack,
|
||||
/// and pop it off when the runtime branch joins. This provides an "overlay"
|
||||
/// of the table of mappings from instructions to `MCValue` from within the branch.
|
||||
@ -493,6 +495,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
const old_air_bookkeeping = self.air_bookkeeping;
|
||||
try self.ensureProcessDeathCapacity(Liveness.bpi);
|
||||
|
||||
self.reused_operands = @TypeOf(self.reused_operands).initEmpty();
|
||||
switch (air_tags[@intFromEnum(inst)]) {
|
||||
// zig fmt: off
|
||||
.ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
|
||||
@ -3523,16 +3526,13 @@ fn finishAirBookkeeping(self: *Self) void {
|
||||
}
|
||||
|
||||
fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Liveness.bpi - 1]Air.Inst.Ref) void {
|
||||
var tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (operands) |op| {
|
||||
const dies = @as(u1, @truncate(tomb_bits)) != 0;
|
||||
tomb_bits >>= 1;
|
||||
if (!dies) continue;
|
||||
const op_index = op.toIndex() orelse continue;
|
||||
self.processDeath(op_index);
|
||||
const tomb_bits = self.liveness.getTombBits(inst);
|
||||
for (0.., operands) |op_index, op| {
|
||||
if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
|
||||
if (self.reused_operands.isSet(op_index)) continue;
|
||||
self.processDeath(op.toIndexAllowNone() orelse continue);
|
||||
}
|
||||
const is_used = @as(u1, @truncate(tomb_bits)) == 0;
|
||||
if (is_used) {
|
||||
if (tomb_bits & 1 << (Liveness.bpi - 1) == 0) {
|
||||
log.debug("%{d} => {}", .{ inst, result });
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
|
||||
@ -4568,7 +4568,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
|
||||
}
|
||||
|
||||
// Prevent the operand deaths processing code from deallocating it.
|
||||
self.liveness.clearOperandDeath(inst, op_index);
|
||||
self.reused_operands.set(op_index);
|
||||
|
||||
// That makes us responsible for doing the rest of the stuff that processDeath would have done.
|
||||
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -38,8 +38,36 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
|
||||
const enc = try dis.parseEncoding(prefixes) orelse return error.UnknownOpcode;
|
||||
switch (enc.data.op_en) {
|
||||
.zo => return inst(enc, .{}),
|
||||
.d, .i => {
|
||||
.z => return inst(enc, .{}),
|
||||
.o => {
|
||||
const reg_low_enc: u3 = @truncate(dis.code[dis.pos - 1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = parseGpRegister(reg_low_enc, prefixes.rex.b, prefixes.rex, enc.data.ops[0].regBitSize()) },
|
||||
});
|
||||
},
|
||||
.zo => {
|
||||
const reg_low_enc: u3 = @truncate(dis.code[dis.pos - 1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = enc.data.ops[0].toReg() },
|
||||
.op2 = .{ .reg = parseGpRegister(reg_low_enc, prefixes.rex.b, prefixes.rex, enc.data.ops[1].regBitSize()) },
|
||||
});
|
||||
},
|
||||
.oz => {
|
||||
const reg_low_enc: u3 = @truncate(dis.code[dis.pos - 1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = parseGpRegister(reg_low_enc, prefixes.rex.b, prefixes.rex, enc.data.ops[0].regBitSize()) },
|
||||
.op2 = .{ .reg = enc.data.ops[1].toReg() },
|
||||
});
|
||||
},
|
||||
.oi => {
|
||||
const reg_low_enc: u3 = @truncate(dis.code[dis.pos - 1]);
|
||||
const imm = try dis.parseImm(enc.data.ops[1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = parseGpRegister(reg_low_enc, prefixes.rex.b, prefixes.rex, enc.data.ops[0].regBitSize()) },
|
||||
.op2 = .{ .imm = imm },
|
||||
});
|
||||
},
|
||||
.i, .d => {
|
||||
const imm = try dis.parseImm(enc.data.ops[0]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .imm = imm },
|
||||
@ -48,20 +76,10 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
.zi => {
|
||||
const imm = try dis.parseImm(enc.data.ops[1]);
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) },
|
||||
.op1 = .{ .reg = enc.data.ops[0].toReg() },
|
||||
.op2 = .{ .imm = imm },
|
||||
});
|
||||
},
|
||||
.o, .oi => {
|
||||
const reg_low_enc = @as(u3, @truncate(dis.code[dis.pos - 1]));
|
||||
const op2: Instruction.Operand = if (enc.data.op_en == .oi) .{
|
||||
.imm = try dis.parseImm(enc.data.ops[1]),
|
||||
} else .none;
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = parseGpRegister(reg_low_enc, prefixes.rex.b, prefixes.rex, enc.data.ops[0].regBitSize()) },
|
||||
.op2 = op2,
|
||||
});
|
||||
},
|
||||
.m, .mi, .m1, .mc => {
|
||||
const modrm = try dis.parseModRmByte();
|
||||
const act_enc = Encoding.findByOpcode(enc.opcode(), .{
|
||||
@ -118,7 +136,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
const seg = segmentRegister(prefixes.legacy);
|
||||
const offset = try dis.parseOffset();
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) },
|
||||
.op1 = .{ .reg = enc.data.ops[0].toReg() },
|
||||
.op2 = .{ .mem = Memory.initMoffs(seg, offset) },
|
||||
});
|
||||
},
|
||||
@ -127,7 +145,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
const offset = try dis.parseOffset();
|
||||
return inst(enc, .{
|
||||
.op1 = .{ .mem = Memory.initMoffs(seg, offset) },
|
||||
.op2 = .{ .reg = Register.rax.toBitSize(enc.data.ops[1].regBitSize()) },
|
||||
.op2 = .{ .reg = enc.data.ops[1].toReg() },
|
||||
});
|
||||
},
|
||||
.mr, .mri, .mrc => {
|
||||
@ -223,7 +241,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
|
||||
.op3 = op3,
|
||||
});
|
||||
},
|
||||
.rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, // TODO
|
||||
.rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable, // TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,22 +10,21 @@ prev_di_loc: Loc,
|
||||
/// Relative to the beginning of `code`.
|
||||
prev_di_pc: usize,
|
||||
|
||||
code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
|
||||
relocs: std.ArrayListUnmanaged(Reloc) = .empty,
|
||||
|
||||
pub const Error = Lower.Error || error{
|
||||
EmitFail,
|
||||
} || link.File.UpdateDebugInfoError;
|
||||
|
||||
pub fn emitMir(emit: *Emit) Error!void {
|
||||
const gpa = emit.lower.bin_file.comp.gpa;
|
||||
const code_offset_mapping = try emit.lower.allocator.alloc(u32, emit.lower.mir.instructions.len);
|
||||
defer emit.lower.allocator.free(code_offset_mapping);
|
||||
var relocs: std.ArrayListUnmanaged(Reloc) = .empty;
|
||||
defer relocs.deinit(emit.lower.allocator);
|
||||
var table_relocs: std.ArrayListUnmanaged(TableReloc) = .empty;
|
||||
defer table_relocs.deinit(emit.lower.allocator);
|
||||
for (0..emit.lower.mir.instructions.len) |mir_i| {
|
||||
const mir_index: Mir.Inst.Index = @intCast(mir_i);
|
||||
try emit.code_offset_mapping.putNoClobber(
|
||||
emit.lower.allocator,
|
||||
mir_index,
|
||||
@intCast(emit.code.items.len),
|
||||
);
|
||||
code_offset_mapping[mir_index] = @intCast(emit.code.items.len);
|
||||
const lowered = try emit.lower.lowerMir(mir_index);
|
||||
var lowered_relocs = lowered.relocs;
|
||||
for (lowered.insts, 0..) |lowered_inst, lowered_index| {
|
||||
@ -89,13 +88,17 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
lowered_relocs[0].lowered_inst_index == lowered_index) : ({
|
||||
lowered_relocs = lowered_relocs[1..];
|
||||
}) switch (lowered_relocs[0].target) {
|
||||
.inst => |target| try emit.relocs.append(emit.lower.allocator, .{
|
||||
.inst => |target| try relocs.append(emit.lower.allocator, .{
|
||||
.source = start_offset,
|
||||
.source_offset = end_offset - 4,
|
||||
.target = target,
|
||||
.target_offset = lowered_relocs[0].off,
|
||||
.length = @intCast(end_offset - start_offset),
|
||||
}),
|
||||
.table => try table_relocs.append(emit.lower.allocator, .{
|
||||
.source_offset = end_offset - 4,
|
||||
.target_offset = lowered_relocs[0].off,
|
||||
}),
|
||||
.linker_extern_fn => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
||||
// Add relocation to the decl.
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
@ -103,7 +106,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);
|
||||
try atom_ptr.addReloc(gpa, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
|
||||
.r_info = @as(u64, sym_index) << 32 | r_type,
|
||||
.r_addend = lowered_relocs[0].off - 4,
|
||||
}, zo);
|
||||
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
|
||||
@ -150,7 +153,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
|
||||
try atom.addReloc(gpa, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
|
||||
.r_info = @as(u64, sym_index) << 32 | r_type,
|
||||
.r_addend = lowered_relocs[0].off - 4,
|
||||
}, zo);
|
||||
},
|
||||
@ -161,7 +164,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
|
||||
try atom.addReloc(gpa, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
|
||||
.r_info = @as(u64, sym_index) << 32 | r_type,
|
||||
.r_addend = lowered_relocs[0].off,
|
||||
}, zo);
|
||||
},
|
||||
@ -176,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
@intFromEnum(std.elf.R_X86_64.PC32);
|
||||
try atom.addReloc(gpa, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
|
||||
.r_info = @as(u64, sym_index) << 32 | r_type,
|
||||
.r_addend = lowered_relocs[0].off - 4,
|
||||
}, zo);
|
||||
} else {
|
||||
@ -186,7 +189,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
@intFromEnum(std.elf.R_X86_64.@"32");
|
||||
try atom.addReloc(gpa, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
|
||||
.r_info = @as(u64, sym_index) << 32 | r_type,
|
||||
.r_addend = lowered_relocs[0].off,
|
||||
}, zo);
|
||||
}
|
||||
@ -412,7 +415,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
loc_buf[0] = switch (mem.base()) {
|
||||
.none => .{ .constu = 0 },
|
||||
.reg => |reg| .{ .breg = reg.dwarfNum() },
|
||||
.frame => unreachable,
|
||||
.frame, .table => unreachable,
|
||||
.reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },
|
||||
};
|
||||
break :base &loc_buf[0];
|
||||
@ -463,13 +466,40 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
}
|
||||
}
|
||||
}
|
||||
try emit.fixupRelocs();
|
||||
}
|
||||
{
|
||||
// TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
|
||||
// This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
|
||||
// possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
|
||||
// until the entire decl is correctly emitted with all JMP/CALL instructions within range.
|
||||
for (relocs.items) |reloc| {
|
||||
const target = code_offset_mapping[reloc.target];
|
||||
const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset;
|
||||
std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little);
|
||||
}
|
||||
}
|
||||
if (emit.lower.mir.table.len > 0) {
|
||||
if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
|
||||
|
||||
pub fn deinit(emit: *Emit) void {
|
||||
emit.relocs.deinit(emit.lower.allocator);
|
||||
emit.code_offset_mapping.deinit(emit.lower.allocator);
|
||||
emit.* = undefined;
|
||||
const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8);
|
||||
var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size);
|
||||
for (table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
|
||||
.r_offset = table_reloc.source_offset,
|
||||
.r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),
|
||||
.r_addend = @as(i64, table_offset) + table_reloc.target_offset,
|
||||
}, zo);
|
||||
for (emit.lower.mir.table) |entry| {
|
||||
try atom.addReloc(gpa, .{
|
||||
.r_offset = table_offset,
|
||||
.r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"64"),
|
||||
.r_addend = code_offset_mapping[entry],
|
||||
}, zo);
|
||||
table_offset += ptr_size;
|
||||
}
|
||||
try emit.code.appendNTimes(gpa, 0, table_offset - emit.code.items.len);
|
||||
} else unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
|
||||
@ -481,7 +511,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
|
||||
|
||||
const Reloc = struct {
|
||||
/// Offset of the instruction.
|
||||
source: usize,
|
||||
source: u32,
|
||||
/// Offset of the relocation within the instruction.
|
||||
source_offset: u32,
|
||||
/// Target of the relocation.
|
||||
@ -492,18 +522,12 @@ const Reloc = struct {
|
||||
length: u5,
|
||||
};
|
||||
|
||||
fn fixupRelocs(emit: *Emit) Error!void {
|
||||
// TODO this function currently assumes all relocs via JMP/CALL instructions are 32bit in size.
|
||||
// This should be reversed like it is done in aarch64 MIR emit code: start with the smallest
|
||||
// possible resolution, i.e., 8bit, and iteratively converge on the minimum required resolution
|
||||
// until the entire decl is correctly emitted with all JMP/CALL instructions within range.
|
||||
for (emit.relocs.items) |reloc| {
|
||||
const target = emit.code_offset_mapping.get(reloc.target) orelse
|
||||
return emit.fail("JMP/CALL relocation target not found!", .{});
|
||||
const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset;
|
||||
std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little);
|
||||
}
|
||||
}
|
||||
const TableReloc = struct {
|
||||
/// Offset of the relocation.
|
||||
source_offset: u32,
|
||||
/// Offset from the start of the table.
|
||||
target_offset: i32,
|
||||
};
|
||||
|
||||
const Loc = struct {
|
||||
line: u32,
|
||||
|
||||
@ -30,9 +30,10 @@ pub fn findByMnemonic(
|
||||
prefix: Instruction.Prefix,
|
||||
mnemonic: Mnemonic,
|
||||
ops: []const Instruction.Operand,
|
||||
target: *const std.Target,
|
||||
) !?Encoding {
|
||||
var input_ops = [1]Op{.none} ** 4;
|
||||
for (input_ops[0..ops.len], ops) |*input_op, op| input_op.* = Op.fromOperand(op);
|
||||
var input_ops: [4]Op = @splat(.none);
|
||||
for (input_ops[0..ops.len], ops) |*input_op, op| input_op.* = Op.fromOperand(op, target);
|
||||
|
||||
const rex_required = for (ops) |op| switch (op) {
|
||||
.reg => |r| switch (r) {
|
||||
@ -57,6 +58,16 @@ pub fn findByMnemonic(
|
||||
var shortest_enc: ?Encoding = null;
|
||||
var shortest_len: ?usize = null;
|
||||
next: for (mnemonic_to_encodings_map[@intFromEnum(mnemonic)]) |data| {
|
||||
if (!switch (data.feature) {
|
||||
.none => true,
|
||||
inline else => |tag| has_features: {
|
||||
comptime var feature_it = std.mem.splitScalar(u8, @tagName(tag), ' ');
|
||||
comptime var features: []const std.Target.x86.Feature = &.{};
|
||||
inline while (comptime feature_it.next()) |feature| features = features ++ .{@field(std.Target.x86.Feature, feature)};
|
||||
break :has_features std.Target.x86.featureSetHasAll(target.cpu.features, features[0..].*);
|
||||
},
|
||||
}) continue;
|
||||
|
||||
switch (data.mode) {
|
||||
.none, .short => if (rex_required) continue,
|
||||
.rex, .rex_short => if (!rex_required) continue,
|
||||
@ -64,7 +75,7 @@ pub fn findByMnemonic(
|
||||
}
|
||||
for (input_ops, data.ops) |input_op, data_op| if (!input_op.isSubset(data_op)) continue :next;
|
||||
|
||||
const enc = Encoding{ .mnemonic = mnemonic, .data = data };
|
||||
const enc: Encoding = .{ .mnemonic = mnemonic, .data = data };
|
||||
if (shortest_enc) |previous_shortest_enc| {
|
||||
const len = estimateInstructionLength(prefix, enc, ops);
|
||||
const previous_shortest_len = shortest_len orelse
|
||||
@ -165,9 +176,14 @@ pub fn format(
|
||||
for (opc) |byte| try writer.print("{x:0>2} ", .{byte});
|
||||
|
||||
switch (encoding.data.op_en) {
|
||||
.zo, .fd, .td, .i, .zi, .d => {},
|
||||
.o, .oi => {
|
||||
const tag = switch (encoding.data.ops[0]) {
|
||||
.z, .fd, .td, .i, .zi, .d => {},
|
||||
.o, .zo, .oz, .oi => {
|
||||
const op = switch (encoding.data.op_en) {
|
||||
.o, .oz, .oi => encoding.data.ops[0],
|
||||
.zo => encoding.data.ops[1],
|
||||
else => unreachable,
|
||||
};
|
||||
const tag = switch (op) {
|
||||
.r8 => "rb",
|
||||
.r16 => "rw",
|
||||
.r32 => "rd",
|
||||
@ -177,7 +193,7 @@ pub fn format(
|
||||
try writer.print("+{s} ", .{tag});
|
||||
},
|
||||
.m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}),
|
||||
.mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr => try writer.writeAll("/r "),
|
||||
.mr, .rm, .rmi, .mri, .mrc, .rm0, .rvm, .rvmr, .rvmi, .mvr, .rmv => try writer.writeAll("/r "),
|
||||
}
|
||||
|
||||
switch (encoding.data.op_en) {
|
||||
@ -202,7 +218,7 @@ pub fn format(
|
||||
try writer.print("{s} ", .{tag});
|
||||
},
|
||||
.rvmr => try writer.writeAll("/is4 "),
|
||||
.zo, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr => {},
|
||||
.z, .fd, .td, .o, .zo, .oz, .m, .m1, .mc, .mr, .rm, .mrc, .rm0, .rvm, .mvr, .rmv => {},
|
||||
}
|
||||
|
||||
try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
|
||||
@ -239,7 +255,8 @@ pub const Mnemonic = enum {
|
||||
// General-purpose
|
||||
adc, add, @"and",
|
||||
bsf, bsr, bswap, bt, btc, btr, bts,
|
||||
call, cbw, cdq, cdqe, clflush,
|
||||
call, cbw, cdq, cdqe,
|
||||
clac, clc, cld, clflush, cli, clts, clui,
|
||||
cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna,
|
||||
cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno,
|
||||
cmovnp, cmovns, cmovnz, cmovo, cmovp, cmovpe, cmovpo, cmovs, cmovz,
|
||||
@ -260,10 +277,12 @@ pub const Mnemonic = enum {
|
||||
neg, nop, not,
|
||||
@"or",
|
||||
pause, pop, popcnt, popfq, push, pushfq,
|
||||
rcl, rcr, ret, rol, ror,
|
||||
sal, sar, sbb,
|
||||
rcl, rcr, ret, rol, ror, rorx,
|
||||
sal, sar, sarx, sbb,
|
||||
scas, scasb, scasd, scasq, scasw,
|
||||
shl, shld, shr, shrd, sub, syscall,
|
||||
shl, shld, shlx, shr, shrd, shrx,
|
||||
stac, stc, std, sti, stui,
|
||||
sub, syscall,
|
||||
seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
|
||||
setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
|
||||
setnz, seto, setp, setpe, setpo, sets, setz,
|
||||
@ -296,7 +315,7 @@ pub const Mnemonic = enum {
|
||||
ldmxcsr,
|
||||
maxps, maxss,
|
||||
minps, minss,
|
||||
movaps, movhlps, movlhps,
|
||||
movaps, movhlps, movhps, movlhps, movlps,
|
||||
movmskps,
|
||||
movss, movups,
|
||||
mulps, mulss,
|
||||
@ -322,6 +341,7 @@ pub const Mnemonic = enum {
|
||||
minpd, minsd,
|
||||
movapd,
|
||||
movdqa, movdqu,
|
||||
movhpd, movlpd,
|
||||
movmskpd,
|
||||
//movsd,
|
||||
movupd,
|
||||
@ -353,6 +373,7 @@ pub const Mnemonic = enum {
|
||||
pmovsxbd, pmovsxbq, pmovsxbw, pmovsxdq, pmovsxwd, pmovsxwq,
|
||||
pmovzxbd, pmovzxbq, pmovzxbw, pmovzxdq, pmovzxwd, pmovzxwq,
|
||||
pmulld,
|
||||
ptest,
|
||||
roundpd, roundps, roundsd, roundss,
|
||||
// SSE4.2
|
||||
pcmpgtq,
|
||||
@ -383,7 +404,7 @@ pub const Mnemonic = enum {
|
||||
vmovd,
|
||||
vmovddup,
|
||||
vmovdqa, vmovdqu,
|
||||
vmovhlps, vmovlhps,
|
||||
vmovhlps, vmovhpd, vmovhps, vmovlhps, vmovlpd, vmovlps,
|
||||
vmovmskpd, vmovmskps,
|
||||
vmovq,
|
||||
vmovsd,
|
||||
@ -413,6 +434,7 @@ pub const Mnemonic = enum {
|
||||
vpsrad, vpsraq, vpsraw,
|
||||
vpsrld, vpsrldq, vpsrlq, vpsrlw,
|
||||
vpsubb, vpsubd, vpsubq, vpsubsb, vpsubsw, vpsubusb, vpsubusw, vpsubw,
|
||||
vptest,
|
||||
vpunpckhbw, vpunpckhdq, vpunpckhqdq, vpunpckhwd,
|
||||
vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
|
||||
vpxor,
|
||||
@ -421,6 +443,7 @@ pub const Mnemonic = enum {
|
||||
vsqrtpd, vsqrtps, vsqrtsd, vsqrtss,
|
||||
vstmxcsr,
|
||||
vsubpd, vsubps, vsubsd, vsubss,
|
||||
vtestpd, vtestps,
|
||||
vxorpd, vxorps,
|
||||
// F16C
|
||||
vcvtph2ps, vcvtps2ph,
|
||||
@ -437,14 +460,14 @@ pub const Mnemonic = enum {
|
||||
|
||||
pub const OpEn = enum {
|
||||
// zig fmt: off
|
||||
zo,
|
||||
o, oi,
|
||||
z,
|
||||
o, zo, oz, oi,
|
||||
i, zi,
|
||||
d, m,
|
||||
fd, td,
|
||||
m1, mc, mi, mr, rm,
|
||||
rmi, mri, mrc,
|
||||
rm0, vmi, rvm, rvmr, rvmi, mvr,
|
||||
rm0, vmi, rvm, rvmr, rvmi, mvr, rmv,
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
@ -471,7 +494,7 @@ pub const Op = enum {
|
||||
ymm, ymm_m256,
|
||||
// zig fmt: on
|
||||
|
||||
pub fn fromOperand(operand: Instruction.Operand) Op {
|
||||
pub fn fromOperand(operand: Instruction.Operand, target: *const std.Target) Op {
|
||||
return switch (operand) {
|
||||
.none => .none,
|
||||
|
||||
@ -513,7 +536,7 @@ pub const Op = enum {
|
||||
|
||||
.mem => |mem| switch (mem) {
|
||||
.moffs => .moffs,
|
||||
.sib, .rip => switch (mem.bitSize()) {
|
||||
.sib, .rip => switch (mem.bitSize(target)) {
|
||||
0 => .m,
|
||||
8 => .m8,
|
||||
16 => .m16,
|
||||
@ -557,6 +580,21 @@ pub const Op = enum {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toReg(op: Op) Register {
|
||||
return switch (op) {
|
||||
else => .none,
|
||||
.al => .al,
|
||||
.ax => .ax,
|
||||
.eax => .eax,
|
||||
.rax => .rax,
|
||||
.cl => .cl,
|
||||
.rip => .rip,
|
||||
.eip => .eip,
|
||||
.ip => .ip,
|
||||
.xmm0 => .xmm0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn immBitSize(op: Op) u64 {
|
||||
return switch (op) {
|
||||
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
|
||||
@ -808,6 +846,8 @@ pub const Feature = enum {
|
||||
avx,
|
||||
avx2,
|
||||
bmi,
|
||||
bmi2,
|
||||
cmov,
|
||||
f16c,
|
||||
fma,
|
||||
lzcnt,
|
||||
@ -815,6 +855,7 @@ pub const Feature = enum {
|
||||
pclmul,
|
||||
@"pclmul avx",
|
||||
popcnt,
|
||||
smap,
|
||||
sse,
|
||||
sse2,
|
||||
sse3,
|
||||
@ -822,6 +863,7 @@ pub const Feature = enum {
|
||||
sse4_2,
|
||||
ssse3,
|
||||
sha,
|
||||
uintr,
|
||||
vaes,
|
||||
vpclmulqdq,
|
||||
x87,
|
||||
@ -831,7 +873,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
||||
var inst = Instruction{
|
||||
.prefix = prefix,
|
||||
.encoding = encoding,
|
||||
.ops = [1]Operand{.none} ** 4,
|
||||
.ops = @splat(.none),
|
||||
};
|
||||
@memcpy(inst.ops[0..ops.len], ops);
|
||||
|
||||
@ -846,7 +888,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
|
||||
const mnemonic_to_encodings_map = init: {
|
||||
@setEvalBranchQuota(5_000);
|
||||
const mnemonic_count = @typeInfo(Mnemonic).@"enum".fields.len;
|
||||
var mnemonic_map: [mnemonic_count][]Data = .{&.{}} ** mnemonic_count;
|
||||
var mnemonic_map: [mnemonic_count][]Data = @splat(&.{});
|
||||
const encodings = @import("encodings.zig");
|
||||
for (encodings.table) |entry| mnemonic_map[@intFromEnum(entry[0])].len += 1;
|
||||
var data_storage: [encodings.table.len]Data = undefined;
|
||||
@ -855,7 +897,7 @@ const mnemonic_to_encodings_map = init: {
|
||||
value.ptr = data_storage[storage_i..].ptr;
|
||||
storage_i += value.len;
|
||||
}
|
||||
var mnemonic_i: [mnemonic_count]usize = .{0} ** mnemonic_count;
|
||||
var mnemonic_i: [mnemonic_count]usize = @splat(0);
|
||||
const ops_len = @typeInfo(std.meta.FieldType(Data, .ops)).array.len;
|
||||
const opc_len = @typeInfo(std.meta.FieldType(Data, .opc)).array.len;
|
||||
for (encodings.table) |entry| {
|
||||
@ -872,7 +914,7 @@ const mnemonic_to_encodings_map = init: {
|
||||
i.* += 1;
|
||||
}
|
||||
const final_storage = data_storage;
|
||||
var final_map: [mnemonic_count][]const Data = .{&.{}} ** mnemonic_count;
|
||||
var final_map: [mnemonic_count][]const Data = @splat(&.{});
|
||||
storage_i = 0;
|
||||
for (&final_map, mnemonic_map) |*final_value, value| {
|
||||
final_value.* = final_storage[storage_i..][0..value.len];
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
//! This file contains the functionality for lowering x86_64 MIR to Instructions
|
||||
|
||||
bin_file: *link.File,
|
||||
target: *const std.Target,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
link_mode: std.builtin.LinkMode,
|
||||
pic: bool,
|
||||
@ -56,6 +57,7 @@ pub const Reloc = struct {
|
||||
|
||||
const Target = union(enum) {
|
||||
inst: Mir.Inst.Index,
|
||||
table,
|
||||
linker_reloc: u32,
|
||||
linker_tlsld: u32,
|
||||
linker_dtpoff: u32,
|
||||
@ -193,7 +195,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
.pseudo_probe_align_ri_s => {
|
||||
try lower.emit(.none, .@"test", &.{
|
||||
.{ .reg = inst.data.ri.r1 },
|
||||
.{ .imm = Immediate.s(@bitCast(inst.data.ri.i)) },
|
||||
.{ .imm = .s(@bitCast(inst.data.ri.i)) },
|
||||
});
|
||||
try lower.emit(.none, .jz, &.{
|
||||
.{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) },
|
||||
@ -229,14 +231,14 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
}
|
||||
try lower.emit(.none, .sub, &.{
|
||||
.{ .reg = inst.data.ri.r1 },
|
||||
.{ .imm = Immediate.s(@bitCast(inst.data.ri.i)) },
|
||||
.{ .imm = .s(@bitCast(inst.data.ri.i)) },
|
||||
});
|
||||
assert(lower.result_insts_len <= pseudo_probe_adjust_unrolled_max_insts);
|
||||
},
|
||||
.pseudo_probe_adjust_setup_rri_s => {
|
||||
try lower.emit(.none, .mov, &.{
|
||||
.{ .reg = inst.data.rri.r2.to32() },
|
||||
.{ .imm = Immediate.s(@bitCast(inst.data.rri.i)) },
|
||||
.{ .imm = .s(@bitCast(inst.data.rri.i)) },
|
||||
});
|
||||
try lower.emit(.none, .sub, &.{
|
||||
.{ .reg = inst.data.rri.r1 },
|
||||
@ -255,7 +257,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
});
|
||||
try lower.emit(.none, .sub, &.{
|
||||
.{ .reg = inst.data.rr.r2 },
|
||||
.{ .imm = Immediate.s(page_size) },
|
||||
.{ .imm = .s(page_size) },
|
||||
});
|
||||
try lower.emit(.none, .jae, &.{
|
||||
.{ .imm = lower.reloc(.{ .inst = index }, 0) },
|
||||
@ -347,7 +349,7 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
|
||||
return error.LowerFail;
|
||||
}
|
||||
|
||||
pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
pub fn imm(lower: *const Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
return switch (ops) {
|
||||
.rri_s,
|
||||
.ri_s,
|
||||
@ -355,7 +357,7 @@ pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
.mi_s,
|
||||
.rmi_s,
|
||||
.pseudo_dbg_local_ai_s,
|
||||
=> Immediate.s(@bitCast(i)),
|
||||
=> .s(@bitCast(i)),
|
||||
|
||||
.rrri,
|
||||
.rri_u,
|
||||
@ -368,18 +370,26 @@ pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
|
||||
.rrm,
|
||||
.rrmi,
|
||||
.pseudo_dbg_local_ai_u,
|
||||
=> Immediate.u(i),
|
||||
=> .u(i),
|
||||
|
||||
.ri_64,
|
||||
.pseudo_dbg_local_ai_64,
|
||||
=> Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
|
||||
=> .u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
|
||||
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mem(lower: Lower, payload: u32) Memory {
|
||||
return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
|
||||
pub fn mem(lower: *Lower, payload: u32) Memory {
|
||||
var m = lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
|
||||
switch (m) {
|
||||
.sib => |*sib| switch (sib.base) {
|
||||
else => {},
|
||||
.table => sib.disp = lower.reloc(.table, sib.disp).signed,
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate {
|
||||
@ -389,7 +399,7 @@ fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate {
|
||||
.off = off,
|
||||
};
|
||||
lower.result_relocs_len += 1;
|
||||
return Immediate.s(0);
|
||||
return .s(0);
|
||||
}
|
||||
|
||||
fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
|
||||
@ -417,19 +427,17 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
// Here, we currently assume local dynamic TLS vars, and so
|
||||
// we emit LD model.
|
||||
_ = lower.reloc(.{ .linker_tlsld = sym_index }, 0);
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .lea, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .lea, &.{
|
||||
.{ .reg = .rdi },
|
||||
.{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
_ = lower.reloc(.{
|
||||
.linker_extern_fn = try elf_file.getGlobalSymbol("__tls_get_addr", null),
|
||||
}, 0);
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .call, &[_]Operand{
|
||||
.{ .imm = Immediate.s(0) },
|
||||
});
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .call, &.{
|
||||
.{ .imm = .s(0) },
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
_ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0);
|
||||
emit_mnemonic = .lea;
|
||||
@ -439,11 +447,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
}) };
|
||||
} else {
|
||||
// Since we are linking statically, we emit LE model directly.
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .mov, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .fs } }) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
_ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
|
||||
emit_mnemonic = .lea;
|
||||
@ -463,11 +470,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
.mov => {
|
||||
if (elf_sym.flags.is_extern_ptr) {
|
||||
const reg = ops[0].reg;
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .mov, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{
|
||||
.{ .reg = reg.to64() },
|
||||
.{ .mem = Memory.initRip(.qword, 0) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{
|
||||
.reg = reg.to64(),
|
||||
@ -482,7 +488,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
}) },
|
||||
.lea => {
|
||||
emit_mnemonic = .mov;
|
||||
break :op .{ .imm = Immediate.s(0) };
|
||||
break :op .{ .imm = .s(0) };
|
||||
},
|
||||
.mov => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{
|
||||
.base = .{ .reg = .ds },
|
||||
@ -495,16 +501,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
|
||||
if (macho_sym.flags.tlv) {
|
||||
_ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .mov, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{
|
||||
.{ .reg = .rdi },
|
||||
.{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .call, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .call, &.{
|
||||
.{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .rdi } }) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
emit_mnemonic = .mov;
|
||||
break :op .{ .reg = .rax };
|
||||
@ -519,11 +523,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
.mov => {
|
||||
if (macho_sym.flags.is_extern_ptr) {
|
||||
const reg = ops[0].reg;
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(.none, .mov, &[_]Operand{
|
||||
lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{
|
||||
.{ .reg = reg.to64() },
|
||||
.{ .mem = Memory.initRip(.qword, 0) },
|
||||
});
|
||||
}, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{
|
||||
.reg = reg.to64(),
|
||||
@ -540,8 +543,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
||||
},
|
||||
};
|
||||
}
|
||||
lower.result_insts[lower.result_insts_len] =
|
||||
try Instruction.new(emit_prefix, emit_mnemonic, emit_ops);
|
||||
lower.result_insts[lower.result_insts_len] = try .new(emit_prefix, emit_mnemonic, emit_ops, lower.target);
|
||||
lower.result_insts_len += 1;
|
||||
}
|
||||
|
||||
@ -743,7 +745,7 @@ fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Er
|
||||
while (it.next()) |i| {
|
||||
try lower.emit(.directive, .@".cfi_rel_offset", &.{
|
||||
.{ .reg = callee_preserved_regs[i] },
|
||||
.{ .imm = Immediate.s(off) },
|
||||
.{ .imm = .s(off) },
|
||||
});
|
||||
off += 8;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
extra: []const u32,
|
||||
table: []const Inst.Index,
|
||||
frame_locs: std.MultiArrayList(FrameLoc).Slice,
|
||||
|
||||
pub const Inst = struct {
|
||||
@ -22,17 +23,26 @@ pub const Inst = struct {
|
||||
/// ___
|
||||
@"_",
|
||||
|
||||
/// Integer __
|
||||
/// Integer ___
|
||||
i_,
|
||||
|
||||
/// ___ Left
|
||||
_l,
|
||||
/// ___ Left Double
|
||||
_ld,
|
||||
/// ___ Left Without Affecting Flags
|
||||
_lx,
|
||||
/// ___ Right
|
||||
_r,
|
||||
/// ___ Right Double
|
||||
_rd,
|
||||
/// ___ Right Without Affecting Flags
|
||||
_rx,
|
||||
|
||||
/// ___ Forward
|
||||
_f,
|
||||
/// ___ Reverse
|
||||
//_r,
|
||||
|
||||
/// ___ Above
|
||||
_a,
|
||||
@ -43,6 +53,7 @@ pub const Inst = struct {
|
||||
/// ___ Below Or Equal
|
||||
_be,
|
||||
/// ___ Carry
|
||||
/// ___ Carry Flag
|
||||
_c,
|
||||
/// ___ Equal
|
||||
_e,
|
||||
@ -94,6 +105,14 @@ pub const Inst = struct {
|
||||
_s,
|
||||
/// ___ Zero
|
||||
_z,
|
||||
/// ___ Alignment Check Flag
|
||||
_ac,
|
||||
/// ___ Direction Flag
|
||||
//_d,
|
||||
/// ___ Interrupt Flag
|
||||
_i,
|
||||
/// ___ User Interrupt Flag
|
||||
_ui,
|
||||
|
||||
/// ___ Byte
|
||||
//_b,
|
||||
@ -210,6 +229,10 @@ pub const Inst = struct {
|
||||
p_q,
|
||||
/// Packed ___ Double Quadword
|
||||
p_dq,
|
||||
/// ___ Aligned Packed Integer Values
|
||||
_dqa,
|
||||
/// ___ Unaligned Packed Integer Values
|
||||
_dqu,
|
||||
|
||||
/// ___ Scalar Single-Precision Values
|
||||
_ss,
|
||||
@ -230,6 +253,10 @@ pub const Inst = struct {
|
||||
v_d,
|
||||
/// VEX-Encoded ___ QuadWord
|
||||
v_q,
|
||||
/// VEX-Encoded ___ Aligned Packed Integer Values
|
||||
v_dqa,
|
||||
/// VEX-Encoded ___ Unaligned Packed Integer Values
|
||||
v_dqu,
|
||||
/// VEX-Encoded ___ Integer Data
|
||||
v_i128,
|
||||
/// VEX-Encoded Packed ___
|
||||
@ -287,9 +314,8 @@ pub const Inst = struct {
|
||||
/// Bitwise logical and of packed double-precision floating-point values
|
||||
@"and",
|
||||
/// Bit scan forward
|
||||
bsf,
|
||||
/// Bit scan reverse
|
||||
bsr,
|
||||
bs,
|
||||
/// Byte swap
|
||||
bswap,
|
||||
/// Bit test
|
||||
@ -305,6 +331,10 @@ pub const Inst = struct {
|
||||
cdq,
|
||||
/// Convert doubleword to quadword
|
||||
cdqe,
|
||||
/// Clear carry flag
|
||||
/// Clear direction flag
|
||||
/// Clear interrupt flag
|
||||
cl,
|
||||
/// Flush cache line
|
||||
clflush,
|
||||
/// Conditional move
|
||||
@ -358,6 +388,8 @@ pub const Inst = struct {
|
||||
/// Move scalar double-precision floating-point value
|
||||
/// Move doubleword
|
||||
/// Move quadword
|
||||
/// Move aligned packed integer values
|
||||
/// Move unaligned packed integer values
|
||||
mov,
|
||||
/// Move data after swapping bytes
|
||||
movbe,
|
||||
@ -401,9 +433,11 @@ pub const Inst = struct {
|
||||
ret,
|
||||
/// Rotate left
|
||||
/// Rotate right
|
||||
/// Rotate right logical without affecting flags
|
||||
ro,
|
||||
/// Arithmetic shift left
|
||||
/// Arithmetic shift right
|
||||
/// Shift left arithmetic without affecting flags
|
||||
sa,
|
||||
/// Integer subtraction with borrow
|
||||
sbb,
|
||||
@ -417,6 +451,8 @@ pub const Inst = struct {
|
||||
/// Double precision shift left
|
||||
/// Logical shift right
|
||||
/// Double precision shift right
|
||||
/// Shift left logical without affecting flags
|
||||
/// Shift right logical without affecting flags
|
||||
sh,
|
||||
/// Subtract
|
||||
/// Subtract packed integers
|
||||
@ -425,6 +461,11 @@ pub const Inst = struct {
|
||||
/// Subtract packed double-precision floating-point values
|
||||
/// Subtract scalar double-precision floating-point values
|
||||
sub,
|
||||
/// Set carry flag
|
||||
/// Set direction flag
|
||||
/// Set interrupt flag
|
||||
/// Store floating-point value
|
||||
st,
|
||||
/// Store string
|
||||
sto,
|
||||
/// Syscall
|
||||
@ -460,8 +501,6 @@ pub const Inst = struct {
|
||||
ldenv,
|
||||
/// Store x87 FPU environment
|
||||
nstenv,
|
||||
/// Store floating-point value
|
||||
st,
|
||||
/// Store x87 FPU environment
|
||||
stenv,
|
||||
|
||||
@ -542,8 +581,14 @@ pub const Inst = struct {
|
||||
/// Move aligned packed single-precision floating-point values
|
||||
/// Move aligned packed double-precision floating-point values
|
||||
mova,
|
||||
/// Move high packed single-precision floating-point values
|
||||
/// Move high packed double-precision floating-point values
|
||||
movh,
|
||||
/// Move packed single-precision floating-point values high to low
|
||||
movhl,
|
||||
/// Move low packed single-precision floating-point values
|
||||
/// Move low packed double-precision floating-point values
|
||||
movl,
|
||||
/// Move packed single-precision floating-point values low to high
|
||||
movlh,
|
||||
/// Move unaligned packed single-precision floating-point values
|
||||
@ -601,10 +646,6 @@ pub const Inst = struct {
|
||||
cvttps2dq,
|
||||
/// Convert with truncation scalar double-precision floating-point value to doubleword integer
|
||||
cvttsd2si,
|
||||
/// Move aligned packed integer values
|
||||
movdqa,
|
||||
/// Move unaligned packed integer values
|
||||
movdqu,
|
||||
/// Packed interleave shuffle of quadruplets of single-precision floating-point values
|
||||
/// Packed interleave shuffle of pairs of double-precision floating-point values
|
||||
/// Shuffle packed doublewords
|
||||
@ -1127,11 +1168,13 @@ pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 };
|
||||
|
||||
/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
|
||||
pub const RegisterList = struct {
|
||||
bitset: BitSet = BitSet.initEmpty(),
|
||||
bitset: BitSet,
|
||||
|
||||
const BitSet = IntegerBitSet(32);
|
||||
const Self = @This();
|
||||
|
||||
pub const empty: RegisterList = .{ .bitset = .initEmpty() };
|
||||
|
||||
fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
|
||||
for (registers, 0..) |cpreg, i| {
|
||||
if (reg.id() == cpreg.id()) return @intCast(i);
|
||||
@ -1157,8 +1200,12 @@ pub const RegisterList = struct {
|
||||
return @intCast(self.bitset.count());
|
||||
}
|
||||
|
||||
pub fn size(self: Self) i32 {
|
||||
return @intCast(self.bitset.count() * 8);
|
||||
pub fn size(self: Self, target: *const std.Target) i32 {
|
||||
return @intCast(self.bitset.count() * @as(u4, switch (target.cpu.arch) {
|
||||
else => unreachable,
|
||||
.x86 => 4,
|
||||
.x86_64 => 8,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1197,7 +1244,7 @@ pub const Memory = struct {
|
||||
size: bits.Memory.Size,
|
||||
index: Register,
|
||||
scale: bits.Memory.Scale,
|
||||
_: u16 = undefined,
|
||||
_: u15 = undefined,
|
||||
};
|
||||
|
||||
pub fn encode(mem: bits.Memory) Memory {
|
||||
@ -1220,7 +1267,7 @@ pub const Memory = struct {
|
||||
},
|
||||
},
|
||||
.base = switch (mem.base) {
|
||||
.none => undefined,
|
||||
.none, .table => undefined,
|
||||
.reg => |reg| @intFromEnum(reg),
|
||||
.frame => |frame_index| @intFromEnum(frame_index),
|
||||
.reloc => |sym_index| sym_index,
|
||||
@ -1249,6 +1296,7 @@ pub const Memory = struct {
|
||||
.none => .none,
|
||||
.reg => .{ .reg = @enumFromInt(mem.base) },
|
||||
.frame => .{ .frame = @enumFromInt(mem.base) },
|
||||
.table => .table,
|
||||
.reloc => .{ .reloc = mem.base },
|
||||
},
|
||||
.scale_index = switch (mem.info.index) {
|
||||
@ -1277,6 +1325,7 @@ pub const Memory = struct {
|
||||
pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
|
||||
mir.instructions.deinit(gpa);
|
||||
gpa.free(mir.extra);
|
||||
gpa.free(mir.table);
|
||||
mir.frame_locs.deinit(gpa);
|
||||
mir.* = undefined;
|
||||
}
|
||||
@ -1312,7 +1361,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
|
||||
|
||||
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
|
||||
return switch (mem.info.base) {
|
||||
.none, .reg, .reloc => mem,
|
||||
.none, .reg, .table, .reloc => mem,
|
||||
.frame => if (mir.frame_locs.len > 0) .{
|
||||
.info = .{
|
||||
.base = .reg,
|
||||
|
||||
@ -242,17 +242,20 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: std.Target, ctx: Context) [8
|
||||
.sse, .sseup, .sseup, .sseup,
|
||||
.sseup, .sseup, .sseup, .none,
|
||||
};
|
||||
// LLVM always returns vectors byval
|
||||
if (bits <= 512 or ctx == .ret) return .{
|
||||
if (bits <= 512 or (ctx == .ret and bits <= @as(u64, if (std.Target.x86.featureSetHas(target.cpu.features, .avx512f))
|
||||
2048
|
||||
else if (std.Target.x86.featureSetHas(target.cpu.features, .avx))
|
||||
1024
|
||||
else
|
||||
512))) return .{
|
||||
.sse, .sseup, .sseup, .sseup,
|
||||
.sseup, .sseup, .sseup, .sseup,
|
||||
};
|
||||
return memory_class;
|
||||
},
|
||||
.optional => {
|
||||
if (ty.isPtrLikeOptional(zcu)) {
|
||||
result[0] = .integer;
|
||||
return result;
|
||||
if (ty.optionalReprIsPayload(zcu)) {
|
||||
return classifySystemV(ty.optionalChild(zcu), zcu, target, ctx);
|
||||
}
|
||||
return memory_class;
|
||||
},
|
||||
@ -405,6 +408,31 @@ fn classifySystemVUnion(
|
||||
return starting_byte_offset + loaded_union.sizeUnordered(ip);
|
||||
}
|
||||
|
||||
pub const zigcc = struct {
|
||||
pub const stack_align: ?InternPool.Alignment = null;
|
||||
pub const return_in_regs = true;
|
||||
pub const params_in_regs = true;
|
||||
|
||||
const volatile_gpr = gp_regs.len - 5;
|
||||
const volatile_x87 = x87_regs.len - 1;
|
||||
const volatile_sse = sse_avx_regs.len;
|
||||
|
||||
/// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
|
||||
/// for anything else but stack offset tracking therefore we exclude them from this set.
|
||||
pub const callee_preserved_regs = gp_regs[volatile_gpr..] ++ x87_regs[volatile_x87 .. x87_regs.len - 1] ++ sse_avx_regs[volatile_sse..];
|
||||
/// These registers need to be preserved (saved on the stack) and restored by the caller before
|
||||
/// the caller relinquishes control to a subroutine via call instruction (or similar).
|
||||
/// In other words, these registers are free to use by the callee.
|
||||
pub const caller_preserved_regs = gp_regs[0..volatile_gpr] ++ x87_regs[0..volatile_x87] ++ sse_avx_regs[0..volatile_sse];
|
||||
|
||||
const int_param_regs = gp_regs[0 .. volatile_gpr - 1];
|
||||
const x87_param_regs = x87_regs[0..volatile_x87];
|
||||
const sse_param_regs = sse_avx_regs[0..volatile_sse];
|
||||
const int_return_regs = gp_regs[0..volatile_gpr];
|
||||
const x87_return_regs = x87_regs[0..volatile_x87];
|
||||
const sse_return_regs = sse_avx_regs[0..volatile_gpr];
|
||||
};
|
||||
|
||||
pub const SysV = struct {
|
||||
/// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
|
||||
/// for anything else but stack offset tracking therefore we exclude them from this set.
|
||||
@ -415,9 +443,11 @@ pub const SysV = struct {
|
||||
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
||||
|
||||
pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
|
||||
pub const c_abi_x87_param_regs = x87_regs[0..0].*;
|
||||
pub const c_abi_sse_param_regs = sse_avx_regs[0..8].*;
|
||||
pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
|
||||
pub const c_abi_sse_return_regs = sse_avx_regs[0..2].*;
|
||||
pub const c_abi_x87_return_regs = x87_regs[0..2].*;
|
||||
pub const c_abi_sse_return_regs = sse_avx_regs[0..4].*;
|
||||
};
|
||||
|
||||
pub const Win64 = struct {
|
||||
@ -430,74 +460,96 @@ pub const Win64 = struct {
|
||||
pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 } ++ x87_regs ++ sse_avx_regs;
|
||||
|
||||
pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
|
||||
pub const c_abi_x87_param_regs = x87_regs[0..0].*;
|
||||
pub const c_abi_sse_param_regs = sse_avx_regs[0..4].*;
|
||||
pub const c_abi_int_return_regs = [_]Register{.rax};
|
||||
pub const c_abi_x87_return_regs = x87_regs[0..0].*;
|
||||
pub const c_abi_sse_return_regs = sse_avx_regs[0..1].*;
|
||||
};
|
||||
|
||||
pub fn resolveCallingConvention(
|
||||
cc: std.builtin.CallingConvention,
|
||||
target: std.Target,
|
||||
) std.builtin.CallingConvention {
|
||||
return switch (cc) {
|
||||
.auto => switch (target.os.tag) {
|
||||
else => .{ .x86_64_sysv = .{} },
|
||||
.windows => .{ .x86_64_win = .{} },
|
||||
},
|
||||
else => cc,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCalleePreservedRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.callee_preserved_regs,
|
||||
.x86_64_sysv => &SysV.callee_preserved_regs,
|
||||
.x86_64_win => &Win64.callee_preserved_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCallerPreservedRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCallerPreservedRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.caller_preserved_regs,
|
||||
.x86_64_sysv => &SysV.caller_preserved_regs,
|
||||
.x86_64_win => &Win64.caller_preserved_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCAbiIntParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.int_param_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_int_param_regs,
|
||||
.x86_64_win => &Win64.c_abi_int_param_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCAbiX87ParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.x87_param_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_x87_param_regs,
|
||||
.x86_64_win => &Win64.c_abi_x87_param_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiSseParamRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.sse_param_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_sse_param_regs,
|
||||
.x86_64_win => &Win64.c_abi_sse_param_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCAbiIntReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.int_return_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_int_return_regs,
|
||||
.x86_64_win => &Win64.c_abi_int_return_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention) []const Register {
|
||||
pub fn getCAbiX87ReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.x87_return_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_x87_return_regs,
|
||||
.x86_64_win => &Win64.c_abi_x87_return_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.sse_return_regs,
|
||||
.x86_64_sysv => &SysV.c_abi_sse_return_regs,
|
||||
.x86_64_win => &Win64.c_abi_sse_return_regs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCAbiLinkerScratchReg(cc: std.builtin.CallingConvention.Tag) Register {
|
||||
return switch (cc) {
|
||||
.auto => zigcc.int_return_regs[zigcc.int_return_regs.len - 1],
|
||||
.x86_64_sysv => SysV.c_abi_int_return_regs[0],
|
||||
.x86_64_win => Win64.c_abi_int_return_regs[0],
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
const gp_regs = [_]Register{
|
||||
.rax, .rcx, .rdx, .rbx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
|
||||
.rax, .rdx, .rbx, .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
|
||||
};
|
||||
const x87_regs = [_]Register{
|
||||
.st0, .st1, .st2, .st3, .st4, .st5, .st6, .st7,
|
||||
|
||||
@ -150,6 +150,31 @@ pub const Condition = enum(u5) {
|
||||
.nz_or_p => .z_and_np,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the equivalent condition when the operands are swapped.
|
||||
pub fn commute(cond: Condition) Condition {
|
||||
return switch (cond) {
|
||||
else => cond,
|
||||
.a => .b,
|
||||
.ae => .be,
|
||||
.b => .a,
|
||||
.be => .ae,
|
||||
.c => .a,
|
||||
.g => .l,
|
||||
.ge => .le,
|
||||
.l => .g,
|
||||
.le => .ge,
|
||||
.na => .nb,
|
||||
.nae => .nbe,
|
||||
.nb => .na,
|
||||
.nbe => .nae,
|
||||
.nc => .na,
|
||||
.ng => .nl,
|
||||
.nge => .nle,
|
||||
.nl => .ng,
|
||||
.nle => .nge,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Register = enum(u7) {
|
||||
@ -454,37 +479,41 @@ pub const RegisterOffset = struct { reg: Register, off: i32 = 0 };
|
||||
pub const SymbolOffset = struct { sym_index: u32, off: i32 = 0 };
|
||||
|
||||
pub const Memory = struct {
|
||||
base: Base,
|
||||
mod: Mod,
|
||||
base: Base = .none,
|
||||
mod: Mod = .{ .rm = .{} },
|
||||
|
||||
pub const Base = union(enum(u2)) {
|
||||
pub const Base = union(enum(u3)) {
|
||||
none,
|
||||
reg: Register,
|
||||
frame: FrameIndex,
|
||||
table,
|
||||
reloc: u32,
|
||||
|
||||
pub const Tag = @typeInfo(Base).@"union".tag_type.?;
|
||||
|
||||
pub fn isExtended(self: Base) bool {
|
||||
return switch (self) {
|
||||
.none, .frame, .reloc => false, // rsp, rbp, and rip are not extended
|
||||
.none, .frame, .table, .reloc => false, // rsp, rbp, and rip are not extended
|
||||
.reg => |reg| reg.isExtended(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Mod = union(enum(u1)) {
|
||||
rm: struct {
|
||||
size: Size,
|
||||
rm: Rm,
|
||||
off: u64,
|
||||
|
||||
pub const Rm = struct {
|
||||
size: Size = .none,
|
||||
index: Register = .none,
|
||||
scale: Scale = .@"1",
|
||||
disp: i32 = 0,
|
||||
},
|
||||
off: u64,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Size = enum(u4) {
|
||||
none,
|
||||
ptr,
|
||||
byte,
|
||||
word,
|
||||
dword,
|
||||
@ -521,9 +550,10 @@ pub const Memory = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitSize(s: Size) u64 {
|
||||
pub fn bitSize(s: Size, target: *const std.Target) u64 {
|
||||
return switch (s) {
|
||||
.none => 0,
|
||||
.ptr => target.ptrBitWidth(),
|
||||
.byte => 8,
|
||||
.word => 16,
|
||||
.dword => 32,
|
||||
@ -543,11 +573,50 @@ pub const Memory = struct {
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (s == .none) return;
|
||||
try writer.writeAll(@tagName(s));
|
||||
try writer.writeAll(" ptr");
|
||||
switch (s) {
|
||||
.none => unreachable,
|
||||
.ptr => {},
|
||||
else => {
|
||||
try writer.writeByte(' ');
|
||||
try writer.writeAll("ptr");
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Scale = enum(u2) { @"1", @"2", @"4", @"8" };
|
||||
pub const Scale = enum(u2) {
|
||||
@"1",
|
||||
@"2",
|
||||
@"4",
|
||||
@"8",
|
||||
|
||||
pub fn fromFactor(factor: u4) Scale {
|
||||
return switch (factor) {
|
||||
else => unreachable,
|
||||
1 => .@"1",
|
||||
2 => .@"2",
|
||||
4 => .@"4",
|
||||
8 => .@"8",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toFactor(scale: Scale) u4 {
|
||||
return switch (scale) {
|
||||
.@"1" => 1,
|
||||
.@"2" => 2,
|
||||
.@"4" => 4,
|
||||
.@"8" => 8,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromLog2(log2: u2) Scale {
|
||||
return @enumFromInt(log2);
|
||||
}
|
||||
|
||||
pub fn toLog2(scale: Scale) u2 {
|
||||
return @intFromEnum(scale);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Immediate = union(enum) {
|
||||
|
||||
@ -138,7 +138,7 @@ pub const Instruction = struct {
|
||||
.moffs => true,
|
||||
.rip => false,
|
||||
.sib => |s| switch (s.base) {
|
||||
.none, .frame, .reloc => false,
|
||||
.none, .frame, .table, .reloc => false,
|
||||
.reg => |reg| reg.class() == .segment,
|
||||
},
|
||||
};
|
||||
@ -161,17 +161,17 @@ pub const Instruction = struct {
|
||||
|
||||
pub fn disp(mem: Memory) Immediate {
|
||||
return switch (mem) {
|
||||
.sib => |s| Immediate.s(s.disp),
|
||||
.rip => |r| Immediate.s(r.disp),
|
||||
.moffs => |m| Immediate.u(m.offset),
|
||||
.sib => |s| .s(s.disp),
|
||||
.rip => |r| .s(r.disp),
|
||||
.moffs => |m| .u(m.offset),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitSize(mem: Memory) u64 {
|
||||
pub fn bitSize(mem: Memory, target: *const std.Target) u64 {
|
||||
return switch (mem) {
|
||||
.rip => |r| r.ptr_size.bitSize(),
|
||||
.sib => |s| s.ptr_size.bitSize(),
|
||||
.moffs => 64,
|
||||
.rip => |r| r.ptr_size.bitSize(target),
|
||||
.sib => |s| s.ptr_size.bitSize(target),
|
||||
.moffs => target.ptrBitWidth(),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -277,6 +277,7 @@ pub const Instruction = struct {
|
||||
.none => any = false,
|
||||
.reg => |reg| try writer.print("{s}", .{@tagName(reg)}),
|
||||
.frame => |frame_index| try writer.print("{}", .{frame_index}),
|
||||
.table => try writer.print("Table", .{}),
|
||||
.reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
|
||||
}
|
||||
if (mem.scaleIndex()) |si| {
|
||||
@ -314,28 +315,33 @@ pub const Instruction = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
|
||||
pub fn new(
|
||||
prefix: Prefix,
|
||||
mnemonic: Mnemonic,
|
||||
ops: []const Operand,
|
||||
target: *const std.Target,
|
||||
) !Instruction {
|
||||
const encoding: Encoding = switch (prefix) {
|
||||
else => (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
|
||||
else => (try Encoding.findByMnemonic(prefix, mnemonic, ops, target)) orelse {
|
||||
log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
|
||||
@tagName(prefix),
|
||||
@tagName(mnemonic),
|
||||
@tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
|
||||
@tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
|
||||
@tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
|
||||
@tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
|
||||
@tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0], target) else .none),
|
||||
@tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1], target) else .none),
|
||||
@tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2], target) else .none),
|
||||
@tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3], target) else .none),
|
||||
});
|
||||
return error.InvalidInstruction;
|
||||
},
|
||||
.directive => .{
|
||||
.mnemonic = mnemonic,
|
||||
.data = .{
|
||||
.op_en = .zo,
|
||||
.op_en = .z,
|
||||
.ops = .{
|
||||
if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none,
|
||||
if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none,
|
||||
if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none,
|
||||
if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none,
|
||||
if (ops.len > 0) Encoding.Op.fromOperand(ops[0], target) else .none,
|
||||
if (ops.len > 1) Encoding.Op.fromOperand(ops[1], target) else .none,
|
||||
if (ops.len > 2) Encoding.Op.fromOperand(ops[2], target) else .none,
|
||||
if (ops.len > 3) Encoding.Op.fromOperand(ops[3], target) else .none,
|
||||
},
|
||||
.opc_len = 0,
|
||||
.opc = undefined,
|
||||
@ -395,7 +401,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
|
||||
switch (data.op_en) {
|
||||
.zo, .o => {},
|
||||
.z, .o, .zo, .oz => {},
|
||||
.i, .d => try encodeImm(inst.ops[0].imm, data.ops[0], encoder),
|
||||
.zi, .oi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder),
|
||||
.fd => try encoder.imm64(inst.ops[1].mem.moffs.offset),
|
||||
@ -403,7 +409,7 @@ pub const Instruction = struct {
|
||||
else => {
|
||||
const mem_op = switch (data.op_en) {
|
||||
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
|
||||
.rm, .rmi, .rm0, .vmi => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
|
||||
.rvm, .rvmr, .rvmi => inst.ops[2],
|
||||
else => unreachable,
|
||||
};
|
||||
@ -412,7 +418,7 @@ pub const Instruction = struct {
|
||||
const rm = switch (data.op_en) {
|
||||
.m, .mi, .m1, .mc, .vmi => enc.modRmExt(),
|
||||
.mr, .mri, .mrc => inst.ops[1].reg.lowEnc(),
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0].reg.lowEnc(),
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(),
|
||||
.mvr => inst.ops[2].reg.lowEnc(),
|
||||
else => unreachable,
|
||||
};
|
||||
@ -422,7 +428,7 @@ pub const Instruction = struct {
|
||||
const op = switch (data.op_en) {
|
||||
.m, .mi, .m1, .mc, .vmi => .none,
|
||||
.mr, .mri, .mrc => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
|
||||
.mvr => inst.ops[2],
|
||||
else => unreachable,
|
||||
};
|
||||
@ -448,7 +454,8 @@ pub const Instruction = struct {
|
||||
const final = opcode.len - 1;
|
||||
for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte);
|
||||
switch (inst.encoding.data.op_en) {
|
||||
.o, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()),
|
||||
.o, .oz, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()),
|
||||
.zo => try encoder.opcode_withReg(opcode[final], inst.ops[1].reg.lowEnc()),
|
||||
else => try encoder.opcode_1byte(opcode[final]),
|
||||
}
|
||||
}
|
||||
@ -474,7 +481,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
|
||||
const segment_override: ?Register = switch (op_en) {
|
||||
.zo, .i, .zi, .o, .oi, .d => null,
|
||||
.z, .i, .zi, .o, .zo, .oz, .oi, .d => null,
|
||||
.fd => inst.ops[1].mem.base().reg,
|
||||
.td => inst.ops[0].mem.base().reg,
|
||||
.rm, .rmi, .rm0 => if (inst.ops[1].isSegmentRegister())
|
||||
@ -493,7 +500,7 @@ pub const Instruction = struct {
|
||||
}
|
||||
else
|
||||
null,
|
||||
.vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable,
|
||||
.vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => unreachable,
|
||||
};
|
||||
if (segment_override) |seg| {
|
||||
legacy.setSegmentOverride(seg);
|
||||
@ -510,11 +517,12 @@ pub const Instruction = struct {
|
||||
rex.w = inst.encoding.data.mode == .long;
|
||||
|
||||
switch (op_en) {
|
||||
.zo, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oi => rex.b = inst.ops[0].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0 => {
|
||||
.z, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oz, .oi => rex.b = inst.ops[0].reg.isExtended(),
|
||||
.zo => rex.b = inst.ops[1].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => {
|
||||
const r_op = switch (op_en) {
|
||||
.rm, .rmi, .rm0 => inst.ops[0],
|
||||
.rm, .rmi, .rm0, .rmv => inst.ops[0],
|
||||
.mr, .mri, .mrc => inst.ops[1],
|
||||
else => .none,
|
||||
};
|
||||
@ -544,11 +552,12 @@ pub const Instruction = struct {
|
||||
vex.w = inst.encoding.data.mode.isLong();
|
||||
|
||||
switch (op_en) {
|
||||
.zo, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oi => vex.b = inst.ops[0].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr => {
|
||||
.z, .i, .zi, .fd, .td, .d => {},
|
||||
.o, .oz, .oi => vex.b = inst.ops[0].reg.isExtended(),
|
||||
.zo => vex.b = inst.ops[1].reg.isExtended(),
|
||||
.m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .vmi, .rvm, .rvmr, .rvmi, .mvr, .rmv => {
|
||||
const r_op = switch (op_en) {
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi => inst.ops[0],
|
||||
.rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0],
|
||||
.mr, .mri, .mrc => inst.ops[1],
|
||||
.mvr => inst.ops[2],
|
||||
.m, .mi, .m1, .mc, .vmi => .none,
|
||||
@ -557,7 +566,7 @@ pub const Instruction = struct {
|
||||
vex.r = r_op.isBaseExtended();
|
||||
|
||||
const b_x_op = switch (op_en) {
|
||||
.rm, .rmi, .rm0, .vmi => inst.ops[1],
|
||||
.rm, .rmi, .rm0, .vmi, .rmv => inst.ops[1],
|
||||
.m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0],
|
||||
.rvm, .rvmr, .rvmi => inst.ops[2],
|
||||
else => unreachable,
|
||||
@ -588,6 +597,7 @@ pub const Instruction = struct {
|
||||
else => {},
|
||||
.vmi => vex.v = inst.ops[0].reg,
|
||||
.rvm, .rvmr, .rvmi => vex.v = inst.ops[1].reg,
|
||||
.rmv => vex.v = inst.ops[2].reg,
|
||||
}
|
||||
|
||||
try encoder.vex(vex);
|
||||
@ -608,7 +618,7 @@ pub const Instruction = struct {
|
||||
switch (mem) {
|
||||
.moffs => unreachable,
|
||||
.sib => |sib| switch (sib.base) {
|
||||
.none => {
|
||||
.none, .table => {
|
||||
try encoder.modRm_SIBDisp0(operand_enc);
|
||||
if (mem.scaleIndex()) |si| {
|
||||
const scale = math.log2_int(u4, si.scale);
|
||||
@ -676,11 +686,11 @@ pub const Instruction = struct {
|
||||
else => unreachable,
|
||||
},
|
||||
.frame => if (@TypeOf(encoder).options.allow_frame_locs) {
|
||||
try encoder.modRm_indirectDisp32(operand_enc, undefined);
|
||||
try encoder.modRm_indirectDisp32(operand_enc, 0);
|
||||
try encoder.disp32(undefined);
|
||||
} else return error.CannotEncode,
|
||||
.reloc => if (@TypeOf(encoder).options.allow_symbols) {
|
||||
try encoder.modRm_indirectDisp32(operand_enc, undefined);
|
||||
try encoder.modRm_indirectDisp32(operand_enc, 0);
|
||||
try encoder.disp32(undefined);
|
||||
} else return error.CannotEncode,
|
||||
},
|
||||
@ -1185,7 +1195,7 @@ const TestEncode = struct {
|
||||
) !void {
|
||||
var stream = std.io.fixedBufferStream(&enc.buffer);
|
||||
var count_writer = std.io.countingWriter(stream.writer());
|
||||
const inst = try Instruction.new(.none, mnemonic, ops);
|
||||
const inst: Instruction = try .new(.none, mnemonic, ops);
|
||||
try inst.encode(count_writer.writer(), .{});
|
||||
enc.index = count_writer.bytes_written;
|
||||
}
|
||||
@ -1199,9 +1209,9 @@ test "encode" {
|
||||
var buf = std.ArrayList(u8).init(testing.allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
const inst = try Instruction.new(.none, .mov, &.{
|
||||
const inst: Instruction = try .new(.none, .mov, &.{
|
||||
.{ .reg = .rbx },
|
||||
.{ .imm = Instruction.Immediate.u(4) },
|
||||
.{ .imm = .u(4) },
|
||||
});
|
||||
try inst.encode(buf.writer(), .{});
|
||||
try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
|
||||
@ -1211,47 +1221,47 @@ test "lower I encoding" {
|
||||
var enc = TestEncode{};
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
.{ .imm = .u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||
.{ .imm = .u(0x10000000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||
.{ .imm = .u(0x10000000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||
|
||||
try enc.encode(.sbb, &.{
|
||||
.{ .reg = .ax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
|
||||
|
||||
try enc.encode(.xor, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
|
||||
}
|
||||
@ -1261,43 +1271,43 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r12 },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
.{ .imm = .u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r12 },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
.{ .imm = .u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r12 },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
.{ .imm = .u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 } }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initRip(.qword, 0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
|
||||
@ -1307,19 +1317,19 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
|
||||
.{ .imm = Instruction.Immediate.s(-16) },
|
||||
.{ .imm = .s(-16) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
|
||||
|
||||
@ -1329,7 +1339,7 @@ test "lower MI encoding" {
|
||||
.disp = 0x10000000,
|
||||
.scale_index = .{ .scale = 2, .index = .rcx },
|
||||
}) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
|
||||
@ -1339,43 +1349,43 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .mem = Instruction.Memory.initRip(.qword, 0) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
||||
.{ .imm = Instruction.Immediate.s(-0x10) },
|
||||
.{ .imm = .s(-0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||
@ -1385,7 +1395,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x26\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||
@ -1395,7 +1405,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
|
||||
@ -1405,7 +1415,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x41\x83\xAB\x00\x00\x00\x10\x10",
|
||||
@ -1624,14 +1634,14 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .reg = .r12 },
|
||||
.{ .imm = Instruction.Immediate.s(-2) },
|
||||
.{ .imm = .s(-2) },
|
||||
});
|
||||
try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
|
||||
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Instruction.Memory.initRip(.qword, -16) },
|
||||
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||
.{ .imm = .s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
|
||||
@ -1642,7 +1652,7 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||
.{ .imm = .s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x66\x69\x5D\xF0\x00\xFC",
|
||||
@ -1653,7 +1663,7 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||
.{ .imm = Instruction.Immediate.u(1024) },
|
||||
.{ .imm = .u(1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x66\x69\x5D\xF0\x00\x04",
|
||||
@ -1769,7 +1779,7 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
|
||||
|
||||
try enc.encode(.call, &.{
|
||||
.{ .imm = Instruction.Immediate.s(0) },
|
||||
.{ .imm = .s(0) },
|
||||
});
|
||||
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
|
||||
|
||||
@ -1828,7 +1838,7 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = .u(0x1000000000000000) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||
@ -1838,7 +1848,7 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = .u(0x1000000000000000) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||
@ -1848,19 +1858,19 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11d },
|
||||
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||
.{ .imm = .u(0x10000000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11w },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
.{ .imm = .u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11b },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
.{ .imm = .u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
|
||||
}
|
||||
@ -1934,7 +1944,7 @@ test "lower NP encoding" {
|
||||
}
|
||||
|
||||
fn invalidInstruction(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
|
||||
const err = Instruction.new(.none, mnemonic, ops);
|
||||
const err: Instruction = .new(.none, mnemonic, ops);
|
||||
try testing.expectError(error.InvalidInstruction, err);
|
||||
}
|
||||
|
||||
@ -1982,12 +1992,12 @@ test "invalid instruction" {
|
||||
.{ .reg = .r12d },
|
||||
});
|
||||
try invalidInstruction(.push, &.{
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = .u(0x1000000000000000) },
|
||||
});
|
||||
}
|
||||
|
||||
fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand) !void {
|
||||
try testing.expectError(error.CannotEncode, Instruction.new(.none, mnemonic, ops));
|
||||
try testing.expectError(error.CannotEncode, .new(.none, mnemonic, ops));
|
||||
}
|
||||
|
||||
test "cannot encode" {
|
||||
@ -2171,7 +2181,7 @@ const Assembler = struct {
|
||||
|
||||
pub fn assemble(as: *Assembler, writer: anytype) !void {
|
||||
while (try as.next()) |parsed_inst| {
|
||||
const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
|
||||
const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
|
||||
try inst.encode(writer, .{});
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,106 +124,118 @@ pub const table = [_]Entry{
|
||||
.{ .call, .d, &.{ .rel32 }, &.{ 0xe8 }, 0, .none, .none },
|
||||
.{ .call, .m, &.{ .rm64 }, &.{ 0xff }, 2, .none, .none },
|
||||
|
||||
.{ .cbw, .zo, &.{ .o16 }, &.{ 0x98 }, 0, .short, .none },
|
||||
.{ .cwde, .zo, &.{ .o32 }, &.{ 0x98 }, 0, .none, .none },
|
||||
.{ .cdqe, .zo, &.{ .o64 }, &.{ 0x98 }, 0, .long, .none },
|
||||
.{ .cbw, .z, &.{ .o16 }, &.{ 0x98 }, 0, .short, .none },
|
||||
.{ .cwde, .z, &.{ .o32 }, &.{ 0x98 }, 0, .none, .none },
|
||||
.{ .cdqe, .z, &.{ .o64 }, &.{ 0x98 }, 0, .long, .none },
|
||||
|
||||
.{ .cwd, .zo, &.{ .o16 }, &.{ 0x99 }, 0, .short, .none },
|
||||
.{ .cdq, .zo, &.{ .o32 }, &.{ 0x99 }, 0, .none, .none },
|
||||
.{ .cqo, .zo, &.{ .o64 }, &.{ 0x99 }, 0, .long, .none },
|
||||
.{ .cwd, .z, &.{ .o16 }, &.{ 0x99 }, 0, .short, .none },
|
||||
.{ .cdq, .z, &.{ .o32 }, &.{ 0x99 }, 0, .none, .none },
|
||||
.{ .cqo, .z, &.{ .o64 }, &.{ 0x99 }, 0, .long, .none },
|
||||
|
||||
.{ .clac, .z, &.{}, &.{ 0x0f, 0x01, 0xca }, 0, .none, .smap },
|
||||
|
||||
.{ .clc, .z, &.{}, &.{ 0xf8 }, 0, .none, .none },
|
||||
|
||||
.{ .cld, .z, &.{}, &.{ 0xfc }, 0, .none, .none },
|
||||
|
||||
.{ .clflush, .m, &.{ .m8 }, &.{ 0x0f, 0xae }, 7, .none, .none },
|
||||
|
||||
.{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
|
||||
.{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
|
||||
.{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
|
||||
.{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
|
||||
.{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
|
||||
.{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
|
||||
.{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
|
||||
.{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
|
||||
.{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
|
||||
.{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
|
||||
.{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
|
||||
.{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
|
||||
.{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
|
||||
.{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
|
||||
.{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
|
||||
.{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
|
||||
.{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
|
||||
.{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
|
||||
.{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
|
||||
.{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
|
||||
.{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
|
||||
.{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
|
||||
.{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
|
||||
.{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
|
||||
.{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
|
||||
.{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
|
||||
.{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
|
||||
.{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
|
||||
.{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
|
||||
.{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
|
||||
.{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .none },
|
||||
.{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .none },
|
||||
.{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .none },
|
||||
.{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .none },
|
||||
.{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .none },
|
||||
.{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .none },
|
||||
.{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
|
||||
.{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
|
||||
.{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
|
||||
.{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .none },
|
||||
.{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .none },
|
||||
.{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .none },
|
||||
.{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .none },
|
||||
.{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .none },
|
||||
.{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .none },
|
||||
.{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
|
||||
.{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
|
||||
.{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
|
||||
.{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .none },
|
||||
.{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .none },
|
||||
.{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .none },
|
||||
.{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .none },
|
||||
.{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .none },
|
||||
.{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .none },
|
||||
.{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .none },
|
||||
.{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .none },
|
||||
.{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .none },
|
||||
.{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .none },
|
||||
.{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .none },
|
||||
.{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .none },
|
||||
.{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .short, .none },
|
||||
.{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none, .none },
|
||||
.{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long, .none },
|
||||
.{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
|
||||
.{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
|
||||
.{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
|
||||
.{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .short, .none },
|
||||
.{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none, .none },
|
||||
.{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long, .none },
|
||||
.{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .none },
|
||||
.{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .none },
|
||||
.{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .none },
|
||||
.{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .short, .none },
|
||||
.{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none, .none },
|
||||
.{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long, .none },
|
||||
.{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
|
||||
.{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
|
||||
.{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
|
||||
.{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .none },
|
||||
.{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .none },
|
||||
.{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .none },
|
||||
.{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .none },
|
||||
.{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .none },
|
||||
.{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .none },
|
||||
.{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .short, .none },
|
||||
.{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none, .none },
|
||||
.{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long, .none },
|
||||
.{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .none },
|
||||
.{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .none },
|
||||
.{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .none },
|
||||
.{ .cli, .z, &.{}, &.{ 0xfa }, 0, .none, .none },
|
||||
|
||||
.{ .clts, .z, &.{}, &.{ 0x0f, 0x06 }, 0, .none, .none },
|
||||
|
||||
.{ .clui, .z, &.{}, &.{ 0xf3, 0x0f, 0x01, 0xee }, 0, .none, .uintr },
|
||||
|
||||
.{ .cmova, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .cmov },
|
||||
.{ .cmova, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .cmov },
|
||||
.{ .cmova, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .cmov },
|
||||
.{ .cmovae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .cmov },
|
||||
.{ .cmovae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .cmov },
|
||||
.{ .cmovae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .cmov },
|
||||
.{ .cmovb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .cmov },
|
||||
.{ .cmovb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .cmov },
|
||||
.{ .cmovb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .cmov },
|
||||
.{ .cmovbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .cmov },
|
||||
.{ .cmovbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .cmov },
|
||||
.{ .cmovbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .cmov },
|
||||
.{ .cmovc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .cmov },
|
||||
.{ .cmovc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .cmov },
|
||||
.{ .cmovc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .cmov },
|
||||
.{ .cmove, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .cmov },
|
||||
.{ .cmove, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .cmov },
|
||||
.{ .cmove, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .cmov },
|
||||
.{ .cmovg, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .cmov },
|
||||
.{ .cmovg, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .cmov },
|
||||
.{ .cmovg, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .cmov },
|
||||
.{ .cmovge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .cmov },
|
||||
.{ .cmovge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .cmov },
|
||||
.{ .cmovge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .cmov },
|
||||
.{ .cmovl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .cmov },
|
||||
.{ .cmovl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .cmov },
|
||||
.{ .cmovl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .cmov },
|
||||
.{ .cmovle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .cmov },
|
||||
.{ .cmovle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .cmov },
|
||||
.{ .cmovle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .cmov },
|
||||
.{ .cmovna, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x46 }, 0, .short, .cmov },
|
||||
.{ .cmovna, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x46 }, 0, .none, .cmov },
|
||||
.{ .cmovna, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x46 }, 0, .long, .cmov },
|
||||
.{ .cmovnae, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x42 }, 0, .short, .cmov },
|
||||
.{ .cmovnae, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x42 }, 0, .none, .cmov },
|
||||
.{ .cmovnae, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x42 }, 0, .long, .cmov },
|
||||
.{ .cmovnb, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .cmov },
|
||||
.{ .cmovnb, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .cmov },
|
||||
.{ .cmovnb, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .cmov },
|
||||
.{ .cmovnbe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x47 }, 0, .short, .cmov },
|
||||
.{ .cmovnbe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x47 }, 0, .none, .cmov },
|
||||
.{ .cmovnbe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x47 }, 0, .long, .cmov },
|
||||
.{ .cmovnc, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x43 }, 0, .short, .cmov },
|
||||
.{ .cmovnc, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x43 }, 0, .none, .cmov },
|
||||
.{ .cmovnc, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x43 }, 0, .long, .cmov },
|
||||
.{ .cmovne, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .cmov },
|
||||
.{ .cmovne, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .cmov },
|
||||
.{ .cmovne, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .cmov },
|
||||
.{ .cmovng, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4e }, 0, .short, .cmov },
|
||||
.{ .cmovng, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4e }, 0, .none, .cmov },
|
||||
.{ .cmovng, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4e }, 0, .long, .cmov },
|
||||
.{ .cmovnge, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4c }, 0, .short, .cmov },
|
||||
.{ .cmovnge, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4c }, 0, .none, .cmov },
|
||||
.{ .cmovnge, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4c }, 0, .long, .cmov },
|
||||
.{ .cmovnl, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4d }, 0, .short, .cmov },
|
||||
.{ .cmovnl, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4d }, 0, .none, .cmov },
|
||||
.{ .cmovnl, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4d }, 0, .long, .cmov },
|
||||
.{ .cmovnle, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4f }, 0, .short, .cmov },
|
||||
.{ .cmovnle, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4f }, 0, .none, .cmov },
|
||||
.{ .cmovnle, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4f }, 0, .long, .cmov },
|
||||
.{ .cmovno, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x41 }, 0, .short, .cmov },
|
||||
.{ .cmovno, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x41 }, 0, .none, .cmov },
|
||||
.{ .cmovno, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x41 }, 0, .long, .cmov },
|
||||
.{ .cmovnp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .cmov },
|
||||
.{ .cmovnp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .cmov },
|
||||
.{ .cmovnp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .cmov },
|
||||
.{ .cmovns, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x49 }, 0, .short, .cmov },
|
||||
.{ .cmovns, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x49 }, 0, .none, .cmov },
|
||||
.{ .cmovns, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x49 }, 0, .long, .cmov },
|
||||
.{ .cmovnz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x45 }, 0, .short, .cmov },
|
||||
.{ .cmovnz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x45 }, 0, .none, .cmov },
|
||||
.{ .cmovnz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x45 }, 0, .long, .cmov },
|
||||
.{ .cmovo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x40 }, 0, .short, .cmov },
|
||||
.{ .cmovo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x40 }, 0, .none, .cmov },
|
||||
.{ .cmovo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x40 }, 0, .long, .cmov },
|
||||
.{ .cmovp, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .cmov },
|
||||
.{ .cmovp, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .cmov },
|
||||
.{ .cmovp, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .cmov },
|
||||
.{ .cmovpe, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4a }, 0, .short, .cmov },
|
||||
.{ .cmovpe, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4a }, 0, .none, .cmov },
|
||||
.{ .cmovpe, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4a }, 0, .long, .cmov },
|
||||
.{ .cmovpo, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x4b }, 0, .short, .cmov },
|
||||
.{ .cmovpo, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x4b }, 0, .none, .cmov },
|
||||
.{ .cmovpo, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x4b }, 0, .long, .cmov },
|
||||
.{ .cmovs, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x48 }, 0, .short, .cmov },
|
||||
.{ .cmovs, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x48 }, 0, .none, .cmov },
|
||||
.{ .cmovs, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x48 }, 0, .long, .cmov },
|
||||
.{ .cmovz, .rm, &.{ .r16, .rm16 }, &.{ 0x0f, 0x44 }, 0, .short, .cmov },
|
||||
.{ .cmovz, .rm, &.{ .r32, .rm32 }, &.{ 0x0f, 0x44 }, 0, .none, .cmov },
|
||||
.{ .cmovz, .rm, &.{ .r64, .rm64 }, &.{ 0x0f, 0x44 }, 0, .long, .cmov },
|
||||
|
||||
.{ .cmp, .zi, &.{ .al, .imm8 }, &.{ 0x3c }, 0, .none, .none },
|
||||
.{ .cmp, .zi, &.{ .ax, .imm16 }, &.{ 0x3d }, 0, .short, .none },
|
||||
@ -248,15 +260,15 @@ pub const table = [_]Entry{
|
||||
.{ .cmp, .rm, &.{ .r32, .rm32 }, &.{ 0x3b }, 0, .none, .none },
|
||||
.{ .cmp, .rm, &.{ .r64, .rm64 }, &.{ 0x3b }, 0, .long, .none },
|
||||
|
||||
.{ .cmps, .zo, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none, .none },
|
||||
.{ .cmps, .zo, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .short, .none },
|
||||
.{ .cmps, .zo, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none, .none },
|
||||
.{ .cmps, .zo, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long, .none },
|
||||
.{ .cmps, .z, &.{ .m8, .m8 }, &.{ 0xa6 }, 0, .none, .none },
|
||||
.{ .cmps, .z, &.{ .m16, .m16 }, &.{ 0xa7 }, 0, .short, .none },
|
||||
.{ .cmps, .z, &.{ .m32, .m32 }, &.{ 0xa7 }, 0, .none, .none },
|
||||
.{ .cmps, .z, &.{ .m64, .m64 }, &.{ 0xa7 }, 0, .long, .none },
|
||||
|
||||
.{ .cmpsb, .zo, &.{}, &.{ 0xa6 }, 0, .none, .none },
|
||||
.{ .cmpsw, .zo, &.{}, &.{ 0xa7 }, 0, .short, .none },
|
||||
.{ .cmpsd, .zo, &.{}, &.{ 0xa7 }, 0, .none, .none },
|
||||
.{ .cmpsq, .zo, &.{}, &.{ 0xa7 }, 0, .long, .none },
|
||||
.{ .cmpsb, .z, &.{}, &.{ 0xa6 }, 0, .none, .none },
|
||||
.{ .cmpsw, .z, &.{}, &.{ 0xa7 }, 0, .short, .none },
|
||||
.{ .cmpsd, .z, &.{}, &.{ 0xa7 }, 0, .none, .none },
|
||||
.{ .cmpsq, .z, &.{}, &.{ 0xa7 }, 0, .long, .none },
|
||||
|
||||
.{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .none, .none },
|
||||
.{ .cmpxchg, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xb0 }, 0, .rex, .none },
|
||||
@ -267,7 +279,7 @@ pub const table = [_]Entry{
|
||||
.{ .cmpxchg8b, .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none, .none },
|
||||
.{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long, .none },
|
||||
|
||||
.{ .cpuid, .zo, &.{}, &.{ 0x0f, 0xa2 }, 0, .none, .none },
|
||||
.{ .cpuid, .z, &.{}, &.{ 0x0f, 0xa2 }, 0, .none, .none },
|
||||
|
||||
.{ .dec, .m, &.{ .rm8 }, &.{ 0xfe }, 1, .none, .none },
|
||||
.{ .dec, .m, &.{ .rm8 }, &.{ 0xfe }, 1, .rex, .none },
|
||||
@ -308,7 +320,7 @@ pub const table = [_]Entry{
|
||||
.{ .inc, .m, &.{ .rm32 }, &.{ 0xff }, 0, .none, .none },
|
||||
.{ .inc, .m, &.{ .rm64 }, &.{ 0xff }, 0, .long, .none },
|
||||
|
||||
.{ .int3, .zo, &.{}, &.{ 0xcc }, 0, .none, .none },
|
||||
.{ .int3, .z, &.{}, &.{ 0xcc }, 0, .none, .none },
|
||||
|
||||
.{ .ja, .d, &.{ .rel32 }, &.{ 0x0f, 0x87 }, 0, .none, .none },
|
||||
.{ .jae, .d, &.{ .rel32 }, &.{ 0x0f, 0x83 }, 0, .none, .none },
|
||||
@ -349,23 +361,23 @@ pub const table = [_]Entry{
|
||||
.{ .lea, .rm, &.{ .r32, .m }, &.{ 0x8d }, 0, .none, .none },
|
||||
.{ .lea, .rm, &.{ .r64, .m }, &.{ 0x8d }, 0, .long, .none },
|
||||
|
||||
.{ .lfence, .zo, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none, .none },
|
||||
.{ .lfence, .z, &.{}, &.{ 0x0f, 0xae, 0xe8 }, 0, .none, .none },
|
||||
|
||||
.{ .lods, .zo, &.{ .m8 }, &.{ 0xac }, 0, .none, .none },
|
||||
.{ .lods, .zo, &.{ .m16 }, &.{ 0xad }, 0, .short, .none },
|
||||
.{ .lods, .zo, &.{ .m32 }, &.{ 0xad }, 0, .none, .none },
|
||||
.{ .lods, .zo, &.{ .m64 }, &.{ 0xad }, 0, .long, .none },
|
||||
.{ .lods, .z, &.{ .m8 }, &.{ 0xac }, 0, .none, .none },
|
||||
.{ .lods, .z, &.{ .m16 }, &.{ 0xad }, 0, .short, .none },
|
||||
.{ .lods, .z, &.{ .m32 }, &.{ 0xad }, 0, .none, .none },
|
||||
.{ .lods, .z, &.{ .m64 }, &.{ 0xad }, 0, .long, .none },
|
||||
|
||||
.{ .lodsb, .zo, &.{}, &.{ 0xac }, 0, .none, .none },
|
||||
.{ .lodsw, .zo, &.{}, &.{ 0xad }, 0, .short, .none },
|
||||
.{ .lodsd, .zo, &.{}, &.{ 0xad }, 0, .none, .none },
|
||||
.{ .lodsq, .zo, &.{}, &.{ 0xad }, 0, .long, .none },
|
||||
.{ .lodsb, .z, &.{}, &.{ 0xac }, 0, .none, .none },
|
||||
.{ .lodsw, .z, &.{}, &.{ 0xad }, 0, .short, .none },
|
||||
.{ .lodsd, .z, &.{}, &.{ 0xad }, 0, .none, .none },
|
||||
.{ .lodsq, .z, &.{}, &.{ 0xad }, 0, .long, .none },
|
||||
|
||||
.{ .lzcnt, .rm, &.{ .r16, .rm16 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .short, .lzcnt },
|
||||
.{ .lzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .none, .lzcnt },
|
||||
.{ .lzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbd }, 0, .long, .lzcnt },
|
||||
|
||||
.{ .mfence, .zo, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none, .none },
|
||||
.{ .mfence, .z, &.{}, &.{ 0x0f, 0xae, 0xf0 }, 0, .none, .none },
|
||||
|
||||
.{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .none, .none },
|
||||
.{ .mov, .mr, &.{ .rm8, .r8 }, &.{ 0x88 }, 0, .rex, .none },
|
||||
@ -409,15 +421,15 @@ pub const table = [_]Entry{
|
||||
.{ .movbe, .mr, &.{ .m32, .r32 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .none, .movbe },
|
||||
.{ .movbe, .mr, &.{ .m64, .r64 }, &.{ 0x0f, 0x38, 0xf1 }, 0, .long, .movbe },
|
||||
|
||||
.{ .movs, .zo, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none, .none },
|
||||
.{ .movs, .zo, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .short, .none },
|
||||
.{ .movs, .zo, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none, .none },
|
||||
.{ .movs, .zo, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long, .none },
|
||||
.{ .movs, .z, &.{ .m8, .m8 }, &.{ 0xa4 }, 0, .none, .none },
|
||||
.{ .movs, .z, &.{ .m16, .m16 }, &.{ 0xa5 }, 0, .short, .none },
|
||||
.{ .movs, .z, &.{ .m32, .m32 }, &.{ 0xa5 }, 0, .none, .none },
|
||||
.{ .movs, .z, &.{ .m64, .m64 }, &.{ 0xa5 }, 0, .long, .none },
|
||||
|
||||
.{ .movsb, .zo, &.{}, &.{ 0xa4 }, 0, .none, .none },
|
||||
.{ .movsw, .zo, &.{}, &.{ 0xa5 }, 0, .short, .none },
|
||||
.{ .movsd, .zo, &.{}, &.{ 0xa5 }, 0, .none, .none },
|
||||
.{ .movsq, .zo, &.{}, &.{ 0xa5 }, 0, .long, .none },
|
||||
.{ .movsb, .z, &.{}, &.{ 0xa4 }, 0, .none, .none },
|
||||
.{ .movsw, .z, &.{}, &.{ 0xa5 }, 0, .short, .none },
|
||||
.{ .movsd, .z, &.{}, &.{ 0xa5 }, 0, .none, .none },
|
||||
.{ .movsq, .z, &.{}, &.{ 0xa5 }, 0, .long, .none },
|
||||
|
||||
.{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .short, .none },
|
||||
.{ .movsx, .rm, &.{ .r16, .rm8 }, &.{ 0x0f, 0xbe }, 0, .rex_short, .none },
|
||||
@ -453,7 +465,7 @@ pub const table = [_]Entry{
|
||||
.{ .neg, .m, &.{ .rm32 }, &.{ 0xf7 }, 3, .none, .none },
|
||||
.{ .neg, .m, &.{ .rm64 }, &.{ 0xf7 }, 3, .long, .none },
|
||||
|
||||
.{ .nop, .zo, &.{}, &.{ 0x90 }, 0, .none, .none },
|
||||
.{ .nop, .z, &.{}, &.{ 0x90 }, 0, .none, .none },
|
||||
|
||||
.{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .none, .none },
|
||||
.{ .not, .m, &.{ .rm8 }, &.{ 0xf6 }, 2, .rex, .none },
|
||||
@ -484,7 +496,7 @@ pub const table = [_]Entry{
|
||||
.{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none, .none },
|
||||
.{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long, .none },
|
||||
|
||||
.{ .pause, .zo, &.{}, &.{ 0xf3, 0x90 }, 0, .none, .none },
|
||||
.{ .pause, .z, &.{}, &.{ 0xf3, 0x90 }, 0, .none, .none },
|
||||
|
||||
.{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .short, .none },
|
||||
.{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none, .none },
|
||||
@ -495,7 +507,7 @@ pub const table = [_]Entry{
|
||||
.{ .popcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .none, .popcnt },
|
||||
.{ .popcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xb8 }, 0, .long, .popcnt },
|
||||
|
||||
.{ .popfq, .zo, &.{}, &.{ 0x9d }, 0, .none, .none },
|
||||
.{ .popfq, .z, &.{}, &.{ 0x9d }, 0, .none, .none },
|
||||
|
||||
.{ .push, .o, &.{ .r16 }, &.{ 0x50 }, 0, .short, .none },
|
||||
.{ .push, .o, &.{ .r64 }, &.{ 0x50 }, 0, .none, .none },
|
||||
@ -505,9 +517,9 @@ pub const table = [_]Entry{
|
||||
.{ .push, .i, &.{ .imm16 }, &.{ 0x68 }, 0, .short, .none },
|
||||
.{ .push, .i, &.{ .imm32 }, &.{ 0x68 }, 0, .none, .none },
|
||||
|
||||
.{ .pushfq, .zo, &.{}, &.{ 0x9c }, 0, .none, .none },
|
||||
.{ .pushfq, .z, &.{}, &.{ 0x9c }, 0, .none, .none },
|
||||
|
||||
.{ .ret, .zo, &.{}, &.{ 0xc3 }, 0, .none, .none },
|
||||
.{ .ret, .z, &.{}, &.{ 0xc3 }, 0, .none, .none },
|
||||
|
||||
.{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .none, .none },
|
||||
.{ .rcl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 2, .rex, .none },
|
||||
@ -628,15 +640,15 @@ pub const table = [_]Entry{
|
||||
.{ .sbb, .rm, &.{ .r32, .rm32 }, &.{ 0x1b }, 0, .none, .none },
|
||||
.{ .sbb, .rm, &.{ .r64, .rm64 }, &.{ 0x1b }, 0, .long, .none },
|
||||
|
||||
.{ .scas, .zo, &.{ .m8 }, &.{ 0xae }, 0, .none, .none },
|
||||
.{ .scas, .zo, &.{ .m16 }, &.{ 0xaf }, 0, .short, .none },
|
||||
.{ .scas, .zo, &.{ .m32 }, &.{ 0xaf }, 0, .none, .none },
|
||||
.{ .scas, .zo, &.{ .m64 }, &.{ 0xaf }, 0, .long, .none },
|
||||
.{ .scas, .z, &.{ .m8 }, &.{ 0xae }, 0, .none, .none },
|
||||
.{ .scas, .z, &.{ .m16 }, &.{ 0xaf }, 0, .short, .none },
|
||||
.{ .scas, .z, &.{ .m32 }, &.{ 0xaf }, 0, .none, .none },
|
||||
.{ .scas, .z, &.{ .m64 }, &.{ 0xaf }, 0, .long, .none },
|
||||
|
||||
.{ .scasb, .zo, &.{}, &.{ 0xae }, 0, .none, .none },
|
||||
.{ .scasw, .zo, &.{}, &.{ 0xaf }, 0, .short, .none },
|
||||
.{ .scasd, .zo, &.{}, &.{ 0xaf }, 0, .none, .none },
|
||||
.{ .scasq, .zo, &.{}, &.{ 0xaf }, 0, .long, .none },
|
||||
.{ .scasb, .z, &.{}, &.{ 0xae }, 0, .none, .none },
|
||||
.{ .scasw, .z, &.{}, &.{ 0xaf }, 0, .short, .none },
|
||||
.{ .scasd, .z, &.{}, &.{ 0xaf }, 0, .none, .none },
|
||||
.{ .scasq, .z, &.{}, &.{ 0xaf }, 0, .long, .none },
|
||||
|
||||
.{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .none, .none },
|
||||
.{ .seta, .m, &.{ .rm8 }, &.{ 0x0f, 0x97 }, 0, .rex, .none },
|
||||
@ -699,7 +711,7 @@ pub const table = [_]Entry{
|
||||
.{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .none, .none },
|
||||
.{ .setz, .m, &.{ .rm8 }, &.{ 0x0f, 0x94 }, 0, .rex, .none },
|
||||
|
||||
.{ .sfence, .zo, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none, .none },
|
||||
.{ .sfence, .z, &.{}, &.{ 0x0f, 0xae, 0xf8 }, 0, .none, .none },
|
||||
|
||||
.{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .none, .none },
|
||||
.{ .shl, .m1, &.{ .rm8, .unity }, &.{ 0xd0 }, 4, .rex, .none },
|
||||
@ -747,15 +759,25 @@ pub const table = [_]Entry{
|
||||
.{ .shrd, .mrc, &.{ .rm32, .r32, .cl }, &.{ 0x0f, 0xad }, 0, .none, .none },
|
||||
.{ .shrd, .mrc, &.{ .rm64, .r64, .cl }, &.{ 0x0f, 0xad }, 0, .long, .none },
|
||||
|
||||
.{ .stos, .zo, &.{ .m8 }, &.{ 0xaa }, 0, .none, .none },
|
||||
.{ .stos, .zo, &.{ .m16 }, &.{ 0xab }, 0, .short, .none },
|
||||
.{ .stos, .zo, &.{ .m32 }, &.{ 0xab }, 0, .none, .none },
|
||||
.{ .stos, .zo, &.{ .m64 }, &.{ 0xab }, 0, .long, .none },
|
||||
.{ .stac, .z, &.{}, &.{ 0x0f, 0x01, 0xcb }, 0, .none, .smap },
|
||||
|
||||
.{ .stosb, .zo, &.{}, &.{ 0xaa }, 0, .none, .none },
|
||||
.{ .stosw, .zo, &.{}, &.{ 0xab }, 0, .short, .none },
|
||||
.{ .stosd, .zo, &.{}, &.{ 0xab }, 0, .none, .none },
|
||||
.{ .stosq, .zo, &.{}, &.{ 0xab }, 0, .long, .none },
|
||||
.{ .stc, .z, &.{}, &.{ 0xf9 }, 0, .none, .none },
|
||||
|
||||
.{ .std, .z, &.{}, &.{ 0xfd }, 0, .none, .none },
|
||||
|
||||
.{ .sti, .z, &.{}, &.{ 0xfb }, 0, .none, .none },
|
||||
|
||||
.{ .stui, .z, &.{}, &.{ 0xf3, 0x0f, 0x01, 0xef }, 0, .none, .uintr },
|
||||
|
||||
.{ .stos, .z, &.{ .m8 }, &.{ 0xaa }, 0, .none, .none },
|
||||
.{ .stos, .z, &.{ .m16 }, &.{ 0xab }, 0, .short, .none },
|
||||
.{ .stos, .z, &.{ .m32 }, &.{ 0xab }, 0, .none, .none },
|
||||
.{ .stos, .z, &.{ .m64 }, &.{ 0xab }, 0, .long, .none },
|
||||
|
||||
.{ .stosb, .z, &.{}, &.{ 0xaa }, 0, .none, .none },
|
||||
.{ .stosw, .z, &.{}, &.{ 0xab }, 0, .short, .none },
|
||||
.{ .stosd, .z, &.{}, &.{ 0xab }, 0, .none, .none },
|
||||
.{ .stosq, .z, &.{}, &.{ 0xab }, 0, .long, .none },
|
||||
|
||||
.{ .sub, .zi, &.{ .al, .imm8 }, &.{ 0x2c }, 0, .none, .none },
|
||||
.{ .sub, .zi, &.{ .ax, .imm16 }, &.{ 0x2d }, 0, .short, .none },
|
||||
@ -780,7 +802,7 @@ pub const table = [_]Entry{
|
||||
.{ .sub, .rm, &.{ .r32, .rm32 }, &.{ 0x2b }, 0, .none, .none },
|
||||
.{ .sub, .rm, &.{ .r64, .rm64 }, &.{ 0x2b }, 0, .long, .none },
|
||||
|
||||
.{ .syscall, .zo, &.{}, &.{ 0x0f, 0x05 }, 0, .none, .none },
|
||||
.{ .syscall, .z, &.{}, &.{ 0x0f, 0x05 }, 0, .none, .none },
|
||||
|
||||
.{ .@"test", .zi, &.{ .al, .imm8 }, &.{ 0xa8 }, 0, .none, .none },
|
||||
.{ .@"test", .zi, &.{ .ax, .imm16 }, &.{ 0xa9 }, 0, .short, .none },
|
||||
@ -801,7 +823,7 @@ pub const table = [_]Entry{
|
||||
.{ .tzcnt, .rm, &.{ .r32, .rm32 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .none, .bmi },
|
||||
.{ .tzcnt, .rm, &.{ .r64, .rm64 }, &.{ 0xf3, 0x0f, 0xbc }, 0, .long, .bmi },
|
||||
|
||||
.{ .ud2, .zo, &.{}, &.{ 0x0f, 0x0b }, 0, .none, .none },
|
||||
.{ .ud2, .z, &.{}, &.{ 0x0f, 0x0b }, 0, .none, .none },
|
||||
|
||||
.{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .none, .none },
|
||||
.{ .xadd, .mr, &.{ .rm8, .r8 }, &.{ 0x0f, 0xc0 }, 0, .rex, .none },
|
||||
@ -809,12 +831,12 @@ pub const table = [_]Entry{
|
||||
.{ .xadd, .mr, &.{ .rm32, .r32 }, &.{ 0x0f, 0xc1 }, 0, .none, .none },
|
||||
.{ .xadd, .mr, &.{ .rm64, .r64 }, &.{ 0x0f, 0xc1 }, 0, .long, .none },
|
||||
|
||||
.{ .xchg, .o, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .short, .none },
|
||||
.{ .xchg, .o, &.{ .r16, .ax }, &.{ 0x90 }, 0, .short, .none },
|
||||
.{ .xchg, .o, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none, .none },
|
||||
.{ .xchg, .o, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long, .none },
|
||||
.{ .xchg, .o, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none, .none },
|
||||
.{ .xchg, .o, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long, .none },
|
||||
.{ .xchg, .zo, &.{ .ax, .r16 }, &.{ 0x90 }, 0, .short, .none },
|
||||
.{ .xchg, .oz, &.{ .r16, .ax }, &.{ 0x90 }, 0, .short, .none },
|
||||
.{ .xchg, .zo, &.{ .eax, .r32 }, &.{ 0x90 }, 0, .none, .none },
|
||||
.{ .xchg, .zo, &.{ .rax, .r64 }, &.{ 0x90 }, 0, .long, .none },
|
||||
.{ .xchg, .oz, &.{ .r32, .eax }, &.{ 0x90 }, 0, .none, .none },
|
||||
.{ .xchg, .oz, &.{ .r64, .rax }, &.{ 0x90 }, 0, .long, .none },
|
||||
.{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .none, .none },
|
||||
.{ .xchg, .mr, &.{ .rm8, .r8 }, &.{ 0x86 }, 0, .rex, .none },
|
||||
.{ .xchg, .rm, &.{ .r8, .rm8 }, &.{ 0x86 }, 0, .none, .none },
|
||||
@ -826,7 +848,7 @@ pub const table = [_]Entry{
|
||||
.{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none, .none },
|
||||
.{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long, .none },
|
||||
|
||||
.{ .xgetbv, .zo, &.{}, &.{ 0x0f, 0x01, 0xd0 }, 0, .none, .none },
|
||||
.{ .xgetbv, .z, &.{}, &.{ 0x0f, 0x01, 0xd0 }, 0, .none, .none },
|
||||
|
||||
.{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none, .none },
|
||||
.{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .short, .none },
|
||||
@ -852,9 +874,9 @@ pub const table = [_]Entry{
|
||||
.{ .xor, .rm, &.{ .r64, .rm64 }, &.{ 0x33 }, 0, .long, .none },
|
||||
|
||||
// X87
|
||||
.{ .fabs, .zo, &.{}, &.{ 0xd9, 0xe1 }, 0, .none, .x87 },
|
||||
.{ .fabs, .z, &.{}, &.{ 0xd9, 0xe1 }, 0, .none, .x87 },
|
||||
|
||||
.{ .fchs, .zo, &.{}, &.{ 0xd9, 0xe0 }, 0, .none, .x87 },
|
||||
.{ .fchs, .z, &.{}, &.{ 0xd9, 0xe0 }, 0, .none, .x87 },
|
||||
|
||||
.{ .ffree, .o, &.{ .st }, &.{ 0xdd, 0xc0 }, 0, .none, .x87 },
|
||||
|
||||
@ -927,8 +949,14 @@ pub const table = [_]Entry{
|
||||
|
||||
.{ .movhlps, .rm, &.{ .xmm, .xmm }, &.{ 0x0f, 0x12 }, 0, .none, .sse },
|
||||
|
||||
.{ .movhps, .rm, &.{ .xmm, .m64 }, &.{ 0x0f, 0x16 }, 0, .none, .sse },
|
||||
.{ .movhps, .mr, &.{ .m64, .xmm }, &.{ 0x0f, 0x17 }, 0, .none, .sse },
|
||||
|
||||
.{ .movlhps, .rm, &.{ .xmm, .xmm }, &.{ 0x0f, 0x16 }, 0, .none, .sse },
|
||||
|
||||
.{ .movlps, .rm, &.{ .xmm, .m64 }, &.{ 0x0f, 0x12 }, 0, .none, .sse },
|
||||
.{ .movlps, .mr, &.{ .m64, .xmm }, &.{ 0x0f, 0x13 }, 0, .none, .sse },
|
||||
|
||||
.{ .movmskps, .rm, &.{ .r32, .xmm }, &.{ 0x0f, 0x50 }, 0, .none, .sse },
|
||||
.{ .movmskps, .rm, &.{ .r64, .xmm }, &.{ 0x0f, 0x50 }, 0, .none, .sse },
|
||||
|
||||
@ -1037,6 +1065,12 @@ pub const table = [_]Entry{
|
||||
.{ .movdqu, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x6f }, 0, .none, .sse2 },
|
||||
.{ .movdqu, .mr, &.{ .xmm_m128, .xmm }, &.{ 0xf3, 0x0f, 0x7f }, 0, .none, .sse2 },
|
||||
|
||||
.{ .movhpd, .rm, &.{ .xmm, .m64 }, &.{ 0x66, 0x0f, 0x16 }, 0, .none, .sse2 },
|
||||
.{ .movhpd, .mr, &.{ .m64, .xmm }, &.{ 0x66, 0x0f, 0x17 }, 0, .none, .sse2 },
|
||||
|
||||
.{ .movlpd, .rm, &.{ .xmm, .m64 }, &.{ 0x66, 0x0f, 0x12 }, 0, .none, .sse2 },
|
||||
.{ .movlpd, .mr, &.{ .m64, .xmm }, &.{ 0x66, 0x0f, 0x13 }, 0, .none, .sse2 },
|
||||
|
||||
.{ .movmskpd, .rm, &.{ .r32, .xmm }, &.{ 0x66, 0x0f, 0x50 }, 0, .none, .sse2 },
|
||||
.{ .movmskpd, .rm, &.{ .r64, .xmm }, &.{ 0x66, 0x0f, 0x50 }, 0, .none, .sse2 },
|
||||
|
||||
@ -1251,6 +1285,8 @@ pub const table = [_]Entry{
|
||||
|
||||
.{ .pmulld, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x40 }, 0, .none, .sse4_1 },
|
||||
|
||||
.{ .ptest, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .none, .sse4_1 },
|
||||
|
||||
.{ .roundpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x09 }, 0, .none, .sse4_1 },
|
||||
|
||||
.{ .roundps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x08 }, 0, .none, .sse4_1 },
|
||||
@ -1287,6 +1323,16 @@ pub const table = [_]Entry{
|
||||
.{ .sha256rnds2, .rm0, &.{ .xmm, .xmm_m128, .xmm0 }, &.{ 0x0f, 0x38, 0xcb }, 0, .none, .sha },
|
||||
|
||||
// AVX
|
||||
.{ .rorx, .rmi, &.{ .r32, .rm32, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w0, .bmi2 },
|
||||
.{ .rorx, .rmi, &.{ .r64, .rm64, .imm8 }, &.{ 0xf2, 0x0f, 0x3a }, 0, .vex_lz_w1, .bmi2 },
|
||||
|
||||
.{ .sarx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
|
||||
.{ .shlx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
|
||||
.{ .shrx, .rmv, &.{ .r32, .rm32, .r32 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w0, .bmi2 },
|
||||
.{ .sarx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf3, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
|
||||
.{ .shlx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0x66, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
|
||||
.{ .shrx, .rmv, &.{ .r64, .rm64, .r64 }, &.{ 0xf2, 0x0f, 0x38, 0xf7 }, 0, .vex_lz_w1, .bmi2 },
|
||||
|
||||
.{ .vaddpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vaddpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x58 }, 0, .vex_256_wig, .avx },
|
||||
|
||||
@ -1474,8 +1520,20 @@ pub const table = [_]Entry{
|
||||
|
||||
.{ .vmovhlps, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovhpd, .rvm, &.{ .xmm, .xmm, .m64 }, &.{ 0x66, 0x0f, 0x16 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vmovhpd, .mr, &.{ .m64, .xmm }, &.{ 0x66, 0x0f, 0x17 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovhps, .rvm, &.{ .xmm, .xmm, .m64 }, &.{ 0x0f, 0x16 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vmovhps, .mr, &.{ .m64, .xmm }, &.{ 0x0f, 0x17 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovlhps, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0x0f, 0x16 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovlpd, .rvm, &.{ .xmm, .xmm, .m64 }, &.{ 0x66, 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vmovlpd, .mr, &.{ .m64, .xmm }, &.{ 0x66, 0x0f, 0x13 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovlps, .rvm, &.{ .xmm, .xmm, .m64 }, &.{ 0x0f, 0x12 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vmovlps, .mr, &.{ .m64, .xmm }, &.{ 0x0f, 0x13 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vmovq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .vex_128_wig, .avx },
|
||||
.{ .vmovq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
@ -1571,14 +1629,14 @@ pub const table = [_]Entry{
|
||||
.{ .vpextrd, .mri, &.{ .rm32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpextrq, .mri, &.{ .rm64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x16 }, 0, .vex_128_w1, .avx },
|
||||
|
||||
.{ .vpextrw, .rmi, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpextrw, .rmi, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0xc5 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128_w0, .avx },
|
||||
|
||||
.{ .vpinsrb, .rmi, &.{ .xmm, .r32_m8, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x20 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpinsrd, .rmi, &.{ .xmm, .rm32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpinsrq, .rmi, &.{ .xmm, .rm64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w1, .avx },
|
||||
.{ .vpinsrb, .rvmi, &.{ .xmm, .xmm, .r32_m8, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x20 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpinsrd, .rvmi, &.{ .xmm, .xmm, .rm32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w0, .avx },
|
||||
.{ .vpinsrq, .rvmi, &.{ .xmm, .xmm, .rm64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x22 }, 0, .vex_128_w1, .avx },
|
||||
|
||||
.{ .vpinsrw, .rvmi, &.{ .xmm, .xmm, .r32_m16, .imm8 }, &.{ 0x66, 0x0f, 0xc4 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpinsrw, .rvmi, &.{ .xmm, .xmm, .r32_m16, .imm8 }, &.{ 0x66, 0x0f, 0xc4 }, 0, .vex_128_w0, .avx },
|
||||
|
||||
.{ .vpmaxsb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x3c }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpmaxsw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xee }, 0, .vex_128_wig, .avx },
|
||||
@ -1666,6 +1724,9 @@ pub const table = [_]Entry{
|
||||
.{ .vpsubusb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd8 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpsubusw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd9 }, 0, .vex_128_wig, .avx },
|
||||
|
||||
.{ .vptest, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vptest, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .vex_256_wig, .avx },
|
||||
|
||||
.{ .vpunpckhbw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x68 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpunpckhwd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x69 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vpunpckhdq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6a }, 0, .vex_128_wig, .avx },
|
||||
@ -1716,6 +1777,11 @@ pub const table = [_]Entry{
|
||||
|
||||
.{ .vsubss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .vex_lig_wig, .avx },
|
||||
|
||||
.{ .vtestps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0e }, 0, .vex_128_w0, .avx },
|
||||
.{ .vtestps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0e }, 0, .vex_256_w0, .avx },
|
||||
.{ .vtestpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_128_w0, .avx },
|
||||
.{ .vtestpd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_256_w0, .avx },
|
||||
|
||||
.{ .vxorpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_128_wig, .avx },
|
||||
.{ .vxorpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_256_wig, .avx },
|
||||
|
||||
|
||||
@ -1312,10 +1312,10 @@ pub const Pool = struct {
|
||||
},
|
||||
else => {
|
||||
const target = &mod.resolved_target.result;
|
||||
const abi_align = Type.intAbiAlignment(int_info.bits, target.*, false);
|
||||
const abi_align = Type.intAbiAlignment(int_info.bits, target.*);
|
||||
const abi_align_bytes = abi_align.toByteUnits().?;
|
||||
const array_ctype = try pool.getArray(allocator, .{
|
||||
.len = @divExact(Type.intAbiSize(int_info.bits, target.*, false), abi_align_bytes),
|
||||
.len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes),
|
||||
.elem_ctype = try pool.fromIntInfo(allocator, .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @intCast(abi_align_bytes * 8),
|
||||
@ -1429,7 +1429,7 @@ pub const Pool = struct {
|
||||
.name = .{ .index = .len },
|
||||
.ctype = CType.usize,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
|
||||
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
|
||||
),
|
||||
},
|
||||
};
|
||||
@ -1524,7 +1524,7 @@ pub const Pool = struct {
|
||||
.name = .{ .index = .len },
|
||||
.ctype = CType.usize,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
|
||||
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
|
||||
),
|
||||
},
|
||||
};
|
||||
@ -1644,7 +1644,7 @@ pub const Pool = struct {
|
||||
.name = .{ .index = .@"error" },
|
||||
.ctype = error_set_ctype,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
Type.intAbiAlignment(error_set_bits, target.*, false),
|
||||
Type.intAbiAlignment(error_set_bits, target.*),
|
||||
),
|
||||
},
|
||||
.{
|
||||
|
||||
@ -581,7 +581,7 @@ const DataLayoutBuilder = struct {
|
||||
switch (kind) {
|
||||
.integer => {
|
||||
if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
|
||||
abi = @min(abi, Type.maxIntAlignment(self.target, true) * 8);
|
||||
abi = @min(abi, Type.maxIntAlignment(self.target) * 8);
|
||||
switch (self.target.cpu.arch) {
|
||||
.aarch64,
|
||||
.aarch64_be,
|
||||
|
||||
@ -135,6 +135,7 @@ pub const Env = enum {
|
||||
else => Env.ast_gen.supports(feature),
|
||||
},
|
||||
.@"x86_64-linux" => switch (feature) {
|
||||
.build_command,
|
||||
.stdio_listen,
|
||||
.incremental,
|
||||
.x86_64_backend,
|
||||
|
||||
@ -396,7 +396,7 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
|
||||
else => {},
|
||||
}
|
||||
try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
|
||||
Type.maxIntAlignment(target, false),
|
||||
Type.maxIntAlignment(target),
|
||||
});
|
||||
return defines;
|
||||
}
|
||||
|
||||
@ -976,6 +976,7 @@ const x86_64 = struct {
|
||||
it: *RelocsIterator,
|
||||
) !void {
|
||||
dev.check(.x86_64_backend);
|
||||
const t = &elf_file.base.comp.root_mod.resolved_target.result;
|
||||
const is_static = elf_file.base.isStatic();
|
||||
const is_dyn_lib = elf_file.isEffectivelyDynLib();
|
||||
|
||||
@ -1046,7 +1047,7 @@ const x86_64 = struct {
|
||||
.GOTTPOFF => {
|
||||
const should_relax = blk: {
|
||||
if (is_dyn_lib or symbol.flags.import) break :blk false;
|
||||
if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false;
|
||||
if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..], t)) break :blk false;
|
||||
break :blk true;
|
||||
};
|
||||
if (!should_relax) {
|
||||
@ -1090,6 +1091,7 @@ const x86_64 = struct {
|
||||
stream: anytype,
|
||||
) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
|
||||
dev.check(.x86_64_backend);
|
||||
const t = &elf_file.base.comp.root_mod.resolved_target.result;
|
||||
const diags = &elf_file.base.comp.link_diags;
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
||||
@ -1120,7 +1122,7 @@ const x86_64 = struct {
|
||||
|
||||
.GOTPCRELX => {
|
||||
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
|
||||
x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;
|
||||
x86_64.relaxGotpcrelx(code[r_offset - 2 ..], t) catch break :blk;
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
|
||||
return;
|
||||
}
|
||||
@ -1129,7 +1131,7 @@ const x86_64 = struct {
|
||||
|
||||
.REX_GOTPCRELX => {
|
||||
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
|
||||
x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;
|
||||
x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..], t) catch break :blk;
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
|
||||
return;
|
||||
}
|
||||
@ -1184,7 +1186,7 @@ const x86_64 = struct {
|
||||
const S_ = target.tlsDescAddress(elf_file);
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
} else {
|
||||
x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
|
||||
x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch {
|
||||
var err = try diags.addErrorWithNotes(1);
|
||||
try err.addMsg("could not relax {s}", .{@tagName(r_type)});
|
||||
err.addNote("in {}:{s} at offset 0x{x}", .{
|
||||
@ -1208,7 +1210,7 @@ const x86_64 = struct {
|
||||
const S_ = target.gotTpAddress(elf_file);
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
} else {
|
||||
x86_64.relaxGotTpOff(code[r_offset - 3 ..]);
|
||||
x86_64.relaxGotTpOff(code[r_offset - 3 ..], t);
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
|
||||
}
|
||||
},
|
||||
@ -1269,31 +1271,31 @@ const x86_64 = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn relaxGotpcrelx(code: []u8) !void {
|
||||
fn relaxGotpcrelx(code: []u8, t: *const std.Target) !void {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse return error.RelaxFailure;
|
||||
const inst = switch (old_inst.encoding.mnemonic) {
|
||||
.call => try Instruction.new(old_inst.prefix, .call, &.{
|
||||
const inst: Instruction = switch (old_inst.encoding.mnemonic) {
|
||||
.call => try .new(old_inst.prefix, .call, &.{
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = Immediate.s(-129) },
|
||||
}),
|
||||
.jmp => try Instruction.new(old_inst.prefix, .jmp, &.{
|
||||
.{ .imm = .s(-129) },
|
||||
}, t),
|
||||
.jmp => try .new(old_inst.prefix, .jmp, &.{
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = Immediate.s(-129) },
|
||||
}),
|
||||
.{ .imm = .s(-129) },
|
||||
}, t),
|
||||
else => return error.RelaxFailure,
|
||||
};
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
const nop = try Instruction.new(.none, .nop, &.{});
|
||||
const nop: Instruction = try .new(.none, .nop, &.{}, t);
|
||||
try encode(&.{ nop, inst }, code);
|
||||
}
|
||||
|
||||
fn relaxRexGotpcrelx(code: []u8) !void {
|
||||
fn relaxRexGotpcrelx(code: []u8, t: *const std.Target) !void {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse return error.RelaxFailure;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
.mov => {
|
||||
const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops);
|
||||
const inst: Instruction = try .new(old_inst.prefix, .lea, &old_inst.ops, t);
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
try encode(&.{inst}, code);
|
||||
},
|
||||
@ -1398,23 +1400,24 @@ const x86_64 = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn canRelaxGotTpOff(code: []const u8) bool {
|
||||
fn canRelaxGotTpOff(code: []const u8, t: *const std.Target) bool {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse return false;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
.mov => if (Instruction.new(old_inst.prefix, .mov, &.{
|
||||
old_inst.ops[0],
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = Immediate.s(-129) },
|
||||
})) |inst| {
|
||||
.mov => {
|
||||
const inst = Instruction.new(old_inst.prefix, .mov, &.{
|
||||
old_inst.ops[0],
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = .s(-129) },
|
||||
}, t) catch return false;
|
||||
inst.encode(std.io.null_writer, .{}) catch return false;
|
||||
return true;
|
||||
} else |_| return false,
|
||||
},
|
||||
else => return false,
|
||||
}
|
||||
}
|
||||
|
||||
fn relaxGotTpOff(code: []u8) void {
|
||||
fn relaxGotTpOff(code: []u8, t: *const std.Target) void {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse unreachable;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
@ -1422,8 +1425,8 @@ const x86_64 = struct {
|
||||
const inst = Instruction.new(old_inst.prefix, .mov, &.{
|
||||
old_inst.ops[0],
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = Immediate.s(-129) },
|
||||
}) catch unreachable;
|
||||
.{ .imm = .s(-129) },
|
||||
}, t) catch unreachable;
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
encode(&.{inst}, code) catch unreachable;
|
||||
},
|
||||
@ -1431,16 +1434,16 @@ const x86_64 = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn relaxGotPcTlsDesc(code: []u8) !void {
|
||||
fn relaxGotPcTlsDesc(code: []u8, target: *const std.Target) !void {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse return error.RelaxFailure;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
.lea => {
|
||||
const inst = try Instruction.new(old_inst.prefix, .mov, &.{
|
||||
const inst: Instruction = try .new(old_inst.prefix, .mov, &.{
|
||||
old_inst.ops[0],
|
||||
// TODO: hack to force imm32s in the assembler
|
||||
.{ .imm = Immediate.s(-129) },
|
||||
});
|
||||
.{ .imm = .s(-129) },
|
||||
}, target);
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
try encode(&.{inst}, code);
|
||||
},
|
||||
@ -1779,7 +1782,7 @@ const aarch64 = struct {
|
||||
const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
|
||||
aarch64_util.writeAddImmInst(off, code);
|
||||
} else {
|
||||
const old_inst = Instruction{
|
||||
const old_inst: Instruction = .{
|
||||
.add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
|
||||
Instruction,
|
||||
Instruction.add_subtract_immediate,
|
||||
@ -1793,7 +1796,7 @@ const aarch64 = struct {
|
||||
},
|
||||
|
||||
.TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
|
||||
const old_inst = Instruction{
|
||||
const old_inst: Instruction = .{
|
||||
.unconditional_branch_register = mem.bytesToValue(std.meta.TagPayload(
|
||||
Instruction,
|
||||
Instruction.unconditional_branch_register,
|
||||
|
||||
@ -3548,7 +3548,7 @@ pub fn getTarget(self: MachO) std.Target {
|
||||
pub fn invalidateKernelCache(dir: fs.Dir, sub_path: []const u8) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
|
||||
if (builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
|
||||
try dir.copyFile(sub_path, dir, sub_path, .{});
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,7 +640,8 @@ fn resolveRelocInner(
|
||||
macho_file: *MachO,
|
||||
writer: anytype,
|
||||
) ResolveError!void {
|
||||
const cpu_arch = macho_file.getTarget().cpu.arch;
|
||||
const t = &macho_file.base.comp.root_mod.resolved_target.result;
|
||||
const cpu_arch = t.cpu.arch;
|
||||
const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
|
||||
const P = @as(i64, @intCast(self.getAddress(macho_file))) + @as(i64, @intCast(rel_offset));
|
||||
const A = rel.addend + rel.getRelocAddend(cpu_arch);
|
||||
@ -747,7 +748,7 @@ fn resolveRelocInner(
|
||||
const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
|
||||
try writer.writeInt(i32, @intCast(S_ + A - P), .little);
|
||||
} else {
|
||||
try x86_64.relaxTlv(code[rel_offset - 3 ..]);
|
||||
try x86_64.relaxTlv(code[rel_offset - 3 ..], t);
|
||||
try writer.writeInt(i32, @intCast(S + A - P), .little);
|
||||
}
|
||||
},
|
||||
@ -893,11 +894,12 @@ fn resolveRelocInner(
|
||||
const x86_64 = struct {
|
||||
fn relaxGotLoad(self: Atom, code: []u8, rel: Relocation, macho_file: *MachO) ResolveError!void {
|
||||
dev.check(.x86_64_backend);
|
||||
const t = &macho_file.base.comp.root_mod.resolved_target.result;
|
||||
const diags = &macho_file.base.comp.link_diags;
|
||||
const old_inst = disassemble(code) orelse return error.RelaxFail;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
.mov => {
|
||||
const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops) catch return error.RelaxFail;
|
||||
const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
encode(&.{inst}, code) catch return error.RelaxFail;
|
||||
},
|
||||
@ -916,12 +918,12 @@ const x86_64 = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn relaxTlv(code: []u8) error{RelaxFail}!void {
|
||||
fn relaxTlv(code: []u8, t: *const std.Target) error{RelaxFail}!void {
|
||||
dev.check(.x86_64_backend);
|
||||
const old_inst = disassemble(code) orelse return error.RelaxFail;
|
||||
switch (old_inst.encoding.mnemonic) {
|
||||
.mov => {
|
||||
const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops) catch return error.RelaxFail;
|
||||
const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
|
||||
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
|
||||
encode(&.{inst}, code) catch return error.RelaxFail;
|
||||
},
|
||||
|
||||
@ -39,6 +39,11 @@ test {
|
||||
_ = Package;
|
||||
}
|
||||
|
||||
const thread_stack_size = switch (builtin.zig_backend) {
|
||||
else => std.Thread.SpawnConfig.default_stack_size,
|
||||
.stage2_x86_64 => 32 << 20,
|
||||
};
|
||||
|
||||
pub const std_options: std.Options = .{
|
||||
.wasiCwd = wasi_cwd,
|
||||
.logFn = log,
|
||||
@ -3320,6 +3325,7 @@ fn buildOutputType(
|
||||
.allocator = gpa,
|
||||
.n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
|
||||
.track_ids = true,
|
||||
.stack_size = thread_stack_size,
|
||||
});
|
||||
defer thread_pool.deinit();
|
||||
|
||||
@ -5024,6 +5030,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
||||
.allocator = gpa,
|
||||
.n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
|
||||
.track_ids = true,
|
||||
.stack_size = thread_stack_size,
|
||||
});
|
||||
defer thread_pool.deinit();
|
||||
|
||||
@ -5460,6 +5467,7 @@ fn jitCmd(
|
||||
.allocator = gpa,
|
||||
.n_jobs = @min(@max(std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
|
||||
.track_ids = true,
|
||||
.stack_size = thread_stack_size,
|
||||
});
|
||||
defer thread_pool.deinit();
|
||||
|
||||
|
||||
@ -96,8 +96,8 @@ const Writer = struct {
|
||||
fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
try s.print("%{d}{c}= {s}(", .{
|
||||
@intFromEnum(inst),
|
||||
try s.print("{}{c}= {s}(", .{
|
||||
inst,
|
||||
@as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
|
||||
@tagName(tag),
|
||||
});
|
||||
@ -409,7 +409,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_block.deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,7 +728,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -739,7 +739,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -765,7 +765,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -776,7 +776,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
|
||||
for (liveness_condbr.then_deaths) |operand| {
|
||||
try s.print(" %{d}!", .{@intFromEnum(operand)});
|
||||
try s.print(" {}!", .{operand});
|
||||
}
|
||||
}
|
||||
|
||||
@ -807,7 +807,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.then_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -827,7 +827,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (liveness_condbr.else_deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -884,7 +884,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -910,7 +910,7 @@ const Writer = struct {
|
||||
try s.writeByteNTimes(' ', w.indent);
|
||||
for (deaths, 0..) |operand, i| {
|
||||
if (i != 0) try s.writeAll(" ");
|
||||
try s.print("%{d}!", .{@intFromEnum(operand)});
|
||||
try s.print("{}!", .{operand});
|
||||
}
|
||||
try s.writeAll("\n");
|
||||
}
|
||||
@ -994,7 +994,7 @@ const Writer = struct {
|
||||
dies: bool,
|
||||
) @TypeOf(s).Error!void {
|
||||
_ = w;
|
||||
try s.print("%{d}", .{@intFromEnum(inst)});
|
||||
try s.print("{}", .{inst});
|
||||
if (dies) try s.writeByte('!');
|
||||
}
|
||||
|
||||
|
||||
@ -41,12 +41,12 @@ pub fn RegisterManager(
|
||||
registers: TrackedRegisters = undefined,
|
||||
/// Tracks which registers are free (in which case the
|
||||
/// corresponding bit is set to 1)
|
||||
free_registers: RegisterBitSet = RegisterBitSet.initFull(),
|
||||
free_registers: RegisterBitSet = .initFull(),
|
||||
/// Tracks all registers allocated in the course of this
|
||||
/// function
|
||||
allocated_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
allocated_registers: RegisterBitSet = .initEmpty(),
|
||||
/// Tracks registers which are locked from being allocated
|
||||
locked_registers: RegisterBitSet = RegisterBitSet.initEmpty(),
|
||||
locked_registers: RegisterBitSet = .initEmpty(),
|
||||
|
||||
const Self = @This();
|
||||
|
||||
@ -58,11 +58,6 @@ pub fn RegisterManager(
|
||||
return @alignCast(@fieldParentPtr("register_manager", self));
|
||||
}
|
||||
|
||||
fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
|
||||
const index = indexOfRegIntoTracked(reg) orelse return true;
|
||||
return !register_class.isSet(index);
|
||||
}
|
||||
|
||||
fn markRegIndexAllocated(self: *Self, tracked_index: TrackedIndex) void {
|
||||
self.allocated_registers.set(tracked_index);
|
||||
}
|
||||
@ -99,8 +94,7 @@ pub fn RegisterManager(
|
||||
max_id = @max(elem_id, max_id);
|
||||
}
|
||||
|
||||
const OptionalIndex = std.math.IntFittingRange(0, set.len);
|
||||
comptime var map = [1]OptionalIndex{set.len} ** (max_id - min_id + 1);
|
||||
comptime var map: [max_id - min_id + 1]std.math.IntFittingRange(0, set.len) = @splat(set.len);
|
||||
inline for (set, 0..) |elem, elem_index| map[comptime elem.id() - min_id] = elem_index;
|
||||
|
||||
const id_index = reg.id() -% min_id;
|
||||
@ -112,6 +106,9 @@ pub fn RegisterManager(
|
||||
pub fn indexOfRegIntoTracked(reg: Register) ?TrackedIndex {
|
||||
return indexOfReg(tracked_registers, reg);
|
||||
}
|
||||
pub inline fn indexOfKnownRegIntoTracked(comptime reg: Register) ?TrackedIndex {
|
||||
return comptime indexOfRegIntoTracked(reg);
|
||||
}
|
||||
|
||||
pub fn regAtTrackedIndex(tracked_index: TrackedIndex) Register {
|
||||
return tracked_registers[tracked_index];
|
||||
@ -124,6 +121,9 @@ pub fn RegisterManager(
|
||||
pub fn isRegFree(self: Self, reg: Register) bool {
|
||||
return self.isRegIndexFree(indexOfRegIntoTracked(reg) orelse return true);
|
||||
}
|
||||
pub fn isKnownRegFree(self: Self, comptime reg: Register) bool {
|
||||
return self.isRegIndexFree(indexOfKnownRegIntoTracked(reg) orelse return true);
|
||||
}
|
||||
|
||||
/// Returns whether this register was allocated in the course
|
||||
/// of this function.
|
||||
@ -143,6 +143,9 @@ pub fn RegisterManager(
|
||||
pub fn isRegLocked(self: Self, reg: Register) bool {
|
||||
return self.isRegIndexLocked(indexOfRegIntoTracked(reg) orelse return false);
|
||||
}
|
||||
pub fn isKnownRegLocked(self: Self, comptime reg: Register) bool {
|
||||
return self.isRegIndexLocked(indexOfKnownRegIntoTracked(reg) orelse return false);
|
||||
}
|
||||
|
||||
pub const RegisterLock = struct { tracked_index: TrackedIndex };
|
||||
|
||||
@ -176,6 +179,9 @@ pub fn RegisterManager(
|
||||
pub fn lockRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
|
||||
return self.lockRegIndexAssumeUnused(indexOfRegIntoTracked(reg) orelse unreachable);
|
||||
}
|
||||
pub fn lockKnownRegAssumeUnused(self: *Self, comptime reg: Register) RegisterLock {
|
||||
return self.lockRegIndexAssumeUnused(indexOfKnownRegIntoTracked(reg) orelse unreachable);
|
||||
}
|
||||
|
||||
/// Like `lockReg` but locks multiple registers.
|
||||
pub fn lockRegs(
|
||||
@ -223,28 +229,20 @@ pub fn RegisterManager(
|
||||
) ?[count]Register {
|
||||
comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
var free_and_not_locked_registers = self.free_registers;
|
||||
free_and_not_locked_registers.setIntersection(register_class);
|
||||
|
||||
var unlocked_registers = self.locked_registers;
|
||||
unlocked_registers.toggleAll();
|
||||
|
||||
free_and_not_locked_registers.setIntersection(unlocked_registers);
|
||||
|
||||
if (free_and_not_locked_registers.count() < count) return null;
|
||||
var free_and_unlocked_registers = self.locked_registers;
|
||||
free_and_unlocked_registers.toggleAll();
|
||||
free_and_unlocked_registers.setIntersection(self.free_registers);
|
||||
free_and_unlocked_registers.setIntersection(register_class);
|
||||
|
||||
var regs: [count]Register = undefined;
|
||||
var i: usize = 0;
|
||||
for (tracked_registers) |reg| {
|
||||
if (i >= count) break;
|
||||
if (excludeRegister(reg, register_class)) continue;
|
||||
if (self.isRegLocked(reg)) continue;
|
||||
if (!self.isRegFree(reg)) continue;
|
||||
|
||||
regs[i] = reg;
|
||||
var it = free_and_unlocked_registers.iterator(.{});
|
||||
while (it.next()) |reg_index| {
|
||||
regs[i] = regAtTrackedIndex(@intCast(reg_index));
|
||||
i += 1;
|
||||
if (i >= count) break;
|
||||
}
|
||||
assert(i == count);
|
||||
if (i < count) return null;
|
||||
|
||||
for (regs, insts) |reg, inst| {
|
||||
log.debug("tryAllocReg {} for inst {?}", .{ reg, inst });
|
||||
@ -279,46 +277,27 @@ pub fn RegisterManager(
|
||||
) AllocationError![count]Register {
|
||||
comptime assert(count > 0 and count <= tracked_registers.len);
|
||||
|
||||
var locked_registers = self.locked_registers;
|
||||
locked_registers.setIntersection(register_class);
|
||||
|
||||
if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
|
||||
|
||||
const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
|
||||
var unlocked_registers = self.locked_registers;
|
||||
unlocked_registers.toggleAll();
|
||||
unlocked_registers.setIntersection(register_class);
|
||||
|
||||
// We'll take over the first count registers. Spill
|
||||
// the instructions that were previously there to a
|
||||
// stack allocations.
|
||||
var regs: [count]Register = undefined;
|
||||
var i: usize = 0;
|
||||
for (tracked_registers) |reg| {
|
||||
if (i >= count) break;
|
||||
if (excludeRegister(reg, register_class)) break;
|
||||
if (self.isRegLocked(reg)) continue;
|
||||
|
||||
log.debug("allocReg {} for inst {?}", .{ reg, insts[i] });
|
||||
regs[i] = reg;
|
||||
self.markRegAllocated(reg);
|
||||
const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
|
||||
if (insts[i]) |inst| {
|
||||
// Track the register
|
||||
if (self.isRegFree(reg)) {
|
||||
self.markRegUsed(reg);
|
||||
} else {
|
||||
const spilled_inst = self.registers[index];
|
||||
try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
}
|
||||
self.registers[index] = inst;
|
||||
} else {
|
||||
// Don't track the register
|
||||
if (!self.isRegFree(reg)) {
|
||||
const spilled_inst = self.registers[index];
|
||||
try self.getFunction().spillInstruction(reg, spilled_inst);
|
||||
self.freeReg(reg);
|
||||
}
|
||||
}
|
||||
|
||||
var it = unlocked_registers.iterator(.{});
|
||||
while (it.next()) |reg_index| {
|
||||
const tracked_index: TrackedIndex = @intCast(reg_index);
|
||||
if (!self.isRegIndexFree(tracked_index) and
|
||||
self.registers[tracked_index].unwrap() == .target) continue;
|
||||
try self.getRegIndex(tracked_index, insts[i]);
|
||||
regs[i] = regAtTrackedIndex(tracked_index);
|
||||
i += 1;
|
||||
if (i >= count) break;
|
||||
}
|
||||
if (i < count) return error.OutOfRegisters;
|
||||
|
||||
break :blk regs;
|
||||
};
|
||||
@ -340,7 +319,7 @@ pub fn RegisterManager(
|
||||
/// Spills the register if it is currently allocated. If a
|
||||
/// corresponding instruction is passed, will also track this
|
||||
/// register.
|
||||
fn getRegIndex(
|
||||
pub fn getRegIndex(
|
||||
self: *Self,
|
||||
tracked_index: TrackedIndex,
|
||||
inst: ?Air.Inst.Index,
|
||||
@ -366,13 +345,13 @@ pub fn RegisterManager(
|
||||
comptime reg: Register,
|
||||
inst: ?Air.Inst.Index,
|
||||
) AllocationError!void {
|
||||
return self.getRegIndex((comptime indexOfRegIntoTracked(reg)) orelse return, inst);
|
||||
return self.getRegIndex(indexOfKnownRegIntoTracked(reg) orelse return, inst);
|
||||
}
|
||||
|
||||
/// Allocates the specified register with the specified
|
||||
/// instruction. Asserts that the register is free and no
|
||||
/// spilling is necessary.
|
||||
fn getRegIndexAssumeFree(
|
||||
pub fn getRegIndexAssumeFree(
|
||||
self: *Self,
|
||||
tracked_index: TrackedIndex,
|
||||
inst: ?Air.Inst.Index,
|
||||
@ -391,7 +370,7 @@ pub fn RegisterManager(
|
||||
}
|
||||
|
||||
/// Marks the specified register as free
|
||||
fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void {
|
||||
pub fn freeRegIndex(self: *Self, tracked_index: TrackedIndex) void {
|
||||
log.debug("freeing register {}", .{regAtTrackedIndex(tracked_index)});
|
||||
self.registers[tracked_index] = undefined;
|
||||
self.markRegIndexFree(tracked_index);
|
||||
@ -420,8 +399,8 @@ const MockRegister1 = enum(u2) {
|
||||
&MockRegister1.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
const gp = blk: {
|
||||
var set: RM.RegisterBitSet = .initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = allocatable_registers.len,
|
||||
@ -448,8 +427,8 @@ const MockRegister2 = enum(u2) {
|
||||
&MockRegister2.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
const gp = blk: {
|
||||
var set: RM.RegisterBitSet = .initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = allocatable_registers.len,
|
||||
@ -489,16 +468,16 @@ const MockRegister3 = enum(u3) {
|
||||
&MockRegister3.allocatable_registers,
|
||||
);
|
||||
|
||||
const gp: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
const gp = blk: {
|
||||
var set: RM.RegisterBitSet = .initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = 0,
|
||||
.end = gp_regs.len,
|
||||
}, true);
|
||||
break :blk set;
|
||||
};
|
||||
const ext: RM.RegisterBitSet = blk: {
|
||||
var set = RM.RegisterBitSet.initEmpty();
|
||||
const ext = blk: {
|
||||
var set: RM.RegisterBitSet = .initEmpty();
|
||||
set.setRangeValue(.{
|
||||
.start = gp_regs.len,
|
||||
.end = allocatable_registers.len,
|
||||
|
||||
@ -110,6 +110,8 @@ test {
|
||||
_ = @import("behavior/widening.zig");
|
||||
_ = @import("behavior/abs.zig");
|
||||
|
||||
_ = @import("behavior/x86_64.zig");
|
||||
|
||||
if (builtin.cpu.arch == .wasm32) {
|
||||
_ = @import("behavior/wasm.zig");
|
||||
}
|
||||
|
||||
@ -144,31 +144,17 @@ test "alignment and size of structs with 128-bit fields" {
|
||||
},
|
||||
},
|
||||
|
||||
.x86_64 => switch (builtin.zig_backend) {
|
||||
.stage2_x86_64 => .{
|
||||
.a_align = 8,
|
||||
.a_size = 16,
|
||||
.x86_64 => .{
|
||||
.a_align = 16,
|
||||
.a_size = 16,
|
||||
|
||||
.b_align = 16,
|
||||
.b_size = 32,
|
||||
.b_align = 16,
|
||||
.b_size = 32,
|
||||
|
||||
.u128_align = 8,
|
||||
.u128_size = 16,
|
||||
.u129_align = 8,
|
||||
.u129_size = 24,
|
||||
},
|
||||
else => .{
|
||||
.a_align = 16,
|
||||
.a_size = 16,
|
||||
|
||||
.b_align = 16,
|
||||
.b_size = 32,
|
||||
|
||||
.u128_align = 16,
|
||||
.u128_size = 16,
|
||||
.u129_align = 16,
|
||||
.u129_size = 32,
|
||||
},
|
||||
.u128_align = 16,
|
||||
.u128_size = 16,
|
||||
.u129_align = 16,
|
||||
.u129_size = 32,
|
||||
},
|
||||
|
||||
.x86,
|
||||
@ -291,8 +277,8 @@ test "function alignment" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
// function alignment is a compile error on wasm
|
||||
if (native_arch.isWasm()) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn alignExpr() align(@sizeOf(usize) * 2) i32 {
|
||||
@ -321,8 +307,8 @@ test "implicitly decreasing fn alignment" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
// function alignment is a compile error on wasm
|
||||
if (native_arch.isWasm()) return error.SkipZigTest;
|
||||
|
||||
try testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
|
||||
try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
|
||||
@ -345,9 +331,9 @@ test "@alignCast functions" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
if (native_arch == .thumb or native_arch == .thumbeb) return error.SkipZigTest;
|
||||
// function alignment is a compile error on wasm
|
||||
if (native_arch.isWasm()) return error.SkipZigTest;
|
||||
if (native_arch.isThumb()) return error.SkipZigTest;
|
||||
|
||||
try expect(fnExpectsOnly1(simple4) == 0x19);
|
||||
}
|
||||
@ -510,9 +496,9 @@ test "align(N) on functions" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
// function alignment is a compile error on wasm32/wasm64
|
||||
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
|
||||
if (native_arch == .thumb or native_arch == .thumbeb) return error.SkipZigTest;
|
||||
// function alignment is a compile error on wasm
|
||||
if (native_arch.isWasm()) return error.SkipZigTest;
|
||||
if (native_arch.isThumb()) return error.SkipZigTest;
|
||||
|
||||
try expect((@intFromPtr(&overaligned_fn) & (0x1000 - 1)) == 0);
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ test "rw constraint (x86_64)" {
|
||||
}
|
||||
|
||||
test "asm modifiers (AArch64)" {
|
||||
if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;
|
||||
if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
|
||||
|
||||
@ -1169,7 +1169,7 @@ test "arrays and vectors with big integers" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -660,6 +660,7 @@ test "arguments pointed to on stack into tailcall" {
|
||||
|
||||
switch (builtin.cpu.arch) {
|
||||
.wasm32,
|
||||
.wasm64,
|
||||
.mips,
|
||||
.mipsel,
|
||||
.mips64,
|
||||
|
||||
@ -124,7 +124,7 @@ test "@floatFromInt(f80)" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -1362,7 +1362,7 @@ test "cast f16 to wider types" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -2539,7 +2539,6 @@ test "@intFromBool on vector" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
|
||||
@ -522,7 +522,7 @@ test "runtime 128 bit integer division" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
|
||||
@ -65,6 +65,8 @@ test "@clz" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
|
||||
try testClz();
|
||||
try comptime testClz();
|
||||
@ -75,6 +77,7 @@ fn testClz() !void {
|
||||
try expect(testOneClz(u8, 0b00001010) == 4);
|
||||
try expect(testOneClz(u8, 0b00011010) == 3);
|
||||
try expect(testOneClz(u8, 0b00000000) == 8);
|
||||
try expect(testOneClz(i8, -1) == 0);
|
||||
}
|
||||
|
||||
test "@clz big ints" {
|
||||
@ -100,7 +103,7 @@ fn testOneClz(comptime T: type, x: T) u32 {
|
||||
|
||||
test "@clz vectors" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
@ -159,6 +162,8 @@ fn testCtz() !void {
|
||||
try expect(testOneCtz(u8, 0b10100000) == 5);
|
||||
try expect(testOneCtz(u8, 0b10001010) == 1);
|
||||
try expect(testOneCtz(u8, 0b00000000) == 8);
|
||||
try expect(testOneCtz(i8, -1) == 0);
|
||||
try expect(testOneCtz(i8, -2) == 1);
|
||||
try expect(testOneCtz(u16, 0b00000000) == 16);
|
||||
}
|
||||
|
||||
@ -467,7 +472,6 @@ test "division" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -583,7 +587,7 @@ fn testFloatDivision() !void {
|
||||
}
|
||||
|
||||
test "large integer division" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
@ -780,7 +784,7 @@ test "128-bit multiplication" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
{
|
||||
@ -1369,7 +1373,7 @@ test "remainder division" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
||||
@ -1522,7 +1526,7 @@ test "@round f80" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -1535,7 +1539,7 @@ test "@round f128" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -1712,7 +1716,7 @@ test "mod lazy values" {
|
||||
|
||||
test "@clz works on both vector and scalar inputs" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
||||
@ -122,7 +122,7 @@ test "@min/max for floats" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ test "@mulAdd f80" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -79,7 +79,7 @@ test "@mulAdd f128" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -189,7 +189,7 @@ test "vector f80" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
try comptime vector80();
|
||||
@ -216,7 +216,7 @@ test "vector f128" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
try comptime vector128();
|
||||
|
||||
@ -57,7 +57,7 @@ fn testNullPtrsEql() !void {
|
||||
|
||||
test "optional with zero-bit type" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
|
||||
@ -138,7 +138,6 @@ test "packed union initialized with a runtime value" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
const Fields = packed struct {
|
||||
|
||||
@ -164,10 +164,10 @@ test "saturating multiplication <= 32 bits" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) {
|
||||
// https://github.com/ziglang/zig/issues/9660
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -264,10 +264,10 @@ test "saturating multiplication" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) {
|
||||
// https://github.com/ziglang/zig/issues/9660
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -311,7 +311,7 @@ test "saturating shift-left" {
|
||||
try testSatShl(i8, 127, 1, 127);
|
||||
try testSatShl(i8, -128, 1, -128);
|
||||
// TODO: remove this check once #9668 is completed
|
||||
if (builtin.cpu.arch != .wasm32) {
|
||||
if (!builtin.cpu.arch.isWasm()) {
|
||||
// skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error
|
||||
try testSatShl(i128, maxInt(i128), 64, maxInt(i128));
|
||||
try testSatShl(u128, maxInt(u128), 64, maxInt(u128));
|
||||
|
||||
@ -418,8 +418,8 @@ test "packed struct 24bits" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
|
||||
if (comptime builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
@ -818,7 +818,7 @@ test "non-packed struct with u128 entry in union" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
const U = union(enum) {
|
||||
@ -941,7 +941,7 @@ test "tuple assigned to variable" {
|
||||
|
||||
test "comptime struct field" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (comptime builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
|
||||
if (builtin.cpu.arch.isArm()) return error.SkipZigTest; // TODO
|
||||
|
||||
const T = struct {
|
||||
a: i32,
|
||||
|
||||
@ -2246,12 +2246,12 @@ test "matching captures causes union equivalence" {
|
||||
}
|
||||
|
||||
test "signed enum tag with negative value" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
|
||||
const Enum = enum(i8) {
|
||||
a = -1,
|
||||
|
||||
@ -100,7 +100,7 @@ test "simple variadic function" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
|
||||
if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -161,7 +161,7 @@ test "coerce reference to var arg" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
|
||||
if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -194,7 +194,7 @@ test "variadic functions" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
|
||||
if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -239,7 +239,7 @@ test "copy VaList" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
|
||||
if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -273,7 +273,7 @@ test "unused VaList arg" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
|
||||
if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
|
||||
// https://github.com/ziglang/zig/issues/14096
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ test "vector float operators" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
|
||||
@ -205,7 +205,6 @@ test "array vector coercion - odd sizes" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
@ -308,7 +307,6 @@ test "tuple to vector" {
|
||||
|
||||
test "vector casts of sizes not divisible by 8" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
@ -646,7 +644,7 @@ test "vector division operators" {
|
||||
|
||||
test "vector bitwise not operator" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
@ -754,7 +752,7 @@ test "vector reduce operation" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21091
|
||||
|
||||
@ -989,7 +987,7 @@ test "saturating multiplication" {
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
// TODO: once #9660 has been solved, remove this line
|
||||
if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
|
||||
if (builtin.target.cpu.arch.isWasm()) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
@ -1256,7 +1254,7 @@ test "byte vector initialized in inline function" {
|
||||
if (builtin.cpu.arch == .aarch64_be and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
|
||||
|
||||
if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
|
||||
builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f)))
|
||||
std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f))
|
||||
{
|
||||
// TODO https://github.com/ziglang/zig/issues/13279
|
||||
return error.SkipZigTest;
|
||||
@ -1363,7 +1361,7 @@ test "load packed vector element" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
var x: @Vector(2, u15) = .{ 1, 4 };
|
||||
@ -1411,7 +1409,6 @@ test "store vector with memset" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
|
||||
@ -83,7 +83,7 @@ test "wrapping multiplication" {
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
// TODO: once #9660 has been solved, remove this line
|
||||
if (builtin.cpu.arch == .wasm32) return error.SkipZigTest;
|
||||
if (builtin.cpu.arch.isWasm()) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
|
||||
9
test/behavior/x86_64.zig
Normal file
9
test/behavior/x86_64.zig
Normal file
@ -0,0 +1,9 @@
|
||||
//! CodeGen tests for the x86_64 backend.
|
||||
|
||||
test {
|
||||
const builtin = @import("builtin");
|
||||
if (builtin.zig_backend != .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.object_format == .coff) return error.SkipZigTest;
|
||||
_ = @import("x86_64/math.zig");
|
||||
_ = @import("x86_64/mem.zig");
|
||||
}
|
||||
115
test/behavior/x86_64/build.zig
Normal file
115
test/behavior/x86_64/build.zig
Normal file
@ -0,0 +1,115 @@
|
||||
const std = @import("std");
|
||||
pub fn build(b: *std.Build) void {
|
||||
const compiler_rt_lib = b.addStaticLibrary(.{
|
||||
.name = "compiler_rt",
|
||||
.use_llvm = false,
|
||||
.use_lld = false,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.addWriteFiles().add("compiler_rt.zig", ""),
|
||||
.target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64 }),
|
||||
}),
|
||||
});
|
||||
compiler_rt_lib.bundle_compiler_rt = true;
|
||||
|
||||
for ([_]std.Target.Query{
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.bsf_bsr_0_clobbers_result}),
|
||||
//.cpu_features_sub = std.Target.x86.featureSet(&.{.sse}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.bsf_bsr_0_clobbers_result}),
|
||||
.cpu_features_sub = std.Target.x86.featureSet(&.{
|
||||
.cmov,
|
||||
//.sse,
|
||||
}),
|
||||
},
|
||||
//.{
|
||||
// .cpu_arch = .x86_64,
|
||||
// .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
// .cpu_features_sub = std.Target.x86.featureSet(&.{.sse}),
|
||||
//},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_sub = std.Target.x86.featureSet(&.{.sse2}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.sse3}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.ssse3}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.sse4_1}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.sse4_2}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v2 },
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v2 },
|
||||
.cpu_features_add = std.Target.x86.featureSet(&.{.avx}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v3 },
|
||||
.cpu_features_sub = std.Target.x86.featureSet(&.{.avx2}),
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v3 },
|
||||
},
|
||||
.{
|
||||
.cpu_arch = .x86_64,
|
||||
.cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v4 },
|
||||
},
|
||||
}) |query| {
|
||||
const target = b.resolveTargetQuery(query);
|
||||
const cpu = query.serializeCpuAlloc(b.allocator) catch @panic("OOM");
|
||||
for ([_][]const u8{
|
||||
"math.zig",
|
||||
"mem.zig",
|
||||
}) |path| {
|
||||
const test_mod = b.createModule(.{
|
||||
.root_source_file = b.path(path),
|
||||
.target = target,
|
||||
});
|
||||
const test_exe = b.addTest(.{
|
||||
.name = std.fs.path.stem(path),
|
||||
.use_llvm = false,
|
||||
.use_lld = false,
|
||||
.root_module = test_mod,
|
||||
});
|
||||
if (!std.Target.x86.featureSetHas(target.result.cpu.features, .sse2)) {
|
||||
test_exe.bundle_compiler_rt = false;
|
||||
test_mod.linkLibrary(compiler_rt_lib);
|
||||
}
|
||||
const test_run = b.addRunArtifact(test_exe);
|
||||
b.default_step.dependOn(&test_run.step);
|
||||
for ([_]*std.Build.Step{
|
||||
&test_exe.step,
|
||||
&test_run.step,
|
||||
}) |step| step.name = b.fmt("{s} {s}", .{ step.name, cpu });
|
||||
}
|
||||
}
|
||||
}
|
||||
1103
test/behavior/x86_64/math.zig
Normal file
1103
test/behavior/x86_64/math.zig
Normal file
File diff suppressed because it is too large
Load Diff
37
test/behavior/x86_64/mem.zig
Normal file
37
test/behavior/x86_64/mem.zig
Normal file
@ -0,0 +1,37 @@
|
||||
fn access(comptime array: anytype) !void {
|
||||
var slice: []const @typeInfo(@TypeOf(array)).array.child = undefined;
|
||||
slice = &array;
|
||||
inline for (0.., &array) |ct_index, *elem| {
|
||||
var rt_index: usize = undefined;
|
||||
rt_index = ct_index;
|
||||
if (&(slice.ptr + ct_index)[0] != elem) return error.Unexpected;
|
||||
if (&(slice.ptr + rt_index)[0] != elem) return error.Unexpected;
|
||||
if (&slice.ptr[ct_index..][0] != elem) return error.Unexpected;
|
||||
if (&slice.ptr[rt_index..][0] != elem) return error.Unexpected;
|
||||
if (&slice.ptr[ct_index] != elem) return error.Unexpected;
|
||||
if (&slice.ptr[rt_index] != elem) return error.Unexpected;
|
||||
if (&slice[ct_index..].ptr[0] != elem) return error.Unexpected;
|
||||
if (&slice[rt_index..].ptr[0] != elem) return error.Unexpected;
|
||||
if (&slice[ct_index] != elem) return error.Unexpected;
|
||||
if (&slice[rt_index] != elem) return error.Unexpected;
|
||||
if (slice.ptr[ct_index] != elem.*) return error.Unexpected;
|
||||
if (slice.ptr[rt_index] != elem.*) return error.Unexpected;
|
||||
if (slice[ct_index] != elem.*) return error.Unexpected;
|
||||
if (slice[rt_index] != elem.*) return error.Unexpected;
|
||||
}
|
||||
}
|
||||
test access {
|
||||
try access([3]u8{ 0xdb, 0xef, 0xbd });
|
||||
try access([3]u16{ 0x340e, 0x3654, 0x88d7 });
|
||||
try access([3]u32{ 0xd424c2c0, 0x2d6ac466, 0x5a0cfaba });
|
||||
try access([3]u64{
|
||||
0x9327a4f5221666a6,
|
||||
0x5c34d3ddd84a8b12,
|
||||
0xbae087f39f649260,
|
||||
});
|
||||
try access([3]u128{
|
||||
0x601cf010065444d4d42d5536dd9b95db,
|
||||
0xa03f592fcaa22d40af23a0c735531e3c,
|
||||
0x5da44907b31602b95c2d93f0b582ceab,
|
||||
});
|
||||
}
|
||||
@ -383,7 +383,7 @@ def InstRef_SummaryProvider(value, _=None):
|
||||
'InternPool.Index(%d)' % value.unsigned if value.unsigned < 0x80000000 else 'instructions[%d]' % (value.unsigned - 0x80000000))
|
||||
|
||||
def InstIndex_SummaryProvider(value, _=None):
|
||||
return 'instructions[%d]' % value.unsigned
|
||||
return 'instructions[%d]' % value.unsigned if value.unsigned < 0x80000000 else 'temps[%d]' % (value.unsigned - 0x80000000)
|
||||
|
||||
class zig_DeclIndex_SynthProvider:
|
||||
def __init__(self, value, _=None): self.value = value
|
||||
|
||||
@ -902,8 +902,8 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.features = &.{ "v8a", "exynos" },
|
||||
},
|
||||
},
|
||||
// LLVM removed support for v2 and v3 but zig wants to support targeting old hardware
|
||||
.extra_features = &.{
|
||||
// LLVM removed support for v2 and v3 but zig wants to support targeting old hardware
|
||||
.{
|
||||
.zig_name = "v2",
|
||||
.desc = "ARMv2 architecture",
|
||||
@ -1043,10 +1043,22 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.llvm_name = "64bit-mode",
|
||||
.omit = true,
|
||||
},
|
||||
.{
|
||||
.llvm_name = "alderlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "amdfam10",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "arrowlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "arrowlake-s",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "athlon",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
@ -1081,16 +1093,64 @@ const llvm_targets = [_]LlvmTarget{
|
||||
},
|
||||
.{
|
||||
.llvm_name = "barcelona",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
.extra_deps = &.{ "3dnowa", "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "broadwell",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "c3",
|
||||
.extra_deps = &.{"3dnow"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "cannonlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "cascadelake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "emeraldrapids",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "geode",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "goldmont",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "goldmont_plus",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "haswell",
|
||||
.extra_deps = &.{"smep"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "i386",
|
||||
.extra_deps = &.{"bsf_bsr_0_clobbers_result"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "i486",
|
||||
.extra_deps = &.{"bsf_bsr_0_clobbers_result"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "icelake_client",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "icelake_server",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "ivybridge",
|
||||
.extra_deps = &.{"smep"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "k6-2",
|
||||
.extra_deps = &.{"3dnow"},
|
||||
@ -1127,6 +1187,10 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.llvm_name = "lakemont",
|
||||
.extra_deps = &.{"soft_float"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "meteorlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "opteron",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
@ -1135,6 +1199,38 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.llvm_name = "opteron-sse3",
|
||||
.extra_deps = &.{"3dnowa"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "raptorlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "rocketlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "sapphirerapids",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "silvermont",
|
||||
.extra_deps = &.{"smep"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "skx",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "skylake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "skylake_avx512",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "tigerlake",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "winchip2",
|
||||
.extra_deps = &.{"3dnow"},
|
||||
@ -1143,9 +1239,29 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.llvm_name = "sse4.2",
|
||||
.extra_deps = &.{"crc32"},
|
||||
},
|
||||
.{
|
||||
.llvm_name = "znver1",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "znver2",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "znver3",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "znver4",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = "znver5",
|
||||
.extra_deps = &.{ "smap", "smep" },
|
||||
},
|
||||
},
|
||||
// Features removed from LLVM
|
||||
.extra_features = &.{
|
||||
// Features removed from LLVM
|
||||
.{
|
||||
.zig_name = "3dnow",
|
||||
.desc = "Enable 3DNow! instructions",
|
||||
@ -1171,6 +1287,22 @@ const llvm_targets = [_]LlvmTarget{
|
||||
.desc = "Prefetch with Intent to Write and T1 Hint",
|
||||
.deps = &.{},
|
||||
},
|
||||
// Custom Zig features
|
||||
.{
|
||||
.zig_name = "bsf_bsr_0_clobbers_result",
|
||||
.desc = "BSF/BSR may clobber the lower 32-bits of the result register when the source is zero",
|
||||
.deps = &.{},
|
||||
},
|
||||
.{
|
||||
.zig_name = "smap",
|
||||
.desc = "Enable Supervisor Mode Access Prevention",
|
||||
.deps = &.{},
|
||||
},
|
||||
.{
|
||||
.zig_name = "smep",
|
||||
.desc = "Enable Supervisor Mode Execution Prevention",
|
||||
.deps = &.{},
|
||||
},
|
||||
},
|
||||
.omit_cpus = &.{
|
||||
// LLVM defines a bunch of dumb aliases with foreach loops in X86.td.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user