Merge pull request #17759 from jacobly0/x86_64

x86_64: pass more tests
This commit is contained in:
Andrew Kelley 2023-10-29 13:10:51 -04:00 committed by GitHub
commit fa022d1ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1489 additions and 1412 deletions

View File

@ -35,8 +35,6 @@ fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) !void {
}
test "addtf3" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
// NaN + any = NaN
@ -106,8 +104,6 @@ fn test__addxf3(a: f80, b: f80, expected: u80) !void {
}
test "addxf3" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
// NaN + any = NaN
try test__addxf3(qnan80, 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));
try test__addxf3(@as(f80, @bitCast(@as(u80, 0x7fff_8000_8000_3000_0000))), 0x1.23456789abcdefp+5, @as(u80, @bitCast(qnan80)));

View File

@ -23,8 +23,6 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
}
test "addoti4" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
const min: i128 = math.minInt(i128);
const max: i128 = math.maxInt(i128);
var i: i128 = 1;

View File

@ -98,8 +98,6 @@ pub inline fn cmp_f80(comptime RT: type, a: f80, b: f80) RT {
}
test "cmp_f80" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
inline for (.{ LE, GE }) |RT| {
try std.testing.expect(cmp_f80(RT, 1.0, 1.0) == RT.Equal);
try std.testing.expect(cmp_f80(RT, 0.0, -0.0) == RT.Equal);

View File

@ -134,8 +134,6 @@ pub fn cosl(x: c_longdouble) callconv(.C) c_longdouble {
}
test "cos32" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
const epsilon = 0.00001;
try expect(math.approxEqAbs(f32, cosf(0.0), 1.0, epsilon));

View File

@ -39,8 +39,6 @@ fn test__divxf3(a: f80, b: f80) !void {
}
test "divxf3" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
// NaN / any = NaN
try expect__divxf3_result(math.nan(f80), 0x1.23456789abcdefp+5, 0x7fffC000000000000000);
// inf / any(except inf and nan) = inf

View File

@ -23,9 +23,6 @@ fn test_fmodx_infs() !void {
}
test "fmodx" {
if (builtin.zig_backend == .stage2_x86_64 and
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .lzcnt)) return error.SkipZigTest;
try test_fmodx(6.4, 4.0, 2.4);
try test_fmodx(6.4, -4.0, 2.4);
try test_fmodx(-6.4, 4.0, -2.4);

View File

@ -41,8 +41,6 @@ fn test__fixunssfsi(a: f32, expected: u32) !void {
}
test "fixsfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixsfsi(-math.floatMax(f32), math.minInt(i32));
try test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
@ -71,6 +69,7 @@ test "fixsfsi" {
try test__fixsfsi(-1.0, -1);
try test__fixsfsi(-0.99, 0);
try test__fixsfsi(-0.5, 0);
try test__fixsfsi(-math.floatMin(f32), 0);
try test__fixsfsi(0.0, 0);
try test__fixsfsi(math.floatMin(f32), 0);
@ -106,8 +105,6 @@ test "fixsfsi" {
}
test "fixunssfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunssfsi(0.0, 0);
try test__fixunssfsi(0.5, 0);
@ -147,8 +144,6 @@ fn test__fixunssfdi(a: f32, expected: u64) !void {
}
test "fixsfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixsfdi(-math.floatMax(f32), math.minInt(i64));
try test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
@ -204,8 +199,6 @@ test "fixsfdi" {
}
test "fixunssfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunssfdi(0.0, 0);
try test__fixunssfdi(0.5, 0);
@ -244,8 +237,6 @@ fn test__fixunssfti(a: f32, expected: u128) !void {
}
test "fixsfti" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixsfti(-math.floatMax(f32), math.minInt(i128));
try test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
@ -317,8 +308,6 @@ test "fixsfti" {
}
test "fixunssfti" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunssfti(0.0, 0);
try test__fixunssfti(0.5, 0);
@ -365,8 +354,6 @@ fn test__fixunsdfsi(a: f64, expected: u32) !void {
}
test "fixdfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixdfsi(-math.floatMax(f64), math.minInt(i32));
try test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
@ -428,8 +415,6 @@ test "fixdfsi" {
}
test "fixunsdfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunsdfsi(0.0, 0);
try test__fixunsdfsi(0.5, 0);
@ -472,8 +457,6 @@ fn test__fixunsdfdi(a: f64, expected: u64) !void {
}
test "fixdfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixdfdi(-math.floatMax(f64), math.minInt(i64));
try test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
@ -527,8 +510,6 @@ test "fixdfdi" {
}
test "fixunsdfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunsdfdi(0.0, 0);
try test__fixunsdfdi(0.5, 0);
try test__fixunsdfdi(0.99, 0);
@ -571,8 +552,6 @@ fn test__fixunsdfti(a: f64, expected: u128) !void {
}
test "fixdfti" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixdfti(-math.floatMax(f64), math.minInt(i128));
try test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
@ -626,8 +605,6 @@ test "fixdfti" {
}
test "fixunsdfti" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunsdfti(0.0, 0);
try test__fixunsdfti(0.5, 0);
@ -677,8 +654,6 @@ fn test__fixunstfsi(a: f128, expected: u32) !void {
}
test "fixtfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixtfsi(-math.floatMax(f128), math.minInt(i32));
try test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
@ -742,8 +717,6 @@ test "fixtfsi" {
}
test "fixunstfsi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunstfsi(math.inf(f128), 0xffffffff);
try test__fixunstfsi(0, 0x0);
try test__fixunstfsi(0x1.23456789abcdefp+5, 0x24);
@ -767,8 +740,6 @@ fn test__fixunstfdi(a: f128, expected: u64) !void {
}
test "fixtfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixtfdi(-math.floatMax(f128), math.minInt(i64));
try test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
@ -832,8 +803,6 @@ test "fixtfdi" {
}
test "fixunstfdi" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunstfdi(0.0, 0);
try test__fixunstfdi(0.5, 0);
@ -886,8 +855,6 @@ fn test__fixunstfti(a: f128, expected: u128) !void {
}
test "fixtfti" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixtfti(-math.floatMax(f128), math.minInt(i128));
try test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
@ -969,8 +936,6 @@ fn test__fixunshfti(a: f16, expected: u128) !void {
}
test "fixunshfti for f16" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try test__fixunshfti(math.inf(f16), math.maxInt(u128));
try test__fixunshfti(math.floatMax(f16), 65504);
}

View File

@ -7,8 +7,6 @@ fn test__negti2(a: i128, expected: i128) !void {
}
test "negti2" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
// TODO ensuring that math.minInt(i128); returns error
try test__negti2(-3, 3);

View File

@ -34,9 +34,6 @@ fn test__powixf2(a: f80, b: i32, expected: f80) !void {
}
test "powihf2" {
if (builtin.zig_backend == .stage2_x86_64 and
!comptime std.Target.x86.featureSetHas(builtin.cpu.features, .f16c)) return error.SkipZigTest;
const inf_f16 = math.inf(f16);
try test__powisf2(0, 0, 1);
try test__powihf2(1, 0, 1);
@ -356,8 +353,6 @@ test "powidf2" {
}
test "powitf2" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const inf_f128 = math.inf(f128);
try test__powitf2(0, 0, 1);
try test__powitf2(1, 0, 1);
@ -463,8 +458,6 @@ test "powitf2" {
}
test "powixf2" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const inf_f80 = math.inf(f80);
try test__powixf2(0, 0, 1);
try test__powixf2(1, 0, 1);

View File

@ -140,8 +140,6 @@ pub fn sinl(x: c_longdouble) callconv(.C) c_longdouble {
}
test "sin32" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const epsilon = 0.00001;
try expect(math.approxEqAbs(f32, sinf(0.0), 0.0, epsilon));

View File

@ -27,8 +27,6 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 {
}
test "suboti3" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
const min: i128 = math.minInt(i128);
const max: i128 = math.maxInt(i128);
var i: i128 = 1;

View File

@ -131,8 +131,6 @@ test "tan" {
}
test "tan32" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const epsilon = 0.00001;
try expect(math.approxEqAbs(f32, tanf(0.0), 0.0, epsilon));

View File

@ -440,6 +440,8 @@ test "Condition - multi signal" {
return error.SkipZigTest;
}
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const num_threads = 4;
const num_iterations = 4;

View File

@ -363,8 +363,6 @@ test "phc format - hash without salt" {
}
test "phc format - calcSize" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const s = "$scrypt$v=1$ln=15,r=8,p=1$c2FsdHNhbHQ$dGVzdHBhc3M";
const v = try deserialize(struct {
alg_id: []const u8,

View File

@ -1054,8 +1054,6 @@ fn isOpcodeRegisterLocation(opcode: u8) bool {
const testing = std.testing;
test "DWARF expressions" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const allocator = std.testing.allocator;
const options = ExpressionOptions{};

View File

@ -2435,8 +2435,6 @@ test "float.hexadecimal" {
}
test "float.hexadecimal.precision" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
try expectFmt("f16: 0x1.5p-2", "f16: {x:.1}", .{@as(f16, 1.0 / 3.0)});
try expectFmt("f32: 0x1.555p-2", "f32: {x:.3}", .{@as(f32, 1.0 / 3.0)});
try expectFmt("f64: 0x1.55555p-2", "f64: {x:.5}", .{@as(f64, 1.0 / 3.0)});

View File

@ -1,6 +1,5 @@
const std = @import("std");
const assert = std.debug.assert;
const builtin = @import("builtin");
const mem = std.mem;
const meta = std.meta;
@ -253,8 +252,6 @@ test "typeContainsSlice" {
}
test "hash pointer" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const array = [_]u32{ 123, 123, 123 };
const a = &array[0];
const b = &array[1];
@ -275,8 +272,6 @@ test "hash pointer" {
}
test "hash slice shallow" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
// Allocate one array dynamically so that we're assured it is not merged
// with the other by the optimization passes.
const array1 = try std.testing.allocator.create([6]u32);
@ -295,8 +290,6 @@ test "hash slice shallow" {
}
test "hash slice deep" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
// Allocate one array dynamically so that we're assured it is not merged
// with the other by the optimization passes.
const array1 = try std.testing.allocator.create([6]u32);
@ -313,8 +306,6 @@ test "hash slice deep" {
}
test "hash struct deep" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Foo = struct {
a: u32,
b: u16,
@ -354,8 +345,6 @@ test "hash struct deep" {
}
test "testHash optional" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const a: ?u32 = 123;
const b: ?u32 = null;
try testing.expectEqual(testHash(a), testHash(@as(u32, 123)));
@ -364,8 +353,6 @@ test "testHash optional" {
}
test "testHash array" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const a = [_]u32{ 1, 2, 3 };
const h = testHash(a);
var hasher = Wyhash.init(0);
@ -382,8 +369,6 @@ test "testHash multi-dimensional array" {
}
test "testHash struct" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Foo = struct {
a: u32 = 1,
b: u32 = 2,
@ -399,8 +384,6 @@ test "testHash struct" {
}
test "testHash union" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Foo = union(enum) {
A: u32,
B: bool,
@ -425,8 +408,6 @@ test "testHash union" {
}
test "testHash vector" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 };
const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 };
try testing.expect(testHash(a) == testHash(a));
@ -439,8 +420,6 @@ test "testHash vector" {
}
test "testHash error union" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Errors = error{Test};
const Foo = struct {
a: u32 = 1,

View File

@ -242,8 +242,6 @@ test "smhasher" {
}
test "iterative api" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Test = struct {
fn do() !void {
try verify.iterativeApi(Wyhash);

View File

@ -164,8 +164,6 @@ pub fn bitReader(
}
test "api coverage" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
const mem_be = [_]u8{ 0b11001101, 0b00001011 };
const mem_le = [_]u8{ 0b00011101, 0b10010101 };

View File

@ -1,5 +1,4 @@
const std = @import("std");
const builtin = @import("builtin");
const io = std.io;
const meta = std.meta;
const trait = std.trait;
@ -10,7 +9,7 @@ const expectError = std.testing.expectError;
const mem = std.mem;
const fs = std.fs;
const File = std.fs.File;
const native_endian = builtin.target.cpu.arch.endian();
const native_endian = @import("builtin").target.cpu.arch.endian();
const tmpDir = std.testing.tmpDir;
@ -61,8 +60,6 @@ test "write a file, read it, then delete it" {
}
test "BitStreams with File Stream" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var tmp = tmpDir(.{});
defer tmp.cleanup();

View File

@ -1,4 +1,3 @@
const builtin = @import("builtin");
const std = @import("std");
const testing = std.testing;
@ -215,8 +214,6 @@ fn test_read_uleb128_seq(comptime T: type, comptime N: usize, encoded: []const u
}
test "deserialize signed LEB128" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
// Truncated
try testing.expectError(error.EndOfStream, test_read_stream_ileb128(i64, "\x80"));
@ -363,8 +360,6 @@ test "serialize unsigned LEB128" {
}
test "serialize signed LEB128" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
// explicitly test i0 because starting `t` at 0
// will break the while loop
try test_write_leb128(@as(i0, 0));

View File

@ -990,8 +990,6 @@ test "big.int mul 0*0" {
}
test "big.int mul large" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var a = try Managed.initCapacity(testing.allocator, 50);
defer a.deinit();
var b = try Managed.initCapacity(testing.allocator, 100);
@ -1075,8 +1073,6 @@ test "big.int mulWrap multi-multi signed" {
}
test "big.int mulWrap large" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
var a = try Managed.initCapacity(testing.allocator, 50);
defer a.deinit();
var b = try Managed.initCapacity(testing.allocator, 100);

View File

@ -108,8 +108,6 @@ test "64" {
}
test "80" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
try expect(ilogbX(f80, 0.0) == fp_ilogb0);
try expect(ilogbX(f80, 0.5) == -1);
try expect(ilogbX(f80, 0.8923) == -1);

View File

@ -67,8 +67,6 @@ pub fn ldexp(x: anytype, n: i32) @TypeOf(x) {
}
test "math.ldexp" {
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
// subnormals
try expect(ldexp(@as(f16, 0x1.1FFp14), -14 - 9 - 15) == math.floatTrueMin(f16));
try expect(ldexp(@as(f32, 0x1.3FFFFFp-1), -126 - 22) == math.floatTrueMin(f32));

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ const Encoding = @import("Encoding.zig");
const Immediate = bits.Immediate;
const Instruction = encoder.Instruction;
const LegacyPrefixes = encoder.LegacyPrefixes;
const Memory = bits.Memory;
const Memory = Instruction.Memory;
const Register = bits.Register;
const Rex = encoder.Rex;

View File

@ -1,7 +1,6 @@
//! This file contains the functionality for emitting x86_64 MIR as machine code
lower: Lower,
bin_file: *link.File,
debug_output: DebugInfoOutput,
code: *std.ArrayList(u8),
@ -41,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.offset = end_offset - 4,
.length = @intCast(end_offset - start_offset),
}),
.linker_extern_fn => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
// Add relocation to the decl.
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
try atom_ptr.addReloc(elf_file, .{
@ -49,9 +48,10 @@ pub fn emitMir(emit: *Emit) Error!void {
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | std.elf.R_X86_64_PLT32,
.r_addend = -4,
});
} else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
// Add relocation to the decl.
const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
const atom_index =
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
const target = macho_file.getGlobalByIndex(symbol.sym_index);
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
.type = .branch,
@ -61,7 +61,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.pcrel = true,
.length = 2,
});
} else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
// Add relocation to the decl.
const atom_index = coff_file.getAtomIndexForSymbol(
.{ .sym_index = symbol.atom_index, .file = null },
@ -76,12 +76,12 @@ pub fn emitMir(emit: *Emit) Error!void {
.length = 2,
});
} else return emit.fail("TODO implement extern reloc for {s}", .{
@tagName(emit.bin_file.tag),
@tagName(emit.lower.bin_file.tag),
}),
.linker_reloc => |data| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
.linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index));
if (emit.bin_file.options.pic) {
if (emit.lower.bin_file.options.pic) {
const r_type: u32 = if (sym.flags.has_zig_got)
link.File.Elf.R_X86_64_ZIG_GOTPCREL
else if (sym.flags.needs_got)
@ -111,10 +111,11 @@ pub fn emitMir(emit: *Emit) Error!void {
.linker_direct,
.linker_import,
.linker_tlv,
=> |symbol| if (emit.bin_file.cast(link.File.Elf)) |_| {
=> |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |_| {
unreachable;
} else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
const atom_index =
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
.type = switch (lowered_relocs[0].target) {
.linker_got => .got,
@ -128,7 +129,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.pcrel = true,
.length = 2,
});
} else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
} else if (emit.lower.bin_file.cast(link.File.Coff)) |coff_file| {
const atom_index = coff_file.getAtomIndexForSymbol(.{
.sym_index = symbol.atom_index,
.file = null,
@ -152,7 +153,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.pcrel = true,
.length = 2,
});
} else if (emit.bin_file.cast(link.File.Plan9)) |p9_file| {
} else if (emit.lower.bin_file.cast(link.File.Plan9)) |p9_file| {
const atom_index = symbol.atom_index;
try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct
.target = symbol.sym_index, // we set sym_index to just be the atom index
@ -161,7 +162,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.type = .pcrel,
});
} else return emit.fail("TODO implement linker reloc for {s}", .{
@tagName(emit.bin_file.tag),
@tagName(emit.lower.bin_file.tag),
}),
};
}

View File

@ -803,7 +803,10 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
@memcpy(inst.ops[0..ops.len], ops);
var cwriter = std.io.countingWriter(std.io.null_writer);
inst.encode(cwriter.writer(), .{ .allow_frame_loc = true }) catch unreachable; // Not allowed to fail here unless OOM.
inst.encode(cwriter.writer(), .{
.allow_frame_locs = true,
.allow_symbols = true,
}) catch unreachable; // Not allowed to fail here unless OOM.
return @as(usize, @intCast(cwriter.bytes_written));
}

View File

@ -50,12 +50,12 @@ pub const Reloc = struct {
const Target = union(enum) {
inst: Mir.Inst.Index,
linker_reloc: Mir.Reloc,
linker_extern_fn: Mir.Reloc,
linker_got: Mir.Reloc,
linker_direct: Mir.Reloc,
linker_import: Mir.Reloc,
linker_tlv: Mir.Reloc,
linker_reloc: bits.Symbol,
linker_extern_fn: bits.Symbol,
linker_got: bits.Symbol,
linker_direct: bits.Symbol,
linker_import: bits.Symbol,
linker_tlv: bits.Symbol,
};
};
@ -99,17 +99,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .reg = inst.data.rr.r2 },
});
},
.pseudo_cmov_nz_or_p_rm_sib,
.pseudo_cmov_nz_or_p_rm_rip,
=> {
.pseudo_cmov_nz_or_p_rm => {
assert(inst.data.rx.fixes == ._);
try lower.emit(.none, .cmovnz, &.{
.{ .reg = inst.data.rx.r1 },
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
});
try lower.emit(.none, .cmovp, &.{
.{ .reg = inst.data.rx.r1 },
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
});
},
.pseudo_set_z_and_np_r => {
@ -125,18 +123,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .reg = inst.data.rr.r2 },
});
},
.pseudo_set_z_and_np_m_sib,
.pseudo_set_z_and_np_m_rip,
=> {
.pseudo_set_z_and_np_m => {
assert(inst.data.rx.fixes == ._);
try lower.emit(.none, .setz, &.{
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
});
try lower.emit(.none, .setnp, &.{
.{ .reg = inst.data.rx.r1 },
});
try lower.emit(.none, .@"and", &.{
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
.{ .reg = inst.data.rx.r1 },
});
},
@ -153,18 +149,16 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.{ .reg = inst.data.rr.r2 },
});
},
.pseudo_set_nz_or_p_m_sib,
.pseudo_set_nz_or_p_m_rip,
=> {
.pseudo_set_nz_or_p_m => {
assert(inst.data.rx.fixes == ._);
try lower.emit(.none, .setnz, &.{
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
});
try lower.emit(.none, .setp, &.{
.{ .reg = inst.data.rx.r1 },
});
try lower.emit(.none, .@"or", &.{
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
.{ .reg = inst.data.rx.r1 },
});
},
@ -289,28 +283,20 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
.rri_s,
.ri_s,
.i_s,
.mi_sib_s,
.mi_rip_s,
.rmi_sib_s,
.rmi_rip_s,
.mi_s,
.rmi_s,
=> Immediate.s(@bitCast(i)),
.rrri,
.rri_u,
.ri_u,
.i_u,
.mi_sib_u,
.mi_rip_u,
.rmi_sib,
.rmi_rip,
.rmi_sib_u,
.rmi_rip_u,
.mri_sib,
.mri_rip,
.rrm_sib,
.rrm_rip,
.rrmi_sib,
.rrmi_rip,
.mi_u,
.rmi,
.rmi_u,
.mri,
.rrm,
.rrmi,
=> Immediate.u(i),
.ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()),
@ -319,50 +305,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
};
}
fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
return lower.mir.resolveFrameLoc(switch (ops) {
.rm_sib,
.rmi_sib,
.rmi_sib_s,
.rmi_sib_u,
.m_sib,
.mi_sib_u,
.mi_sib_s,
.mr_sib,
.mrr_sib,
.mri_sib,
.rrm_sib,
.rrmi_sib,
.pseudo_cmov_nz_or_p_rm_sib,
.pseudo_set_z_and_np_m_sib,
.pseudo_set_nz_or_p_m_sib,
=> lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
.rm_rip,
.rmi_rip,
.rmi_rip_s,
.rmi_rip_u,
.m_rip,
.mi_rip_u,
.mi_rip_s,
.mr_rip,
.mrr_rip,
.mri_rip,
.rrm_rip,
.rrmi_rip,
.pseudo_cmov_nz_or_p_rm_rip,
.pseudo_set_z_and_np_m_rip,
.pseudo_set_nz_or_p_m_rip,
=> lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
.rax_moffs,
.moffs_rax,
=> lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
else => unreachable,
});
fn mem(lower: Lower, payload: u32) Memory {
return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode();
}
fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
@ -375,7 +319,42 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
}
fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
var emit_prefix = prefix;
var emit_mnemonic = mnemonic;
var emit_ops_storage: [4]Operand = undefined;
const emit_ops = emit_ops_storage[0..ops.len];
for (emit_ops, ops) |*emit_op, op| {
emit_op.* = switch (op) {
else => op,
.mem => |mem_op| switch (mem_op.base()) {
else => op,
.reloc => |sym| op: {
assert(prefix == .none);
assert(mem_op.sib.disp == 0);
assert(mem_op.sib.scale_index.scale == 0);
_ = lower.reloc(.{ .linker_reloc = sym });
break :op if (lower.bin_file.options.pic) switch (mnemonic) {
.mov, .lea => .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
else => unreachable,
} else switch (mnemonic) {
.call => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .ds },
}) },
.lea => {
emit_mnemonic = .mov;
break :op .{ .imm = Immediate.s(0) };
},
.mov => .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .ds },
}) },
else => unreachable,
};
},
},
};
}
lower.result_insts[lower.result_insts_len] =
try Instruction.new(emit_prefix, emit_mnemonic, emit_ops);
lower.result_insts_len += 1;
}
@ -391,74 +370,13 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.rrri => inst.data.rrri.fixes,
.rri_s, .rri_u => inst.data.rri.fixes,
.ri_s, .ri_u => inst.data.ri.fixes,
.ri64,
.rm_sib,
.rm_rip,
.rmi_sib_s,
.rmi_sib_u,
.rmi_rip_s,
.rmi_rip_u,
.mr_sib,
.mr_rip,
=> inst.data.rx.fixes,
.mrr_sib, .mrr_rip, .rrm_sib, .rrm_rip => inst.data.rrx.fixes,
.rmi_sib, .rmi_rip, .mri_sib, .mri_rip => inst.data.rix.fixes,
.rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
.mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => inst.data.x.fixes,
.m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
.extern_fn_reloc,
.got_reloc,
.direct_reloc,
.import_reloc,
.tlv_reloc,
=> ._,
.linker_reloc => {
if (lower.bin_file.options.pic) {
assert(inst.data.rx.fixes == ._);
const reg = inst.data.rx.r1;
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
_ = lower.reloc(.{ .linker_reloc = extra });
const mnemonic: Mnemonic = switch (inst.tag) {
.mov => .mov,
.lea => .lea,
else => unreachable,
};
try lower.emit(.none, mnemonic, &.{
.{ .reg = reg },
.{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
});
} else {
switch (inst.tag) {
.call => {
_ = lower.reloc(.{ .linker_reloc = inst.data.reloc });
try lower.emit(.none, .call, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
});
},
.lea => {
assert(inst.data.rx.fixes == ._);
const reg = inst.data.rx.r1;
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
try lower.emit(.none, .mov, &.{
.{ .reg = reg },
.{ .imm = lower.reloc(.{ .linker_reloc = extra }) },
});
},
.mov => {
assert(inst.data.rx.fixes == ._);
const reg = inst.data.rx.r1;
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
_ = lower.reloc(.{ .linker_reloc = extra });
try lower.emit(.none, .mov, &.{
.{ .reg = reg },
.{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
});
},
else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
}
}
return;
},
.ri64, .rm, .rmi_s, .mr => inst.data.rx.fixes,
.mrr, .rrm => inst.data.rrx.fixes,
.rmi, .mri => inst.data.rix.fixes,
.rrmi => inst.data.rrix.fixes,
.mi_u, .mi_s => inst.data.x.fixes,
.m => inst.data.x.fixes,
.extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
};
try lower.emit(switch (fixes) {
@ -527,73 +445,64 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.{ .reg = inst.data.rri.r2 },
.{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
},
.m_sib, .m_rip => &.{
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
.m => &.{
.{ .mem = lower.mem(inst.data.x.payload) },
},
.mi_sib_s, .mi_sib_u, .mi_rip_s, .mi_rip_u => &.{
.{ .mem = lower.mem(inst.ops, inst.data.x.payload + 1) },
.mi_s, .mi_u => &.{
.{ .mem = lower.mem(inst.data.x.payload + 1) },
.{ .imm = lower.imm(
inst.ops,
lower.mir.extraData(Mir.Imm32, inst.data.x.payload).data.imm,
) },
},
.rm_sib, .rm_rip => &.{
.rm => &.{
.{ .reg = inst.data.rx.r1 },
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.{ .mem = lower.mem(inst.data.rx.payload) },
},
.rmi_sib, .rmi_rip => &.{
.rmi => &.{
.{ .reg = inst.data.rix.r1 },
.{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
.{ .mem = lower.mem(inst.data.rix.payload) },
.{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
},
.rmi_sib_s, .rmi_sib_u, .rmi_rip_s, .rmi_rip_u => &.{
.rmi_s, .rmi_u => &.{
.{ .reg = inst.data.rx.r1 },
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload + 1) },
.{ .mem = lower.mem(inst.data.rx.payload + 1) },
.{ .imm = lower.imm(
inst.ops,
lower.mir.extraData(Mir.Imm32, inst.data.rx.payload).data.imm,
) },
},
.mr_sib, .mr_rip => &.{
.{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
.mr => &.{
.{ .mem = lower.mem(inst.data.rx.payload) },
.{ .reg = inst.data.rx.r1 },
},
.mrr_sib, .mrr_rip => &.{
.{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
.mrr => &.{
.{ .mem = lower.mem(inst.data.rrx.payload) },
.{ .reg = inst.data.rrx.r1 },
.{ .reg = inst.data.rrx.r2 },
},
.mri_sib, .mri_rip => &.{
.{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
.mri => &.{
.{ .mem = lower.mem(inst.data.rix.payload) },
.{ .reg = inst.data.rix.r1 },
.{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
},
.rrm_sib, .rrm_rip => &.{
.rrm => &.{
.{ .reg = inst.data.rrx.r1 },
.{ .reg = inst.data.rrx.r2 },
.{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
.{ .mem = lower.mem(inst.data.rrx.payload) },
},
.rrmi_sib, .rrmi_rip => &.{
.rrmi => &.{
.{ .reg = inst.data.rrix.r1 },
.{ .reg = inst.data.rrix.r2 },
.{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
.{ .mem = lower.mem(inst.data.rrix.payload) },
.{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
},
.rax_moffs => &.{
.{ .reg = .rax },
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
},
.moffs_rax => &.{
.{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
.{ .reg = .rax },
},
.extern_fn_reloc => &.{
.{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
},
.linker_reloc => unreachable,
.got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
const reg = inst.data.rx.r1;
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data;
_ = lower.reloc(switch (inst.ops) {
.got_reloc => .{ .linker_got = extra },
.direct_reloc => .{ .linker_direct = extra },
@ -635,7 +544,7 @@ const ErrorMsg = Module.ErrorMsg;
const Immediate = bits.Immediate;
const Instruction = encoder.Instruction;
const Lower = @This();
const Memory = bits.Memory;
const Memory = Instruction.Memory;
const Mir = @import("Mir.zig");
const Mnemonic = Instruction.Mnemonic;
const Module = @import("../../Module.zig");

View File

@ -17,7 +17,6 @@ const encoder = @import("encoder.zig");
const Air = @import("../../Air.zig");
const CodeGen = @import("CodeGen.zig");
const IntegerBitSet = std.bit_set.IntegerBitSet;
const Memory = bits.Memory;
const Register = bits.Register;
instructions: std.MultiArrayList(Inst).Slice,
@ -767,84 +766,42 @@ pub const Inst = struct {
/// Relative displacement operand.
/// Uses `imm` payload.
rel,
/// Register, memory (SIB) operands.
/// Register, memory operands.
/// Uses `rx` payload.
rm_sib,
/// Register, memory (RIP) operands.
/// Uses `rx` payload.
rm_rip,
/// Register, memory (SIB), immediate (word) operands.
/// Uses `rix` payload with extra data of type `MemorySib`.
rmi_sib,
/// Register, memory (RIP), immediate (word) operands.
/// Uses `rix` payload with extra data of type `MemoryRip`.
rmi_rip,
/// Register, memory (SIB), immediate (signed) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemorySib`.
rmi_sib_s,
/// Register, memory (SIB), immediate (unsigned) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemorySib`.
rmi_sib_u,
/// Register, memory (RIP), immediate (signed) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemoryRip`.
rmi_rip_s,
/// Register, memory (RIP), immediate (unsigned) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `MemoryRip`.
rmi_rip_u,
/// Register, register, memory (RIP).
/// Uses `rrix` payload with extra data of type `MemoryRip`.
rrm_rip,
/// Register, register, memory (SIB).
/// Uses `rrix` payload with extra data of type `MemorySib`.
rrm_sib,
/// Register, register, memory (RIP), immediate (byte) operands.
/// Uses `rrix` payload with extra data of type `MemoryRip`.
rrmi_rip,
/// Register, register, memory (SIB), immediate (byte) operands.
/// Uses `rrix` payload with extra data of type `MemorySib`.
rrmi_sib,
/// Single memory (SIB) operand.
/// Uses `x` with extra data of type `MemorySib`.
m_sib,
/// Single memory (RIP) operand.
/// Uses `x` with extra data of type `MemoryRip`.
m_rip,
/// Memory (SIB), immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
mi_sib_s,
/// Memory (SIB), immediate (unsigned) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `MemorySib`.
mi_sib_u,
/// Memory (RIP), immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
mi_rip_s,
/// Memory (RIP), immediate (unsigned) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `MemoryRip`.
mi_rip_u,
/// Memory (SIB), register operands.
/// Uses `rx` payload with extra data of type `MemorySib`.
mr_sib,
/// Memory (RIP), register operands.
/// Uses `rx` payload with extra data of type `MemoryRip`.
mr_rip,
/// Memory (SIB), register, register operands.
/// Uses `rrx` payload with extra data of type `MemorySib`.
mrr_sib,
/// Memory (RIP), register, register operands.
/// Uses `rrx` payload with extra data of type `MemoryRip`.
mrr_rip,
/// Memory (SIB), register, immediate (word) operands.
/// Uses `rix` payload with extra data of type `MemorySib`.
mri_sib,
/// Memory (RIP), register, immediate (word) operands.
/// Uses `rix` payload with extra data of type `MemoryRip`.
mri_rip,
/// Rax, Memory moffs.
/// Uses `x` with extra data of type `MemoryMoffs`.
rax_moffs,
/// Memory moffs, rax.
/// Uses `x` with extra data of type `MemoryMoffs`.
moffs_rax,
rm,
/// Register, memory, immediate (word) operands.
/// Uses `rix` payload with extra data of type `Memory`.
rmi,
/// Register, memory, immediate (signed) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
rmi_s,
/// Register, memory, immediate (unsigned) operands.
/// Uses `rx` payload with extra data of type `Imm32` followed by `Memory`.
rmi_u,
/// Register, register, memory.
/// Uses `rrix` payload with extra data of type `Memory`.
rrm,
/// Register, register, memory, immediate (byte) operands.
/// Uses `rrix` payload with extra data of type `Memory`.
rrmi,
/// Single memory operand.
/// Uses `x` with extra data of type `Memory`.
m,
/// Memory, immediate (sign-extend) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
mi_s,
/// Memory, immediate (unsigned) operands.
/// Uses `x` payload with extra data of type `Imm32` followed by `Memory`.
mi_u,
/// Memory, register operands.
/// Uses `rx` payload with extra data of type `Memory`.
mr,
/// Memory, register, register operands.
/// Uses `rrx` payload with extra data of type `Memory`.
mrr,
/// Memory, register, immediate (word) operands.
/// Uses `rix` payload with extra data of type `Memory`.
mri,
/// References another Mir instruction directly.
/// Uses `inst` payload.
inst,
@ -852,20 +809,17 @@ pub const Inst = struct {
/// Uses `reloc` payload.
extern_fn_reloc,
/// Linker relocation - GOT indirection.
/// Uses `rx` payload with extra data of type `Reloc`.
/// Uses `rx` payload with extra data of type `bits.Symbol`.
got_reloc,
/// Linker relocation - direct reference.
/// Uses `rx` payload with extra data of type `Reloc`.
/// Uses `rx` payload with extra data of type `bits.Symbol`.
direct_reloc,
/// Linker relocation - imports table indirection (binding).
/// Uses `rx` payload with extra data of type `Reloc`.
/// Uses `rx` payload with extra data of type `bits.Symbol`.
import_reloc,
/// Linker relocation - threadlocal variable via GOT indirection.
/// Uses `rx` payload with extra data of type `Reloc`.
/// Uses `rx` payload with extra data of type `bits.Symbol`.
tlv_reloc,
/// Linker relocation.
/// Uses `rx` payload with extra data of type `Reloc`.
linker_reloc,
// Pseudo instructions:
@ -878,10 +832,7 @@ pub const Inst = struct {
pseudo_cmov_nz_or_p_rr,
/// Conditional move if zero flag not set or parity flag set
/// Uses `rx` payload.
pseudo_cmov_nz_or_p_rm_sib,
/// Conditional move if zero flag not set or parity flag set
/// Uses `rx` payload.
pseudo_cmov_nz_or_p_rm_rip,
pseudo_cmov_nz_or_p_rm,
/// Set byte if zero flag set and parity flag not set
/// Requires a scratch register!
/// Uses `rr` payload.
@ -889,11 +840,7 @@ pub const Inst = struct {
/// Set byte if zero flag set and parity flag not set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_z_and_np_m_sib,
/// Set byte if zero flag set and parity flag not set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_z_and_np_m_rip,
pseudo_set_z_and_np_m,
/// Set byte if zero flag not set or parity flag set
/// Requires a scratch register!
/// Uses `rr` payload.
@ -901,11 +848,7 @@ pub const Inst = struct {
/// Set byte if zero flag not set or parity flag set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_nz_or_p_m_sib,
/// Set byte if zero flag not set or parity flag set
/// Requires a scratch register!
/// Uses `rx` payload.
pseudo_set_nz_or_p_m_rip,
pseudo_set_nz_or_p_m,
/// Jump if zero flag set and parity flag not set
/// Uses `inst` payload.
pseudo_j_z_and_np_inst,
@ -1036,7 +979,7 @@ pub const Inst = struct {
/// Relocation for the linker where:
/// * `atom_index` is the index of the source
/// * `sym_index` is the index of the target
reloc: Reloc,
reloc: bits.Symbol,
/// Debug line and column position
line_column: struct {
line: u32,
@ -1055,14 +998,6 @@ pub const Inst = struct {
}
};
/// A linker symbol not yet allocated in VM.
pub const Reloc = struct {
/// Index of the containing atom.
atom_index: u32,
/// Index into the linker's symbol table.
sym_index: u32,
};
/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
pub const RegisterList = struct {
bitset: BitSet = BitSet.initEmpty(),
@ -1123,100 +1058,94 @@ pub const Imm64 = struct {
}
};
// TODO this can be further compacted using packed struct
pub const MemorySib = struct {
/// Size of the pointer.
ptr_size: u32,
/// Base register tag of type Memory.Base.Tag
base_tag: u32,
/// Base register of type Register or FrameIndex
pub const Memory = struct {
info: Info,
base: u32,
/// Scale starting at bit 0 and index register starting at bit 4.
scale_index: u32,
/// Displacement value.
disp: i32,
off: u32,
extra: u32,
pub fn encode(mem: Memory) MemorySib {
const sib = mem.sib;
assert(sib.scale_index.scale == 0 or std.math.isPowerOfTwo(sib.scale_index.scale));
pub const Info = packed struct(u32) {
base: @typeInfo(bits.Memory.Base).Union.tag_type.?,
mod: @typeInfo(bits.Memory.Mod).Union.tag_type.?,
size: bits.Memory.Size,
index: Register,
scale: bits.Memory.Scale,
_: u16 = undefined,
};
pub fn encode(mem: bits.Memory) Memory {
assert(mem.base != .reloc or mem.mod != .off);
return .{
.ptr_size = @intFromEnum(sib.ptr_size),
.base_tag = @intFromEnum(sib.base),
.base = switch (sib.base) {
.info = .{
.base = mem.base,
.mod = mem.mod,
.size = switch (mem.mod) {
.rm => |rm| rm.size,
.off => undefined,
},
.index = switch (mem.mod) {
.rm => |rm| rm.index,
.off => undefined,
},
.scale = switch (mem.mod) {
.rm => |rm| rm.scale,
.off => undefined,
},
},
.base = switch (mem.base) {
.none => undefined,
.reg => |r| @intFromEnum(r),
.frame => |fi| @intFromEnum(fi),
.reg => |reg| @intFromEnum(reg),
.frame => |frame_index| @intFromEnum(frame_index),
.reloc => |symbol| symbol.sym_index,
},
.scale_index = @as(u32, sib.scale_index.scale) << 0 |
@as(u32, if (sib.scale_index.scale > 0)
@intFromEnum(sib.scale_index.index)
.off = switch (mem.mod) {
.rm => |rm| @bitCast(rm.disp),
.off => |off| @truncate(off),
},
.extra = if (mem.base == .reloc)
mem.base.reloc.atom_index
else if (mem.mod == .off)
@intCast(mem.mod.off >> 32)
else
undefined) << 4,
.disp = sib.disp,
undefined,
};
}
pub fn decode(msib: MemorySib) Memory {
const scale: u4 = @truncate(msib.scale_index);
assert(scale == 0 or std.math.isPowerOfTwo(scale));
return .{ .sib = .{
.ptr_size = @enumFromInt(msib.ptr_size),
.base = switch (@as(Memory.Base.Tag, @enumFromInt(msib.base_tag))) {
.none => .none,
.reg => .{ .reg = @enumFromInt(msib.base) },
.frame => .{ .frame = @enumFromInt(msib.base) },
pub fn decode(mem: Memory) encoder.Instruction.Memory {
switch (mem.info.mod) {
.rm => {
if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) {
assert(mem.info.index == .none and mem.info.scale == .@"1");
return encoder.Instruction.Memory.rip(mem.info.size, @bitCast(mem.off));
}
return encoder.Instruction.Memory.sib(mem.info.size, .{
.disp = @bitCast(mem.off),
.base = switch (mem.info.base) {
.none => .none,
.reg => .{ .reg = @enumFromInt(mem.base) },
.frame => .{ .frame = @enumFromInt(mem.base) },
.reloc => .{ .reloc = .{ .atom_index = mem.extra, .sym_index = mem.base } },
},
.scale_index = switch (mem.info.index) {
.none => null,
else => |index| .{ .scale = switch (mem.info.scale) {
inline else => |scale| comptime std.fmt.parseInt(
u4,
@tagName(scale),
10,
) catch unreachable,
}, .index = index },
},
});
},
.scale_index = .{
.scale = scale,
.index = if (scale > 0) @enumFromInt(msib.scale_index >> 4) else undefined,
.off => {
assert(mem.info.base == .reg);
return encoder.Instruction.Memory.moffs(
@enumFromInt(mem.base),
@as(u64, mem.extra) << 32 | mem.off,
);
},
.disp = msib.disp,
} };
}
};
pub const MemoryRip = struct {
/// Size of the pointer.
ptr_size: u32,
/// Displacement value.
disp: i32,
pub fn encode(mem: Memory) MemoryRip {
return .{
.ptr_size = @intFromEnum(mem.rip.ptr_size),
.disp = mem.rip.disp,
};
}
pub fn decode(mrip: MemoryRip) Memory {
return .{ .rip = .{
.ptr_size = @enumFromInt(mrip.ptr_size),
.disp = mrip.disp,
} };
}
};
pub const MemoryMoffs = struct {
/// Segment register.
seg: u32,
/// Absolute offset wrt to the segment register split between MSB and LSB parts much like
/// `Imm64` payload.
msb: u32,
lsb: u32,
pub fn encode(seg: Register, offset: u64) MemoryMoffs {
return .{
.seg = @intFromEnum(seg),
.msb = @truncate(offset >> 32),
.lsb = @truncate(offset >> 0),
};
}
pub fn decode(moffs: MemoryMoffs) Memory {
return .{ .moffs = .{
.seg = @enumFromInt(moffs.seg),
.offset = @as(u64, moffs.msb) << 32 | @as(u64, moffs.lsb) << 0,
} };
}
}
};
@ -1234,8 +1163,8 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end:
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => mir.extra[i],
i32 => @bitCast(mir.extra[i]),
else => @compileError("bad field type"),
i32, Memory.Info => @bitCast(mir.extra[i]),
else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
};
i += 1;
}
@ -1251,15 +1180,19 @@ pub const FrameLoc = struct {
};
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
return switch (mem) {
.sib => |sib| switch (sib.base) {
.none, .reg => mem,
.frame => |index| if (mir.frame_locs.len > 0) Memory.sib(sib.ptr_size, .{
.base = .{ .reg = mir.frame_locs.items(.base)[@intFromEnum(index)] },
.disp = mir.frame_locs.items(.disp)[@intFromEnum(index)] + sib.disp,
.scale_index = mem.scaleIndex(),
}) else mem,
},
.rip, .moffs => mem,
return switch (mem.info.base) {
.none, .reg, .reloc => mem,
.frame => if (mir.frame_locs.len > 0) Memory{
.info = .{
.base = .reg,
.mod = mem.info.mod,
.size = mem.info.size,
.index = mem.info.index,
.scale = mem.info.scale,
},
.base = @intFromEnum(mir.frame_locs.items(.base)[mem.base]),
.off = @bitCast(mir.frame_locs.items(.disp)[mem.base] + @as(i32, @bitCast(mem.off))),
.extra = mem.extra,
} else mem,
};
}

View File

@ -181,6 +181,8 @@ pub const Register = enum(u7) {
es, cs, ss, ds, fs, gs,
rip, eip, ip,
none,
// zig fmt: on
@ -442,34 +444,58 @@ pub const FrameIndex = enum(u32) {
}
};
pub const Memory = union(enum) {
sib: Sib,
rip: Rip,
moffs: Moffs,
/// A linker symbol not yet allocated in VM.
pub const Symbol = struct {
/// Index of the containing atom.
atom_index: u32,
/// Index into the linker's symbol table.
sym_index: u32,
pub const Base = union(enum) {
pub fn format(
sym: Symbol,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
try writer.writeAll("Symbol(");
try std.fmt.formatType(sym.atom_index, fmt, options, writer, 0);
try writer.writeAll(", ");
try std.fmt.formatType(sym.sym_index, fmt, options, writer, 0);
try writer.writeByte(')');
}
};
pub const Memory = struct {
base: Base,
mod: Mod,
pub const Base = union(enum(u2)) {
none,
reg: Register,
frame: FrameIndex,
reloc: Symbol,
pub const Tag = @typeInfo(Base).Union.tag_type.?;
pub fn isExtended(self: Base) bool {
return switch (self) {
.none, .frame => false, // neither rsp nor rbp are extended
.none, .frame, .reloc => false, // rsp, rbp, and rip are not extended
.reg => |reg| reg.isExtended(),
};
}
};
pub const ScaleIndex = struct {
scale: u4,
index: Register,
const none = ScaleIndex{ .scale = 0, .index = undefined };
pub const Mod = union(enum(u1)) {
rm: struct {
size: Size,
index: Register = .none,
scale: Scale = .@"1",
disp: i32 = 0,
},
off: u64,
};
pub const PtrSize = enum {
pub const Size = enum(u4) {
none,
byte,
word,
@ -480,7 +506,7 @@ pub const Memory = union(enum) {
yword,
zword,
pub fn fromSize(size: u32) PtrSize {
pub fn fromSize(size: u32) Size {
return switch (size) {
1...1 => .byte,
2...2 => .word,
@ -493,7 +519,7 @@ pub const Memory = union(enum) {
};
}
pub fn fromBitSize(bit_size: u64) PtrSize {
pub fn fromBitSize(bit_size: u64) Size {
return switch (bit_size) {
8 => .byte,
16 => .word,
@ -507,7 +533,7 @@ pub const Memory = union(enum) {
};
}
pub fn bitSize(s: PtrSize) u64 {
pub fn bitSize(s: Size) u64 {
return switch (s) {
.none => 0,
.byte => 8,
@ -522,7 +548,7 @@ pub const Memory = union(enum) {
}
pub fn format(
s: PtrSize,
s: Size,
comptime _: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
@ -533,79 +559,7 @@ pub const Memory = union(enum) {
}
};
pub const Sib = struct {
ptr_size: PtrSize,
base: Base,
scale_index: ScaleIndex,
disp: i32,
};
pub const Rip = struct {
ptr_size: PtrSize,
disp: i32,
};
pub const Moffs = struct {
seg: Register,
offset: u64,
};
pub fn moffs(reg: Register, offset: u64) Memory {
assert(reg.class() == .segment);
return .{ .moffs = .{ .seg = reg, .offset = offset } };
}
pub fn sib(ptr_size: PtrSize, args: struct {
disp: i32 = 0,
base: Base = .none,
scale_index: ?ScaleIndex = null,
}) Memory {
if (args.scale_index) |si| assert(std.math.isPowerOfTwo(si.scale));
return .{ .sib = .{
.base = args.base,
.disp = args.disp,
.ptr_size = ptr_size,
.scale_index = if (args.scale_index) |si| si else ScaleIndex.none,
} };
}
pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
}
pub fn isSegmentRegister(mem: Memory) bool {
return switch (mem) {
.moffs => true,
.rip => false,
.sib => |s| switch (s.base) {
.none, .frame => false,
.reg => |reg| reg.class() == .segment,
},
};
}
pub fn base(mem: Memory) Base {
return switch (mem) {
.moffs => |m| .{ .reg = m.seg },
.sib => |s| s.base,
.rip => .none,
};
}
pub fn scaleIndex(mem: Memory) ?ScaleIndex {
return switch (mem) {
.moffs, .rip => null,
.sib => |s| if (s.scale_index.scale > 0) s.scale_index else null,
};
}
pub fn bitSize(mem: Memory) u64 {
return switch (mem) {
.rip => |r| r.ptr_size.bitSize(),
.sib => |s| s.ptr_size.bitSize(),
.moffs => 64,
};
}
pub const Scale = enum(u2) { @"1", @"2", @"4", @"8" };
};
pub const Immediate = union(enum) {

View File

@ -6,9 +6,10 @@ const testing = std.testing;
const bits = @import("bits.zig");
const Encoding = @import("Encoding.zig");
const FrameIndex = bits.FrameIndex;
const Immediate = bits.Immediate;
const Memory = bits.Memory;
const Register = bits.Register;
const Symbol = bits.Symbol;
pub const Instruction = struct {
prefix: Prefix = .none,
@ -27,6 +28,97 @@ pub const Instruction = struct {
repnz,
};
pub const Memory = union(enum) {
sib: Sib,
rip: Rip,
moffs: Moffs,
pub const Base = bits.Memory.Base;
pub const ScaleIndex = struct {
scale: u4,
index: Register,
const none = ScaleIndex{ .scale = 0, .index = undefined };
};
pub const PtrSize = bits.Memory.Size;
pub const Sib = struct {
ptr_size: PtrSize,
base: Base,
scale_index: ScaleIndex,
disp: i32,
};
pub const Rip = struct {
ptr_size: PtrSize,
disp: i32,
};
pub const Moffs = struct {
seg: Register,
offset: u64,
};
pub fn moffs(reg: Register, offset: u64) Memory {
assert(reg.class() == .segment);
return .{ .moffs = .{ .seg = reg, .offset = offset } };
}
pub fn sib(ptr_size: PtrSize, args: struct {
disp: i32 = 0,
base: Base = .none,
scale_index: ?ScaleIndex = null,
}) Memory {
if (args.scale_index) |si| assert(std.math.isPowerOfTwo(si.scale));
return .{ .sib = .{
.base = args.base,
.disp = args.disp,
.ptr_size = ptr_size,
.scale_index = if (args.scale_index) |si| si else ScaleIndex.none,
} };
}
pub fn rip(ptr_size: PtrSize, disp: i32) Memory {
return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } };
}
pub fn isSegmentRegister(mem: Memory) bool {
return switch (mem) {
.moffs => true,
.rip => false,
.sib => |s| switch (s.base) {
.none, .frame, .reloc => false,
.reg => |reg| reg.class() == .segment,
},
};
}
pub fn base(mem: Memory) Base {
return switch (mem) {
.moffs => |m| .{ .reg = m.seg },
.sib => |s| s.base,
.rip => .none,
};
}
pub fn scaleIndex(mem: Memory) ?ScaleIndex {
return switch (mem) {
.moffs, .rip => null,
.sib => |s| if (s.scale_index.scale > 0) s.scale_index else null,
};
}
pub fn bitSize(mem: Memory) u64 {
return switch (mem) {
.rip => |r| r.ptr_size.bitSize(),
.sib => |s| s.ptr_size.bitSize(),
.moffs => 64,
};
}
};
pub const Operand = union(enum) {
none,
reg: Register,
@ -125,8 +217,8 @@ pub const Instruction = struct {
try writer.print("{s}", .{@tagName(reg)});
any = true;
},
.frame => |frame| {
try writer.print("{}", .{frame});
inline .frame, .reloc => |payload| {
try writer.print("{}", .{payload});
any = true;
},
}
@ -498,7 +590,11 @@ pub const Instruction = struct {
}
}
},
.frame => if (@TypeOf(encoder).options.allow_frame_loc) {
.frame => if (@TypeOf(encoder).options.allow_frame_locs) {
try encoder.modRm_indirectDisp32(operand_enc, undefined);
try encoder.disp32(undefined);
} else return error.CannotEncode,
.reloc => if (@TypeOf(encoder).options.allow_symbols) {
try encoder.modRm_indirectDisp32(operand_enc, undefined);
try encoder.disp32(undefined);
} else return error.CannotEncode,
@ -570,7 +666,7 @@ pub const LegacyPrefixes = packed struct {
}
};
pub const Options = struct { allow_frame_loc: bool = false };
pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool = false };
fn Encoder(comptime T: type, comptime opts: Options) type {
return struct {
@ -1085,7 +1181,7 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
@ -1109,13 +1205,13 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.dword, .{ .base = .r11 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
try enc.encode(.mov, &.{
.{ .mem = Memory.rip(.qword, 0x10) },
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@ -1125,25 +1221,25 @@ test "lower MI encoding" {
);
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
.{ .imm = Immediate.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 = Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) },
.{ .imm = Immediate.s(-16) },
});
try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = .ds,
.disp = 0x10000000,
.scale_index = .{ .scale = 2, .index = .rcx },
@ -1157,13 +1253,13 @@ test "lower MI encoding" {
);
try enc.encode(.adc, &.{
.{ .mem = Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
try enc.encode(.adc, &.{
.{ .mem = Memory.rip(.qword, 0) },
.{ .mem = Instruction.Memory.rip(.qword, 0) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
@ -1175,7 +1271,7 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
try enc.encode(.add, &.{
.{ .mem = Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
@ -1187,13 +1283,13 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
try enc.encode(.add, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
.{ .imm = Immediate.s(-0x10) },
});
try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
try enc.encode(.@"and", &.{
.{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@ -1203,7 +1299,7 @@ test "lower MI encoding" {
);
try enc.encode(.@"and", &.{
.{ .mem = Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@ -1213,7 +1309,7 @@ test "lower MI encoding" {
);
try enc.encode(.@"and", &.{
.{ .mem = Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@ -1223,7 +1319,7 @@ test "lower MI encoding" {
);
try enc.encode(.sub, &.{
.{ .mem = Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@ -1238,25 +1334,25 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Memory.sib(.qword, .{ .base = .r11 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11 }) },
});
try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
try enc.encode(.mov, &.{
.{ .reg = .rbx },
.{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
});
try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
});
try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = .rbp,
.scale_index = .{ .scale = 1, .index = .rcx },
.disp = -8,
@ -1266,7 +1362,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .eax },
.{ .mem = Memory.sib(.dword, .{
.{ .mem = Instruction.Memory.sib(.dword, .{
.base = .rbp,
.scale_index = .{ .scale = 4, .index = .rdx },
.disp = -4,
@ -1276,7 +1372,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = .rbp,
.scale_index = .{ .scale = 8, .index = .rcx },
.disp = -8,
@ -1286,7 +1382,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .r8b },
.{ .mem = Memory.sib(.byte, .{
.{ .mem = Instruction.Memory.sib(.byte, .{
.base = .rsi,
.scale_index = .{ .scale = 1, .index = .rcx },
.disp = -24,
@ -1302,7 +1398,7 @@ test "lower RM encoding" {
try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
.{ .reg = .fs },
});
try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");
@ -1314,7 +1410,7 @@ test "lower RM encoding" {
try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .reg = .fs },
});
try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
@ -1339,19 +1435,19 @@ test "lower RM encoding" {
try enc.encode(.movsx, &.{
.{ .reg = .eax },
.{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
});
try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
try enc.encode(.movsx, &.{
.{ .reg = .eax },
.{ .mem = Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
});
try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");
try enc.encode(.movsx, &.{
.{ .reg = .ax },
.{ .mem = Memory.rip(.byte, 0x10) },
.{ .mem = Instruction.Memory.rip(.byte, 0x10) },
});
try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");
@ -1369,37 +1465,37 @@ test "lower RM encoding" {
try enc.encode(.lea, &.{
.{ .reg = .rax },
.{ .mem = Memory.rip(.qword, 0x10) },
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
});
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");
try enc.encode(.lea, &.{
.{ .reg = .rax },
.{ .mem = Memory.rip(.dword, 0x10) },
.{ .mem = Instruction.Memory.rip(.dword, 0x10) },
});
try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");
try enc.encode(.lea, &.{
.{ .reg = .eax },
.{ .mem = Memory.rip(.dword, 0x10) },
.{ .mem = Instruction.Memory.rip(.dword, 0x10) },
});
try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");
try enc.encode(.lea, &.{
.{ .reg = .eax },
.{ .mem = Memory.rip(.word, 0x10) },
.{ .mem = Instruction.Memory.rip(.word, 0x10) },
});
try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");
try enc.encode(.lea, &.{
.{ .reg = .ax },
.{ .mem = Memory.rip(.byte, 0x10) },
.{ .mem = Instruction.Memory.rip(.byte, 0x10) },
});
try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
try enc.encode(.lea, &.{
.{ .reg = .rsi },
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = .rbp,
.scale_index = .{ .scale = 1, .index = .rcx },
}) },
@ -1408,31 +1504,31 @@ test "lower RM encoding" {
try enc.encode(.add, &.{
.{ .reg = .r11 },
.{ .mem = Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
try enc.encode(.add, &.{
.{ .reg = .r12b },
.{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
try enc.encode(.add, &.{
.{ .reg = .r12b },
.{ .mem = Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
try enc.encode(.sub, &.{
.{ .reg = .r11 },
.{ .mem = Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
try enc.encode(.sub, &.{
.{ .reg = .r11 },
.{ .mem = Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
@ -1455,7 +1551,7 @@ test "lower RMI encoding" {
try enc.encode(.imul, &.{
.{ .reg = .r11 },
.{ .mem = Memory.rip(.qword, -16) },
.{ .mem = Instruction.Memory.rip(.qword, -16) },
.{ .imm = Immediate.s(-1024) },
});
try expectEqualHexStrings(
@ -1466,7 +1562,7 @@ test "lower RMI encoding" {
try enc.encode(.imul, &.{
.{ .reg = .bx },
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .imm = Immediate.s(-1024) },
});
try expectEqualHexStrings(
@ -1477,7 +1573,7 @@ test "lower RMI encoding" {
try enc.encode(.imul, &.{
.{ .reg = .bx },
.{ .mem = Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
.{ .imm = Immediate.u(1024) },
});
try expectEqualHexStrings(
@ -1497,19 +1593,19 @@ test "lower MR encoding" {
try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
.{ .reg = .r11 },
});
try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
try enc.encode(.mov, &.{
.{ .mem = Memory.rip(.qword, 0x10) },
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
.{ .reg = .r12 },
});
try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = .r11,
.scale_index = .{ .scale = 2, .index = .r12 },
.disp = 0x10,
@ -1519,13 +1615,13 @@ test "lower MR encoding" {
try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");
try enc.encode(.mov, &.{
.{ .mem = Memory.rip(.word, -0x10) },
.{ .mem = Instruction.Memory.rip(.word, -0x10) },
.{ .reg = .r12w },
});
try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");
try enc.encode(.mov, &.{
.{ .mem = Memory.sib(.byte, .{
.{ .mem = Instruction.Memory.sib(.byte, .{
.base = .r11,
.scale_index = .{ .scale = 2, .index = .r12 },
.disp = 0x10,
@ -1535,25 +1631,25 @@ test "lower MR encoding" {
try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
try enc.encode(.add, &.{
.{ .mem = Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .reg = .r12b },
});
try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
try enc.encode(.add, &.{
.{ .mem = Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
.{ .reg = .r12d },
});
try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
try enc.encode(.add, &.{
.{ .mem = Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
.{ .reg = .r12d },
});
try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
try enc.encode(.sub, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
.{ .reg = .r12 },
});
try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
@ -1568,12 +1664,12 @@ test "lower M encoding" {
try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
try enc.encode(.call, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .r12 }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12 }) },
});
try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
try enc.encode(.call, &.{
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = null,
.scale_index = .{ .index = .r11, .scale = 2 },
}) },
@ -1581,7 +1677,7 @@ test "lower M encoding" {
try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
try enc.encode(.call, &.{
.{ .mem = Memory.sib(.qword, .{
.{ .mem = Instruction.Memory.sib(.qword, .{
.base = null,
.scale_index = .{ .index = .r12, .scale = 2 },
}) },
@ -1589,7 +1685,7 @@ test "lower M encoding" {
try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
try enc.encode(.call, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .gs }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .gs }) },
});
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
@ -1599,22 +1695,22 @@ test "lower M encoding" {
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
try enc.encode(.push, &.{
.{ .mem = Memory.sib(.qword, .{ .base = .rbp }) },
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp }) },
});
try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
try enc.encode(.push, &.{
.{ .mem = Memory.sib(.word, .{ .base = .rbp }) },
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
});
try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
try enc.encode(.pop, &.{
.{ .mem = Memory.rip(.qword, 0) },
.{ .mem = Instruction.Memory.rip(.qword, 0) },
});
try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");
try enc.encode(.pop, &.{
.{ .mem = Memory.rip(.word, 0) },
.{ .mem = Instruction.Memory.rip(.word, 0) },
});
try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");
@ -1695,48 +1791,48 @@ test "lower FD/TD encoding" {
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Memory.moffs(.cs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.cs, 0x10) },
});
try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");
try enc.encode(.mov, &.{
.{ .reg = .eax },
.{ .mem = Memory.moffs(.fs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.fs, 0x10) },
});
try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");
try enc.encode(.mov, &.{
.{ .reg = .ax },
.{ .mem = Memory.moffs(.gs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.gs, 0x10) },
});
try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");
try enc.encode(.mov, &.{
.{ .reg = .al },
.{ .mem = Memory.moffs(.ds, 0x10) },
.{ .mem = Instruction.Memory.moffs(.ds, 0x10) },
});
try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");
try enc.encode(.mov, &.{
.{ .mem = Memory.moffs(.cs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.cs, 0x10) },
.{ .reg = .rax },
});
try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");
try enc.encode(.mov, &.{
.{ .mem = Memory.moffs(.fs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.fs, 0x10) },
.{ .reg = .eax },
});
try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");
try enc.encode(.mov, &.{
.{ .mem = Memory.moffs(.gs, 0x10) },
.{ .mem = Instruction.Memory.moffs(.gs, 0x10) },
.{ .reg = .ax },
});
try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");
try enc.encode(.mov, &.{
.{ .mem = Memory.moffs(.ds, 0x10) },
.{ .mem = Instruction.Memory.moffs(.ds, 0x10) },
.{ .reg = .al },
});
try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");
@ -1774,16 +1870,16 @@ test "invalid instruction" {
.{ .reg = .al },
});
try invalidInstruction(.call, &.{
.{ .mem = Memory.rip(.dword, 0) },
.{ .mem = Instruction.Memory.rip(.dword, 0) },
});
try invalidInstruction(.call, &.{
.{ .mem = Memory.rip(.word, 0) },
.{ .mem = Instruction.Memory.rip(.word, 0) },
});
try invalidInstruction(.call, &.{
.{ .mem = Memory.rip(.byte, 0) },
.{ .mem = Instruction.Memory.rip(.byte, 0) },
});
try invalidInstruction(.mov, &.{
.{ .mem = Memory.rip(.word, 0x10) },
.{ .mem = Instruction.Memory.rip(.word, 0x10) },
.{ .reg = .r12 },
});
try invalidInstruction(.lea, &.{
@ -1792,7 +1888,7 @@ test "invalid instruction" {
});
try invalidInstruction(.lea, &.{
.{ .reg = .al },
.{ .mem = Memory.rip(.byte, 0) },
.{ .mem = Instruction.Memory.rip(.byte, 0) },
});
try invalidInstruction(.pop, &.{
.{ .reg = .r12b },
@ -1817,7 +1913,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand
test "cannot encode" {
try cannotEncode(.@"test", &.{
.{ .mem = Memory.sib(.byte, .{ .base = .r12 }) },
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
.{ .reg = .ah },
});
try cannotEncode(.@"test", &.{
@ -2149,8 +2245,8 @@ const Assembler = struct {
return null;
}
fn parseMemory(as: *Assembler) ParseError!Memory {
const ptr_size: ?Memory.PtrSize = blk: {
fn parseMemory(as: *Assembler) ParseError!Instruction.Memory {
const ptr_size: ?Instruction.Memory.PtrSize = blk: {
const pos = as.it.pos;
const ptr_size = as.parsePtrSize() catch |err| switch (err) {
error.UnexpectedToken => {
@ -2194,7 +2290,7 @@ const Assembler = struct {
if (res.rip) {
if (res.base != null or res.scale_index != null or res.offset != null)
return error.InvalidMemoryOperand;
return Memory.rip(ptr_size orelse .qword, res.disp orelse 0);
return Instruction.Memory.rip(ptr_size orelse .qword, res.disp orelse 0);
}
if (res.base) |base| {
if (res.rip)
@ -2202,9 +2298,9 @@ const Assembler = struct {
if (res.offset) |offset| {
if (res.scale_index != null or res.disp != null)
return error.InvalidMemoryOperand;
return Memory.moffs(base, offset);
return Instruction.Memory.moffs(base, offset);
}
return Memory.sib(ptr_size orelse .qword, .{
return Instruction.Memory.sib(ptr_size orelse .qword, .{
.base = base,
.scale_index = res.scale_index,
.disp = res.disp orelse 0,
@ -2222,12 +2318,12 @@ const Assembler = struct {
const MemoryParseResult = struct {
rip: bool = false,
base: ?Register = null,
scale_index: ?Memory.ScaleIndex = null,
scale_index: ?Instruction.Memory.ScaleIndex = null,
disp: ?i32 = null,
offset: ?u64 = null,
};
fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!MemoryParseResult {
fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!Instruction.MemoryParseResult {
var res: MemoryParseResult = .{};
inline for (rule, 0..) |cond, i| {
if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) {
@ -2294,7 +2390,7 @@ const Assembler = struct {
return res;
}
fn parsePtrSize(as: *Assembler) ParseError!Memory.PtrSize {
fn parsePtrSize(as: *Assembler) ParseError!Instruction.Memory.PtrSize {
const size = try as.expect(.string);
try as.skip(1, .{.space});
const ptr = try as.expect(.string);

View File

@ -4,7 +4,6 @@ const expect = std.testing.expect;
test "exporting enum type and value" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
@ -21,7 +20,6 @@ test "exporting enum type and value" {
test "exporting with internal linkage" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
@ -37,7 +35,6 @@ test "exporting with internal linkage" {
test "exporting using field access" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

View File

@ -577,7 +577,6 @@ test "pass and return comptime-only types" {
test "pointer to alias behaves same as pointer to function" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

View File

@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 };
test "store to global array" {
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_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
@ -20,7 +19,6 @@ var vpos = @Vector(2, f32){ 0.0, 0.0 };
test "store to global vector" {
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_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

View File

@ -23,7 +23,6 @@ const snan_f128: f128 = math.snan(f128);
test "nan memory equality" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

View File

@ -28,6 +28,7 @@ const TestTarget = struct {
single_threaded: ?bool = null,
use_llvm: ?bool = null,
use_lld: ?bool = null,
force_pic: ?bool = null,
};
const test_targets = blk: {
@ -103,6 +104,7 @@ const test_targets = blk: {
},
.use_llvm = false,
.use_lld = false,
.force_pic = true,
},
.{
.target = .{
@ -494,6 +496,7 @@ const CAbiTarget = struct {
target: CrossTarget = .{},
use_llvm: ?bool = null,
use_lld: ?bool = null,
force_pic: ?bool = null,
c_defines: []const []const u8 = &.{},
};
@ -536,6 +539,7 @@ const c_abi_targets = [_]CAbiTarget{
},
.use_llvm = false,
.use_lld = false,
.force_pic = true,
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
},
.{
@ -1118,6 +1122,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
.use_lld = test_target.use_lld,
.zig_lib_dir = .{ .path = "lib" },
});
these_tests.force_pic = test_target.force_pic;
const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else "";
const backend_suffix = if (test_target.use_llvm == true)
"-llvm"
@ -1128,6 +1133,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
else
"";
const use_lld = if (test_target.use_lld == false) "-no-lld" else "";
const use_pic = if (test_target.force_pic == true) "-pic" else "";
these_tests.addIncludePath(.{ .path = "test" });
@ -1136,7 +1142,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
these_tests.stack_size = 2 * 1024 * 1024;
}
const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}", .{
const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}", .{
options.name,
triple_txt,
model_txt,
@ -1145,6 +1151,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
single_threaded_suffix,
backend_suffix,
use_lld,
use_pic,
});
if (test_target.target.ofmt == std.Target.ObjectFormat.c) {
@ -1234,13 +1241,8 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
continue;
}
if (c_abi_target.use_llvm == false and optimize_mode == .ReleaseFast) {
// panic: unrecognized command line argument
continue;
}
const test_step = b.addTest(.{
.name = b.fmt("test-c-abi-{s}-{s}-{s}{s}{s}", .{
.name = b.fmt("test-c-abi-{s}-{s}-{s}{s}{s}{s}", .{
c_abi_target.target.zigTriple(b.allocator) catch @panic("OOM"),
c_abi_target.target.getCpuModel().name,
@tagName(optimize_mode),
@ -1253,6 +1255,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
else
"",
if (c_abi_target.use_lld == false) "-no-lld" else "",
if (c_abi_target.force_pic == true) "-pic" else "",
}),
.root_source_file = .{ .path = "test/c_abi/main.zig" },
.target = c_abi_target.target,
@ -1261,6 +1264,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
.use_llvm = c_abi_target.use_llvm,
.use_lld = c_abi_target.use_lld,
});
test_step.force_pic = c_abi_target.force_pic;
if (c_abi_target.target.abi != null and c_abi_target.target.abi.?.isMusl()) {
// TODO NativeTargetInfo insists on dynamically linking musl
// for some reason?