sub: test cases
This commit is contained in:
parent
736215ffa8
commit
afb8469af3
171
src/main.zig
171
src/main.zig
@ -1,6 +1,8 @@
|
||||
const std = @import("std");
|
||||
const log = std.log;
|
||||
const page_size = std.mem.page_size;
|
||||
const assert = std.debug.assert;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
const Section = struct {
|
||||
@ -56,11 +58,34 @@ const Rex = enum(u8) {
|
||||
const upper_4_bits = 0b100_0000;
|
||||
};
|
||||
|
||||
const GPRegister = enum(u4) {
|
||||
a = 0,
|
||||
c = 1,
|
||||
d = 2,
|
||||
b = 3,
|
||||
sp = 4,
|
||||
bp = 5,
|
||||
si = 6,
|
||||
di = 7,
|
||||
r8 = 8,
|
||||
r9 = 9,
|
||||
r10 = 10,
|
||||
r11 = 11,
|
||||
r12 = 12,
|
||||
r13 = 13,
|
||||
r14 = 14,
|
||||
r15 = 15,
|
||||
};
|
||||
|
||||
const prefix_lock = 0xf0;
|
||||
const prefix_repne_nz = 0xf2;
|
||||
const prefix_rep = 0xf3;
|
||||
const prefix_rex_w = [1]u8{@intFromEnum(Rex.w)};
|
||||
const prefix_16_bit_operand = [1]u8{0x66};
|
||||
|
||||
const ret = [1]u8{0xc3};
|
||||
const movabs_to_register_a = [1]u8{0xb8};
|
||||
const mov_a_imm = [1]u8{0xb8};
|
||||
const mov_reg_imm8: u8 = 0xb0;
|
||||
|
||||
inline fn intToArrayOfBytes(integer: anytype) [@sizeOf(@TypeOf(integer))]u8 {
|
||||
comptime {
|
||||
@ -70,16 +95,31 @@ inline fn intToArrayOfBytes(integer: anytype) [@sizeOf(@TypeOf(integer))]u8 {
|
||||
return @as([@sizeOf(@TypeOf(integer))]u8, @bitCast(integer));
|
||||
}
|
||||
|
||||
inline fn movU16ToA(integer: u16) [4]u8 {
|
||||
return prefix_16_bit_operand ++ movabs_to_register_a ++ intToArrayOfBytes(integer);
|
||||
fn movToAInstructionByteCount(comptime bit_count: u16) type {
|
||||
return [
|
||||
switch (bit_count) {
|
||||
8 => 2,
|
||||
16 => 4,
|
||||
32 => 5,
|
||||
64 => 10,
|
||||
else => @compileError("Not supported"),
|
||||
}
|
||||
]u8;
|
||||
}
|
||||
|
||||
inline fn movU32ToA(integer: u32) [5]u8 {
|
||||
return movabs_to_register_a ++ intToArrayOfBytes(integer);
|
||||
}
|
||||
|
||||
inline fn movU64ToA(integer: u64) [10]u8 {
|
||||
return prefix_rex_w ++ movabs_to_register_a ++ intToArrayOfBytes(integer);
|
||||
inline fn movAImm(comptime signedness: std.builtin.Signedness, comptime bit_count: u16, integer: @Type(.{
|
||||
.Int = .{
|
||||
.signedness = signedness,
|
||||
.bits = bit_count,
|
||||
},
|
||||
})) movToAInstructionByteCount(bit_count) {
|
||||
return switch (@TypeOf(integer)) {
|
||||
u8, i8 => .{mov_reg_imm8 | @intFromEnum(GPRegister.a)},
|
||||
u16, i16 => prefix_16_bit_operand ++ mov_a_imm,
|
||||
u32, i32 => mov_a_imm,
|
||||
u64, i64 => prefix_rex_w ++ mov_a_imm,
|
||||
else => @compileError("Unsupported"),
|
||||
} ++ intToArrayOfBytes(integer);
|
||||
}
|
||||
|
||||
test "ret void" {
|
||||
@ -90,35 +130,104 @@ test "ret void" {
|
||||
function_pointer();
|
||||
}
|
||||
|
||||
test "ret unsigned integer 16-bit" {
|
||||
const integer_types_to_test = [_]type{ u8, u16, u32, u64, i8, i16, i32, i64 };
|
||||
|
||||
fn testRetInteger(comptime T: type) !void {
|
||||
comptime {
|
||||
assert(@typeInfo(T) == .Int);
|
||||
assert((T == u8 or T == u16 or T == u32 or T == u64) or (T == i8 or T == i16 or T == i32 or T == i64));
|
||||
}
|
||||
|
||||
var image = try Image.create();
|
||||
const expected_number = 0xffff;
|
||||
image.appendCode(&movU16ToA(expected_number));
|
||||
const signedness = @typeInfo(T).Int.signedness;
|
||||
const expected_number = getMaxInteger(T);
|
||||
|
||||
image.appendCode(&movAImm(signedness, @bitSizeOf(T), expected_number));
|
||||
image.appendCode(&ret);
|
||||
|
||||
const function_pointer = image.getEntryPoint(fn () callconv(.C) u16);
|
||||
const function_pointer = image.getEntryPoint(fn () callconv(.C) T);
|
||||
const result = function_pointer();
|
||||
try expectEqual(result, expected_number);
|
||||
try expect(result == expected_number);
|
||||
}
|
||||
|
||||
test "ret unsigned integer 32-bit" {
|
||||
var image = try Image.create();
|
||||
const expected_number = 0xffff_ffff;
|
||||
image.appendCode(&movU32ToA(expected_number));
|
||||
image.appendCode(&ret);
|
||||
fn getMaxInteger(comptime T: type) T {
|
||||
comptime {
|
||||
assert(@typeInfo(T) == .Int);
|
||||
}
|
||||
|
||||
const function_pointer = image.getEntryPoint(fn () callconv(.C) u32);
|
||||
const result = function_pointer();
|
||||
try expectEqual(result, expected_number);
|
||||
return switch (@typeInfo(T).Int.signedness) {
|
||||
.unsigned => std.math.maxInt(T),
|
||||
.signed => std.math.minInt(T),
|
||||
};
|
||||
}
|
||||
|
||||
test "ret unsigned integer 64-bit" {
|
||||
var image = try Image.create();
|
||||
const expected_number = 0xffff_ffff_ffff_ffff;
|
||||
image.appendCode(&movU64ToA(expected_number));
|
||||
image.appendCode(&ret);
|
||||
|
||||
const function_pointer = image.getEntryPoint(fn () callconv(.C) u64);
|
||||
const result = function_pointer();
|
||||
try expectEqual(result, expected_number);
|
||||
test "ret integer" {
|
||||
inline for (integer_types_to_test) |Int| {
|
||||
try testRetInteger(Int);
|
||||
}
|
||||
}
|
||||
|
||||
const mov_rm_r = 0x89;
|
||||
|
||||
test "ret integer argument" {
|
||||
inline for (integer_types_to_test) |Int| {
|
||||
var image = try Image.create();
|
||||
const number = getMaxInteger(Int);
|
||||
const mov_a_di = switch (Int) {
|
||||
u8, i8 => .{ 0x40, 0x88, 0xf8 },
|
||||
u16, i16 => prefix_16_bit_operand ++ .{ mov_rm_r, 0xf8 },
|
||||
u32, i32 => .{ mov_rm_r, 0xf8 },
|
||||
u64, i64 => prefix_rex_w ++ .{ mov_rm_r, 0xf8 },
|
||||
else => @compileError("Not supported"),
|
||||
};
|
||||
|
||||
image.appendCode(&mov_a_di);
|
||||
image.appendCode(&ret);
|
||||
|
||||
const functionPointer = image.getEntryPoint(fn (Int) callconv(.C) Int);
|
||||
const result = functionPointer(number);
|
||||
try expectEqual(number, result);
|
||||
}
|
||||
}
|
||||
var r = std.rand.Pcg.init(0xffffffffffffffff);
|
||||
|
||||
fn getRandomNumberRange(comptime T: type, min: T, max: T) T {
|
||||
const random = r.random();
|
||||
return switch (@typeInfo(T).Int.signedness) {
|
||||
.signed => random.intRangeAtMost(T, min, max),
|
||||
.unsigned => random.uintAtMost(T, max),
|
||||
};
|
||||
}
|
||||
|
||||
const sub_rm_r = 0x29;
|
||||
|
||||
test "ret sub arguments" {
|
||||
inline for (integer_types_to_test) |Int| {
|
||||
var image = try Image.create();
|
||||
const a = getRandomNumberRange(Int, std.math.minInt(Int) / 2, std.math.maxInt(Int) / 2);
|
||||
const b = getRandomNumberRange(Int, std.math.minInt(Int) / 2, a);
|
||||
|
||||
const mov_a_di = switch (Int) {
|
||||
u8, i8 => .{ 0x40, 0x88, 0xf8 },
|
||||
u16, i16 => prefix_16_bit_operand ++ .{ mov_rm_r, 0xf8 },
|
||||
u32, i32 => .{ mov_rm_r, 0xf8 },
|
||||
u64, i64 => prefix_rex_w ++ .{ mov_rm_r, 0xf8 },
|
||||
else => @compileError("Not supported"),
|
||||
};
|
||||
image.appendCode(&mov_a_di);
|
||||
|
||||
const sub_a_si = switch (Int) {
|
||||
u8, i8 => .{ 0x40, 0x28, 0xf0 },
|
||||
u16, i16 => prefix_16_bit_operand ++ .{ sub_rm_r, 0xf0 },
|
||||
u32, i32 => .{ sub_rm_r, 0xf0 },
|
||||
u64, i64 => prefix_rex_w ++ .{ sub_rm_r, 0xf0 },
|
||||
else => @compileError("Not supported"),
|
||||
};
|
||||
image.appendCode(&sub_a_si);
|
||||
image.appendCode(&ret);
|
||||
|
||||
const functionPointer = image.getEntryPoint(fn (Int, Int) callconv(.C) Int);
|
||||
const result = functionPointer(a, b);
|
||||
try expectEqual(a - b, result);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user