Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ metajit.cpp uses a generating extension for tracing.
## Coding Guidelines

- Do not add code comments.
- NEVER push directly to main under any circumstances.
- Start commit messages with a lowercase letter.
- Name feature branches `<author-first-name>-<short-description>`, using the author's first name followed by a dash and a short description with words separated by dashes.
- Never edit the generated jitir.hpp and jitir_llvmapi.hpp files directly. Instead, edit the corresponding template files jitir.tmpl.hpp and jitir_llvmapi.tmpl.hpp. The instructions are specified in the jitir.py generator script.
- Never edit any files in tests/output. They are just output files from the unit tests used to debug failing test cases. They are also not golden tests; in fact, they are ignored by Git.
Expand Down
22 changes: 14 additions & 8 deletions jitir.tmpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,21 @@ namespace metajit {
};
}

namespace metajit {
inline const char* to_string(Type type) {
static const char* names[] = {
"Void",
"Bool",
"Int8", "Int16", "Int32", "Int64",
"Float32", "Float64",
"Ptr"
};
return names[(size_t) type];
}
}

std::ostream& operator<<(std::ostream& stream, metajit::Type type) {
static const char* names[] = {
"Void",
"Bool",
"Int8", "Int16", "Int32", "Int64",
"Float32", "Float64",
"Ptr"
};
stream << names[(size_t) type];
stream << metajit::to_string(type);
return stream;
}

Expand Down
7 changes: 4 additions & 3 deletions llvmgen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,10 @@ namespace metajit {
return call_inst;
} else if (dynmatch(EqInst, eq, inst)) {
if (is_float(eq->arg(0)->type())) {
return _builder.CreateFCmpUEQ(
emit_arg(eq->arg(0)),
emit_arg(eq->arg(1))
llvm::Type* bits_type = _builder.getIntNTy(type_size(eq->arg(0)->type()) * 8);
return _builder.CreateICmpEQ(
_builder.CreateBitCast(emit_arg(eq->arg(0)), bits_type),
_builder.CreateBitCast(emit_arg(eq->arg(1)), bits_type)
);
} else {
return _builder.CreateICmpEQ(
Expand Down
69 changes: 69 additions & 0 deletions tests/test_cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,37 @@ int main(int argc, char** argv) {

DiffTestSuite suite("tests/output/test_cfg", argc, argv);

for (Type type : {Type::Float32, Type::Float64, Type::Int32, Type::Int64}) {
suite.test(std::string("entry_argument_") + to_string(type)).run([type]() {
for (auto mode : {X86CodeGen::Mode::JIT, X86CodeGen::Mode::AOT}) {
Context context;
Allocator allocator;
Section* section = new Section(context, allocator);
Builder builder(section);
Block* entry = builder.build_block({type, Type::Ptr});
builder.move_to_end(entry);
builder.build_store(entry->arg(1), entry->arg(0), AliasingGroup(0), 0);
builder.build_exit();
section->autoname();
section->set_ordering(BlockOrdering::Natural);

uint64_t bits = 0x123456789abcdef0;
uint64_t result = 0;
if (is_float(type)) {
X86CodeGen codegen(section, {Reg::X86_R12(), Reg::X86_R13()}, mode);
using Func = void(* [[clang::preserve_none]])(uint64_t, uint64_t*);
((Func) codegen.deploy())(bits, &result);
} else {
X86CodeGen codegen(section, {Reg::X86_XMM(0), Reg::X86_R12()}, mode);
using Func = void(* [[clang::preserve_none]])(double, uint64_t*);
((Func) codegen.deploy())(bit_cast<double>(bits), &result);
}
unittest_assert(result == (bits & type_mask(type)));
delete section;
}
});
}

suite.diff_test("entry_argument_spilled_before_first_use").aot(false).run([](Builder& builder, TestData& data) {
std::vector<Value*> values;
for (size_t index = 0; index < 32; index++) {
Expand All @@ -39,6 +70,44 @@ int main(int argc, char** argv) {
data.output(input);
});

for (Type type : {Type::Float32, Type::Float64}) {
suite.diff_test(std::string("float_block_argument_") + to_string(type)).run([type](Builder& builder, TestData& data) {
Block* a = builder.build_block();
Block* b = builder.build_block();
Block* cont = builder.build_block({type});
Value* cond = data.input(Type::Bool);
Value* value_a = data.input(type);
Value* value_b = data.input(type);
builder.build_branch(cond, a, b);
builder.move_to_end(a);
builder.build_jump(cont, {value_a});
builder.move_to_end(b);
builder.build_jump(cont, {value_b});
builder.move_to_end(cont);
data.output(cont->arg(0));
});

suite.diff_test(std::string("float_swap_loop_") + to_string(type)).run([type](Builder& builder, TestData& data) {
Block* header = builder.build_block({Type::Bool, type, type});
Block* body = builder.build_block();
Block* end = builder.build_block();
Value* a = data.input(type);
Value* b = data.input(type);
Value* cond = data.input(Type::Bool);
builder.build_jump(header, {cond, a, b});
builder.move_to_end(header);
builder.build_branch(header->arg(0), body, end);
builder.move_to_end(body);
builder.build_jump(header, {
builder.build_const(Type::Bool, false),
header->arg(2), header->arg(1)
});
builder.move_to_end(end);
data.output(header->arg(1));
data.output(header->arg(2));
});
}

suite.diff_test("branch").run([](Builder& builder, TestData& data) {
Block* a = builder.build_block();
Block* b = builder.build_block();
Expand Down
110 changes: 95 additions & 15 deletions tests/test_insts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,21 @@ void test_binop(DiffTestSuite& suite) {
binop(xor, true)

binop(eq, false)
binop_type(eq, Float32)
binop_type(eq, Float64)
binop(lt_u, false)
binop(lt_s, false)

for (Type type : {Type::Float32, Type::Float64}) {
suite.diff_test(std::string("eq_bits_") + to_string(type)).run([type](Builder& builder, TestData& data) {
Value* zero = data.input(RandomRange(type, 0, 0));
uint64_t sign = uint64_t(1) << (type_size(type) * 8 - 1);
Value* negative_zero = data.input(RandomRange(type, sign, sign));
Value* nan = data.input(RandomRange(type, type_mask(type), type_mask(type)));
data.output(builder.build_eq(zero, negative_zero));
data.output(builder.build_eq(nan, nan));
});
}
}

void test_shift(DiffTestSuite& suite) {
Expand Down Expand Up @@ -104,6 +117,8 @@ void test_select(DiffTestSuite& suite) {
select_type(Int16)
select_type(Int32)
select_type(Int64)
select_type(Float32)
select_type(Float64)
}

void test_resize(DiffTestSuite& suite) {
Expand Down Expand Up @@ -251,21 +266,15 @@ void test_assume_const(DiffTestSuite& suite) {
}

void test_alloca(DiffTestSuite& suite) {
suite.diff_test("alloca_store_load_Int32").run([](Builder& builder, TestData& data) {
Value* ptr = builder.build_alloca(builder.build_const(Type::Int64, 4), 4);
Value* val = data.input(Type::Int32);
builder.build_store(ptr, val, AliasingGroup(0), 0);
Value* loaded = builder.build_load(ptr, Type::Int32, LoadFlags::None, AliasingGroup(0), 0);
data.output(loaded);
});

suite.diff_test("alloca_store_load_Int64").run([](Builder& builder, TestData& data) {
Value* ptr = builder.build_alloca(builder.build_const(Type::Int64, 8), 8);
Value* val = data.input(Type::Int64);
builder.build_store(ptr, val, AliasingGroup(0), 0);
Value* loaded = builder.build_load(ptr, Type::Int64, LoadFlags::None, AliasingGroup(0), 0);
data.output(loaded);
});
for (Type type : {Type::Int32, Type::Int64, Type::Float32, Type::Float64}) {
suite.diff_test(std::string("alloca_store_load_") + to_string(type)).run([=](Builder& builder, TestData& data) {
Value* ptr = builder.build_alloca(builder.build_const(Type::Int64, type_size(type)), type_size(type));
Value* val = data.input(type);
builder.build_store(ptr, val, AliasingGroup(0), 0);
Value* loaded = builder.build_load(ptr, type, LoadFlags::None, AliasingGroup(0), 0);
data.output(loaded);
});
}

suite.diff_test("alloca_multiple_stores").run([](Builder& builder, TestData& data) {
Value* ptr = builder.build_alloca(builder.build_const(Type::Int64, 8), 8);
Expand Down Expand Up @@ -456,7 +465,76 @@ void test_call(DiffTestSuite& suite) {
});
}

template <typename F>
__attribute__((noinline)) F test_call_fp_default(uint64_t i, float a, double b) {
return (F) i + (F) a + (F) b;
}

template <typename F>
__attribute__((preserve_none, noinline)) F test_call_fp_preserve_none(uint64_t i, float a, double b) {
return (F) i + (F) a + (F) b;
}

template <typename F>
void test_call_fp(DiffTestSuite& suite, Type type) {
for (CallConv call_conv : {CallConv::Default, CallConv::PreserveNone}) {
std::ostringstream name;
name << "call_fp_" << type;
if (call_conv == CallConv::Default) {
name << "_default";
} else {
name << "_preserve_none";
}

suite.diff_test(name.str()).aot(false).interpreter(false).run([=](Builder& builder, TestData& data) {
Value* i = data.input(RandomRange(Type::Int64, 0, 100));
Value* a = data.input(Type::Float32);
Value* b = data.input(Type::Float64);

Value* callee;
if (call_conv == CallConv::Default) {
callee = builder.build_const(Type::Ptr, (uint64_t)(void*) test_call_fp_default<F>);
} else {
callee = builder.build_const(Type::Ptr, (uint64_t)(void*) test_call_fp_preserve_none<F>);
}
Value* first = builder.build_call(callee, type, {i, a, b}, call_conv);
Value* second = builder.build_call(callee, type, {i, a, b}, call_conv);

data.output(first);
data.output(second);
data.output(i);
data.output(a);
data.output(b);
});
}
}

void test_binop_f(DiffTestSuite& suite) {
for (Type type : {Type::Float32, Type::Float64}) {
suite.diff_test(std::string("float_spills_") + to_string(type)).aot(false).run([type](Builder& builder, TestData& data) {
std::vector<Value*> values;
for (size_t index = 0; index < 17; index++) {
values.push_back(data.input(type));
}
for (Value* value : values) {
data.output(value);
}
});

suite.diff_test(std::string("mixed_register_classes_") + to_string(type)).run([type](Builder& builder, TestData& data) {
std::vector<Value*> floats;
std::vector<Value*> integers;
for (size_t index = 0; index < 8; index++) {
floats.push_back(data.input(type));
integers.push_back(data.input(Type::Int64));
}
for (size_t index = 0; index < floats.size(); index++) {
data.output(floats[index]);
data.output(integers[index]);
}
});
}

#define binop_f_type(name, type) \
suite.diff_test(#name "_" #type).run([](Builder& builder, TestData& data) { \
data.output(builder.build_##name(data.input(Type::type), data.input(Type::type))); \
Expand Down Expand Up @@ -576,6 +654,8 @@ int main(int argc, char** argv) {
test_assume_const(suite);
test_alloca(suite);
test_call(suite);
test_call_fp<float>(suite, Type::Float32);
test_call_fp<double>(suite, Type::Float64);
test_binop_f(suite);
test_convert_f(suite);
test_ptr_to_int(suite);
Expand Down
Loading
Loading