srctree

Robin Linden parent 0511fb44 59ea1cb8
azm: Stub out a simple AMD64 assembler

inlinesplit
.clang-tidy added: 140, removed: 7, total 133
@@ -58,7 +58,7 @@ Checks: >
# clang-tidy-16.
WarningsAsErrors: "*,-clang-diagnostic-builtin-macro-redefined"
 
HeaderFilterRegex: "\\./(archive|browser|css|css2|dom|dom2|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|uri|url|util|wasm)/"
HeaderFilterRegex: "\\./(archive|azm|browser|css|css2|dom|dom2|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|uri|url|util|wasm)/"
 
CheckOptions:
# performance-move-const-arg
 
.gitlint added: 140, removed: 7, total 133
@@ -4,4 +4,4 @@ ignore=body-is-missing
# TODO(robinlinden): Better way of documenting and setting this up.
# Each commit must start with the main area it affects.
[title-match-regex]
regex=^(archive|browser|bzl|css|css2|dom|dom2|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|uri|url|util|wasm|all|build|ci|deps|doc|meta)(/.*|\+.*)?:
regex=^(archive|azm|browser|bzl|css|css2|dom|dom2|engine|etest|geom|gfx|html|html2|idna|img|js|layout|net|os|protocol|render|style|tui|uri|url|util|wasm|all|build|ci|deps|doc|meta)(/.*|\+.*)?:
 
filename was Deleted added: 140, removed: 7, total 133
@@ -0,0 +1,22 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("//bzl:copts.bzl", "HASTUR_COPTS")
 
cc_library(
name = "azm",
hdrs = ["assembler.h"],
copts = HASTUR_COPTS,
visibility = ["//visibility:public"],
)
 
[cc_test(
name = src[:-4],
size = "small",
srcs = [src],
copts = HASTUR_COPTS,
deps = [
":azm",
"//etest",
],
) for src in glob(
include = ["*_test.cpp"],
)]
 
filename was Deleted added: 140, removed: 7, total 133
@@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef AZM_ASSEMBLER_H_
#define AZM_ASSEMBLER_H_
 
#include <cstdint>
#include <optional>
#include <utility>
#include <vector>
 
namespace azm {
 
enum class Reg32 {
Eax,
Ecx,
Edx,
Ebx,
};
 
struct Imm32 {
std::uint32_t v{};
};
 
constexpr std::optional<std::uint8_t> register_index(Reg32 reg) {
switch (reg) {
case Reg32::Eax:
return std::uint8_t{0};
case Reg32::Ecx:
return std::uint8_t{1};
case Reg32::Edx:
return std::uint8_t{2};
case Reg32::Ebx:
return std::uint8_t{3};
}
return std::nullopt;
}
 
// https://www.felixcloutier.com/x86/
class Amd64Assembler {
public:
[[nodiscard]] std::vector<std::uint8_t> take_assembled() { return std::exchange(assembled_, {}); }
 
void mov(Reg32 dst, Imm32 imm32) {
emit(0xb8 + register_index(dst).value());
emit(imm32);
}
 
void ret() { emit(0xc3); }
 
private:
void emit(std::uint8_t byte) { assembled_.push_back(byte); }
void emit(Imm32 imm32) {
for (auto i = 0; i < 4; ++i) {
emit(imm32.v & 0xff);
imm32.v >>= 8;
}
}
 
std::vector<std::uint8_t> assembled_;
};
 
} // namespace azm
 
#endif
 
filename was Deleted added: 140, removed: 7, total 133
@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "azm/assembler.h"
 
#include "etest/etest2.h"
 
#include <cstdint>
#include <type_traits>
#include <vector>
 
using CodeVec = std::vector<std::uint8_t>;
 
int main() {
etest::Suite s{"assembler::amd64"};
using namespace azm;
 
s.add_test("Register index", [](etest::IActions &a) {
a.expect_eq(register_index(Reg32::Eax), 0);
a.expect_eq(register_index(Reg32::Ecx), 1);
a.expect_eq(register_index(Reg32::Edx), 2);
a.expect_eq(register_index(Reg32::Ebx), 3);
a.expect_eq(register_index(static_cast<Reg32>(std::underlying_type_t<Reg32>{30})), std::nullopt);
});
 
s.add_test("MOV r32, imm32", [](etest::IActions &a) {
Amd64Assembler assembler;
 
assembler.mov(Reg32::Eax, Imm32{0xdeadbeef});
a.expect_eq(assembler.take_assembled(), CodeVec{0xb8, 0xef, 0xbe, 0xad, 0xde});
 
assembler.mov(Reg32::Edx, Imm32{0x1234});
a.expect_eq(assembler.take_assembled(), CodeVec{0xba, 0x34, 0x12, 0, 0});
});
 
s.add_test("RET", [](etest::IActions &a) {
Amd64Assembler assembler;
 
assembler.ret();
a.expect_eq(assembler.take_assembled(), CodeVec{0xc3});
});
 
return s.run();
}