From 4609339c5a32fb956356b4f458cd2e017c9fe96d Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 25 Jan 2014 20:30:18 -0800 Subject: [PATCH] JIT hackery. Not quite working. --- docs/gpu.md | 1 + .../x64/lowering/lowering_sequences.cc | 1586 ++++++++++++++--- src/alloy/backend/x64/x64_emitter.cc | 82 + src/alloy/backend/x64/x64_emitter.h | 103 ++ src/alloy/backend/x64/x64_function.cc | 6 +- src/alloy/compiler/compiler_passes.h | 1 - .../compiler/passes/finalization_pass.cc | 10 +- .../passes/register_allocation_pass.cc | 51 - .../passes/register_allocation_pass.h | 40 - src/alloy/compiler/passes/sources.gypi | 2 - src/alloy/frontend/ppc/ppc_translator.cc | 3 - src/alloy/hir/hir_builder.cc | 2 + src/alloy/hir/instr.cc | 13 + src/alloy/hir/instr.h | 25 + src/alloy/hir/value.cc | 17 + src/alloy/hir/value.h | 22 +- 16 files changed, 1585 insertions(+), 379 deletions(-) delete mode 100644 src/alloy/compiler/passes/register_allocation_pass.cc delete mode 100644 src/alloy/compiler/passes/register_allocation_pass.h diff --git a/docs/gpu.md b/docs/gpu.md index cf630b6e4..00fa701c7 100644 --- a/docs/gpu.md +++ b/docs/gpu.md @@ -8,6 +8,7 @@ * [LLVM R600 Tables](https://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/R600/R600Instructions.td) ** The opcode formats don't match, but the name->psuedo code is correct. +* [xemit](https://github.com/gligli/libxemit/blob/master/xemitops.c) ## Tools diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index 0cb940c8f..62686229a 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -22,10 +22,160 @@ using namespace Xbyak; namespace { -#define UNIMPLEMENTED_SEQ() +#define UNIMPLEMENTED_SEQ() __debugbreak() +#define ASSERT_INVALID_TYPE() XEASSERTALWAYS() // TODO(benvanik): emit traces/printfs/etc +void Dummy() { + // +} + +// Sets EFLAGs with zf for the given value. +void CheckBoolean(X64Emitter& e, Value* v) { + if (v->IsConstant()) { + e.mov(e.ah, (v->IsConstantZero() ? 1 : 0) << 6); + e.sahf(); + } else if (v->type == INT8_TYPE) { + Reg8 src; + e.BeginOp(v, src, 0); + e.test(src, src); + e.EndOp(src); + } else if (v->type == INT16_TYPE) { + Reg16 src; + e.BeginOp(v, src, 0); + e.test(src, src); + e.EndOp(src); + } else if (v->type == INT32_TYPE) { + Reg32 src; + e.BeginOp(v, src, 0); + e.test(src, src); + e.EndOp(src); + } else if (v->type == INT64_TYPE) { + Reg64 src; + e.BeginOp(v, src, 0); + e.test(src, src); + e.EndOp(src); + } else if (v->type == FLOAT32_TYPE) { + UNIMPLEMENTED_SEQ(); + } else if (v->type == FLOAT64_TYPE) { + UNIMPLEMENTED_SEQ(); + } else if (v->type == VEC128_TYPE) { + UNIMPLEMENTED_SEQ(); + } else { + ASSERT_INVALID_TYPE(); + } +} + +void CompareXX(X64Emitter& e, Instr*& i, void(set_fn)(X64Emitter& e, Reg8& dest, bool invert)) { + if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I8, SIG_TYPE_I8)) { + Reg8 dest; + Reg8 src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + e.cmp(src1, src2); + set_fn(e, dest, false); + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I8, SIG_TYPE_I8C)) { + Reg8 dest; + Reg8 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + e.cmp(src1, i->src2.value->constant.i8); + set_fn(e, dest, false); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I8C, SIG_TYPE_I8)) { + Reg8 dest; + Reg8 src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + e.cmp(src2, i->src1.value->constant.i8); + set_fn(e, dest, true); + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I16, SIG_TYPE_I16)) { + Reg8 dest; + Reg16 src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + e.cmp(src1, src2); + set_fn(e, dest, false); + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I16, SIG_TYPE_I16C)) { + Reg8 dest; + Reg16 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + e.cmp(src1, i->src2.value->constant.i16); + set_fn(e, dest, false); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I16C, SIG_TYPE_I16)) { + Reg8 dest; + Reg16 src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + e.cmp(src2, i->src1.value->constant.i16); + e.sete(dest); + set_fn(e, dest, true); + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I32, SIG_TYPE_I32)) { + Reg8 dest; + Reg32 src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + e.cmp(src1, src2); + set_fn(e, dest, false); + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I32, SIG_TYPE_I32C)) { + Reg8 dest; + Reg32 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + e.cmp(src1, i->src2.value->constant.i32); + set_fn(e, dest, false); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I32C, SIG_TYPE_I32)) { + Reg8 dest; + Reg32 src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + e.cmp(src2, i->src1.value->constant.i32); + set_fn(e, dest, true); + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I64, SIG_TYPE_I64)) { + Reg8 dest; + Reg64 src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + e.cmp(src1, src2); + set_fn(e, dest, false); + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I64, SIG_TYPE_I64C)) { + Reg8 dest; + Reg64 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + e.mov(e.rax, i->src2.value->constant.i64); + e.cmp(src1, e.rax); + set_fn(e, dest, false); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I64C, SIG_TYPE_I64)) { + Reg8 dest; + Reg64 src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + e.mov(e.rax, i->src1.value->constant.i64); + e.cmp(src2, e.rax); + set_fn(e, dest, true); + e.EndOp(dest, src2); + } else { + UNIMPLEMENTED_SEQ(); + } +}; + } // namespace @@ -34,18 +184,18 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // General // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& instr) { - //char* str = (char*)instr->src1.offset; + table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& i) { + //char* str = (char*)i->src1.offset; //lb.Comment(str); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + //UNIMPLEMENTED_SEQ(); + i = i->next; return true; }); - table->AddSequence(OPCODE_NOP, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_NOP, [](X64Emitter& e, Instr*& i) { // If we got this, chances are we want it. e.nop(); - instr = instr->next; + i = i->next; return true; }); @@ -53,54 +203,54 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Debugging // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& i) { // TODO(benvanik): translate source offsets for mapping? We're just passing // down the original offset - it may be nice to have two. - //lb.SourceOffset(instr->src1.offset); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + //lb.SourceOffset(i->src1.offset); + //UNIMPLEMENTED_SEQ(); + i = i->next; return true; }); - table->AddSequence(OPCODE_DEBUG_BREAK, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DEBUG_BREAK, [](X64Emitter& e, Instr*& i) { // TODO(benvanik): insert a call to the debug break function to let the // debugger know. e.db(0xCC); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DEBUG_BREAK_TRUE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DEBUG_BREAK_TRUE, [](X64Emitter& e, Instr*& i) { e.inLocalLabel(); - //e.test(e.rax, e.rax); - e.jne(".x"); + CheckBoolean(e, i->src1.value); + e.jne(".x", e.T_SHORT); // TODO(benvanik): insert a call to the debug break function to let the // debugger know. e.db(0xCC); e.L(".x"); e.outLocalLabel(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_TRAP, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_TRAP, [](X64Emitter& e, Instr*& i) { // TODO(benvanik): insert a call to the trap function to let the // debugger know. e.db(0xCC); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_TRAP_TRUE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_TRAP_TRUE, [](X64Emitter& e, Instr*& i) { e.inLocalLabel(); - //e.test(rax, rax); - e.jne(".x"); + CheckBoolean(e, i->src1.value); + e.jne(".x", e.T_SHORT); // TODO(benvanik): insert a call to the trap function to let the // debugger know. e.db(0xCC); e.L(".x"); e.outLocalLabel(); - instr = instr->next; + i = i->next; return true; }); @@ -108,49 +258,59 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Calls // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_CALL, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_CALL, [](X64Emitter& e, Instr*& i) { + e.mov(e.rax, (uint64_t)Dummy); + e.call(e.rax); UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_CALL_TRUE, [](X64Emitter& e, Instr*& instr) { - //auto skip_label = lb.NewLocalLabel(); - //lb.Test(instr->src1.value, instr->src1.value); - //lb.JumpNE(skip_label); - //// TODO - //lb.MarkLabel(skip_label); + table->AddSequence(OPCODE_CALL_TRUE, [](X64Emitter& e, Instr*& i) { + e.inLocalLabel(); + CheckBoolean(e, i->src1.value); + e.jne(".x", e.T_SHORT); + // TODO(benvanik): call + e.mov(e.rax, (uint64_t)Dummy); + e.call(e.rax); UNIMPLEMENTED_SEQ(); - instr = instr->next; + e.L(".x"); + e.outLocalLabel(); + i = i->next; return true; }); - table->AddSequence(OPCODE_CALL_INDIRECT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_CALL_INDIRECT, [](X64Emitter& e, Instr*& i) { + e.mov(e.rax, (uint64_t)Dummy); + e.call(e.rax); UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& instr) { - //auto skip_label = lb.NewLocalLabel(); - //lb.Test(instr->src1.value, instr->src1.value); - //lb.JumpNE(skip_label); + table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& i) { + e.inLocalLabel(); + CheckBoolean(e, i->src1.value); + e.jne(".x", e.T_SHORT); + // TODO(benvanik): call + e.mov(e.rax, (uint64_t)Dummy); + e.call(e.rax); + UNIMPLEMENTED_SEQ(); + e.L(".x"); + e.outLocalLabel(); + i = i->next; + return true; + }); + + table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& i) { + e.ret(); + i = i->next; + return true; + }); + + table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](X64Emitter& e, Instr*& i) { //UNIMPLEMENTED_SEQ(); - //lb.MarkLabel(skip_label); - UNIMPLEMENTED_SEQ(); - instr = instr->next; - return true; - }); - - table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; - return true; - }); - - table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -158,29 +318,26 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Branches // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_BRANCH, [](X64Emitter& e, Instr*& instr) { - /*auto target = (LIRLabel*)instr->src1.label->tag; - lb.Jump(target);*/ - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_BRANCH, [](X64Emitter& e, Instr*& i) { + auto target = i->src1.label; + e.jmp(target->name, e.T_NEAR); + i = i->next; return true; }); - table->AddSequence(OPCODE_BRANCH_TRUE, [](X64Emitter& e, Instr*& instr) { - /*lb.Test(instr->src1.value, instr->src1.value); - auto target = (LIRLabel*)instr->src2.label->tag; - lb.JumpEQ(target);*/ - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_BRANCH_TRUE, [](X64Emitter& e, Instr*& i) { + CheckBoolean(e, i->src1.value); + auto target = i->src2.label; + e.je(target->name, e.T_NEAR); + i = i->next; return true; }); - table->AddSequence(OPCODE_BRANCH_FALSE, [](X64Emitter& e, Instr*& instr) { - /*lb.Test(instr->src1.value, instr->src1.value); - auto target = (LIRLabel*)instr->src2.label->tag; - lb.JumpNE(target);*/ - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_BRANCH_FALSE, [](X64Emitter& e, Instr*& i) { + CheckBoolean(e, i->src1.value); + auto target = i->src2.label; + e.jne(target->name, e.T_NEAR); + i = i->next; return true; }); @@ -188,62 +345,222 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Types // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_ASSIGN, [](X64Emitter& e, Instr*& instr) { - //lb.Mov(instr->dest, instr->src1.value); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_ASSIGN, [](X64Emitter& e, Instr*& i) { + if (i->dest->type == INT8_TYPE) { + Reg8 dest, src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src); + e.EndOp(dest, src); + } else if (i->dest->type == INT16_TYPE) { + Reg16 dest, src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src); + e.EndOp(dest, src); + } else if (i->dest->type == INT32_TYPE) { + Reg32 dest, src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src); + e.EndOp(dest, src); + } else if (i->dest->type == INT64_TYPE) { + Reg64 dest, src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src); + e.EndOp(dest, src); + } else if (i->dest->type == FLOAT32_TYPE) { + UNIMPLEMENTED_SEQ(); + } else if (i->dest->type == FLOAT64_TYPE) { + UNIMPLEMENTED_SEQ(); + } else if (i->dest->type == VEC128_TYPE) { + UNIMPLEMENTED_SEQ(); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_CAST, [](X64Emitter& e, Instr*& instr) { - //lb.Mov(instr->dest, instr->src1.value); + table->AddSequence(OPCODE_CAST, [](X64Emitter& e, Instr*& i) { + // Need a matrix. UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ZERO_EXTEND, [](X64Emitter& e, Instr*& instr) { - //lb.MovZX(instr->dest, instr->src1.value); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_ZERO_EXTEND, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I16, SIG_TYPE_I8)) { + Reg16 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movzx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I8)) { + Reg32 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movzx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I16)) { + Reg32 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movzx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I8)) { + Reg64 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movzx(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I16)) { + Reg64 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movzx(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I32)) { + Reg64 dest; + Reg32 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest.cvt32(), src.cvt32()); + e.EndOp(dest, src); + } else { + UNIMPLEMENTED_SEQ(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_SIGN_EXTEND, [](X64Emitter& e, Instr*& instr) { - //lb.MovSX(instr->dest, instr->src1.value); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_SIGN_EXTEND, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I16, SIG_TYPE_I8)) { + Reg16 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I8)) { + Reg32 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I16)) { + Reg32 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I8)) { + Reg64 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I16)) { + Reg64 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I32)) { + Reg64 dest; + Reg32 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.movsx(dest, src.cvt32()); + e.EndOp(dest, src); + } else { + UNIMPLEMENTED_SEQ(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_TRUNCATE, [](X64Emitter& e, Instr*& instr) { - //lb.Mov(instr->dest, instr->src1.value); - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_TRUNCATE, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I8, SIG_TYPE_I16)) { + Reg8 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I32)) { + Reg8 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I64)) { + Reg8 dest; + Reg64 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt8()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I32)) { + Reg16 dest; + Reg32 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I64)) { + Reg16 dest; + Reg64 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt16()); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I64)) { + Reg32 dest; + Reg64 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.mov(dest, src.cvt32()); + e.EndOp(dest, src); + } else { + UNIMPLEMENTED_SEQ(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_CONVERT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_CONVERT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ROUND, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ROUND, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_CONVERT_I2F, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_CONVERT_I2F, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_CONVERT_F2I, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_CONVERT_F2I, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -253,21 +570,21 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // specials for zeroing/etc (xor/etc) - table->AddSequence(OPCODE_LOAD_VECTOR_SHL, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_LOAD_VECTOR_SHL, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_LOAD_VECTOR_SHR, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_LOAD_VECTOR_SHR, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_LOAD_CLOCK, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_LOAD_CLOCK, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -275,23 +592,106 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Context // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_LOAD_CONTEXT, [](X64Emitter& e, Instr*& instr) { - /*lb.Mov( - instr->dest, - LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX), - instr->src1.offset);*/ - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_LOAD_CONTEXT, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I8, SIG_TYPE_IGNORE)) { + Reg8 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.byte[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_IGNORE)) { + Reg16 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.word[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_IGNORE)) { + Reg32 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.dword[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_IGNORE)) { + Reg64 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.qword[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F32, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movss(dest, e.dword[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F64, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movsd(dest, e.qword[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_V128, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + // TODO(benvanik): we should try to stick to movaps if possible. + e.movups(dest, e.ptr[e.rcx + i->src1.offset]); + e.EndOp(dest); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_STORE_CONTEXT, [](X64Emitter& e, Instr*& instr) { - /*lb.Mov( - LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX), - instr->src1.offset, - instr->src2.value);*/ - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_STORE_CONTEXT, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8)) { + Reg8 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.byte[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8C)) { + e.mov(e.byte[e.rcx + i->src1.offset], i->src2.value->constant.i8); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16)) { + Reg16 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.word[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16C)) { + e.mov(e.word[e.rcx + i->src1.offset], i->src2.value->constant.i16); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32)) { + Reg32 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.dword[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32C)) { + e.mov(e.dword[e.rcx + i->src1.offset], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64)) { + Reg64 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.qword[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64C)) { + e.mov(e.qword[e.rcx + i->src1.offset], i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movss(e.dword[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32C)) { + e.mov(e.dword[e.rcx + i->src1.offset], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movsd(e.qword[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64C)) { + e.mov(e.qword[e.rcx + i->src1.offset], i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + // NOTE: we always know we are aligned. + e.movaps(e.ptr[e.rcx + i->src1.offset], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128C)) { + e.mov(e.ptr[e.rcx + i->src1.offset], i->src2.value->constant.v128.low); + e.mov(e.ptr[e.rcx + i->src1.offset + 8], i->src2.value->constant.v128.high); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); @@ -299,27 +699,143 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Memory // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_LOAD, [](X64Emitter& e, Instr*& instr) { - // TODO(benvanik): dynamic register access check + table->AddSequence(OPCODE_LOAD, [](X64Emitter& e, Instr*& i) { + // TODO(benvanik): dynamic register access check. // mov reg, [membase + address.32] - // TODO(benvanik): special for f32/f64/v128 - UNIMPLEMENTED_SEQ(); - instr = instr->next; + Reg64 addr_off; + RegExp addr; + if (i->src1.value->IsConstant()) { + // TODO(benvanik): a way to do this without using a register. + e.mov(e.eax, i->src1.value->AsUint32()); + addr = e.rdx + e.rax; + } else { + e.BeginOp(i->src1.value, addr_off, 0); + e.mov(addr_off.cvt32(), addr_off.cvt32()); // trunc to 32bits + addr = e.rdx + addr_off; + } + if (i->Match(SIG_TYPE_I8, SIG_TYPE_IGNORE)) { + Reg8 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.byte[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_IGNORE)) { + Reg16 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.word[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_IGNORE)) { + Reg32 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.dword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_IGNORE)) { + Reg64 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.mov(dest, e.qword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F32, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movss(dest, e.dword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_F64, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.movsd(dest, e.qword[addr]); + e.EndOp(dest); + } else if (i->Match(SIG_TYPE_V128, SIG_TYPE_IGNORE)) { + Xmm dest; + e.BeginOp(i->dest, dest, REG_DEST); + // TODO(benvanik): we should try to stick to movaps if possible. + e.movups(dest, e.ptr[addr]); + e.EndOp(dest); + } else { + ASSERT_INVALID_TYPE(); + } + if (!i->src1.value->IsConstant()) { + e.EndOp(addr_off); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_STORE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_STORE, [](X64Emitter& e, Instr*& i) { // TODO(benvanik): dynamic register access check // mov [membase + address.32], reg - // TODO(benvanik): special for f32/f64/v128 - UNIMPLEMENTED_SEQ(); - instr = instr->next; + Reg64 addr_off; + RegExp addr; + if (i->src1.value->IsConstant()) { + e.mov(e.eax, i->src1.value->AsUint32()); + addr = e.rdx + e.rax; + } else { + e.BeginOp(i->src1.value, addr_off, 0); + e.mov(addr_off.cvt32(), addr_off.cvt32()); // trunc to 32bits + addr = e.rdx + addr_off; + } + if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8)) { + Reg8 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.byte[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I8C)) { + e.mov(e.byte[addr], i->src2.value->constant.i8); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16)) { + Reg16 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.word[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I16C)) { + e.mov(e.word[addr], i->src2.value->constant.i16); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32)) { + Reg32 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.dword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I32C)) { + e.mov(e.dword[addr], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64)) { + Reg64 src; + e.BeginOp(i->src2.value, src, 0); + e.mov(e.qword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_I64C)) { + e.mov(e.qword[addr], i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movss(e.dword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F32C)) { + e.mov(e.dword[addr], i->src2.value->constant.i32); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + e.movsd(e.qword[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_F64C)) { + e.mov(e.qword[addr], i->src2.value->constant.i64); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128)) { + Xmm src; + e.BeginOp(i->src2.value, src, 0); + // TODO(benvanik): we should try to stick to movaps if possible. + e.movups(e.ptr[addr], src); + e.EndOp(src); + } else if (i->Match(SIG_TYPE_X, SIG_TYPE_IGNORE, SIG_TYPE_V128C)) { + e.mov(e.ptr[addr], i->src2.value->constant.v128.low); + e.mov(e.ptr[addr + 8], i->src2.value->constant.v128.high); + } else { + ASSERT_INVALID_TYPE(); + } + if (!i->src1.value->IsConstant()) { + e.EndOp(addr_off); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_PREFETCH, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_PREFETCH, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -327,141 +843,209 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Comparisons // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_MAX, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MAX, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_MIN, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MIN, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SELECT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SELECT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_IS_TRUE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_IS_TRUE, [](X64Emitter& e, Instr*& i) { + CheckBoolean(e, i->src1.value); + Reg8 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.setnz(dest); + e.EndOp(dest); + i = i->next; return true; }); - table->AddSequence(OPCODE_IS_FALSE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_IS_FALSE, [](X64Emitter& e, Instr*& i) { + CheckBoolean(e, i->src1.value); + Reg8 dest; + e.BeginOp(i->dest, dest, REG_DEST); + e.setz(dest); + e.EndOp(dest); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_EQ, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_EQ, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.sete(dest); + } else { + e.setne(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_NE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_NE, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setne(dest); + } else { + e.sete(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_SLT, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_SLT, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setl(dest); + } else { + e.setge(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_SLE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_SLE, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setle(dest); + } else { + e.setg(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_SGT, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_SGT, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setg(dest); + } else { + e.setle(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_SGE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_SGE, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setge(dest); + } else { + e.setl(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_ULT, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_ULT, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setb(dest); + } else { + e.setae(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_ULE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_ULE, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setbe(dest); + } else { + e.seta(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_UGT, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_UGT, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.seta(dest); + } else { + e.setbe(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_COMPARE_UGE, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_COMPARE_UGE, [](X64Emitter& e, Instr*& i) { + CompareXX(e, i, [](X64Emitter& e, Reg8& dest, bool invert) { + if (!invert) { + e.setae(dest); + } else { + e.setb(dest); + } + }); + i = i->next; return true; }); - table->AddSequence(OPCODE_DID_CARRY, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DID_CARRY, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DID_OVERFLOW, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DID_OVERFLOW, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DID_SATURATE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DID_SATURATE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_COMPARE_EQ, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_COMPARE_EQ, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_COMPARE_SGT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_COMPARE_SGT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_COMPARE_SGE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_COMPARE_SGE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_COMPARE_UGT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_COMPARE_UGT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_COMPARE_UGE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_COMPARE_UGE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -469,219 +1053,679 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Math // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_ADD, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_ADD, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8, SIG_TYPE_I8)) { + Reg8 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.add(dest, src2); + } else if (dest == src2) { + e.add(dest, src1); + } else { + e.mov(dest, src1); + e.add(dest, src2); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8, SIG_TYPE_I8C)) { + Reg8 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.add(dest, i->src2.value->constant.i8); + } else { + e.mov(dest, src1); + e.add(dest, i->src2.value->constant.i8); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8C, SIG_TYPE_I8)) { + Reg8 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.add(dest, i->src1.value->constant.i8); + } else { + e.mov(dest, src2); + e.add(dest, i->src1.value->constant.i8); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16, SIG_TYPE_I16)) { + Reg16 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.add(dest, src2); + } else if (dest == src2) { + e.add(dest, src1); + } else { + e.mov(dest, src1); + e.add(dest, src2); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16, SIG_TYPE_I16C)) { + Reg16 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.add(dest, i->src2.value->constant.i16); + } else { + e.mov(dest, src1); + e.add(dest, i->src2.value->constant.i16); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16C, SIG_TYPE_I16)) { + Reg16 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.add(dest, i->src1.value->constant.i16); + } else { + e.mov(dest, src2); + e.add(dest, i->src1.value->constant.i16); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32, SIG_TYPE_I32)) { + Reg32 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.add(dest, src2); + } else if (dest == src2) { + e.add(dest, src1); + } else { + e.mov(dest, src1); + e.add(dest, src2); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32, SIG_TYPE_I32C)) { + Reg32 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.add(dest, i->src2.value->constant.i32); + } else { + e.mov(dest, src1); + e.add(dest, i->src2.value->constant.i32); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32C, SIG_TYPE_I32)) { + Reg32 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.add(dest, i->src1.value->constant.i32); + } else { + e.mov(dest, src2); + e.add(dest, i->src1.value->constant.i32); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64, SIG_TYPE_I64)) { + Reg64 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.add(dest, src2); + } else if (dest == src2) { + e.add(dest, src1); + } else { + e.mov(dest, src1); + e.add(dest, src2); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64, SIG_TYPE_I64C)) { + Reg64 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.mov(e.rax, i->src2.value->constant.i64); + e.add(dest, e.rax); + } else { + e.mov(e.rax, i->src2.value->constant.i64); + e.mov(dest, src1); + e.add(dest, e.rax); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64C, SIG_TYPE_I64)) { + Reg64 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.mov(e.rax, i->src1.value->constant.i64); + e.add(dest, e.rax); + } else { + e.mov(e.rax, i->src1.value->constant.i64); + e.mov(dest, src2); + e.add(dest, e.rax); + } + if (i->flags & ARITHMETIC_SET_CARRY) { + UNIMPLEMENTED_SEQ(); + } + e.EndOp(dest, src2); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_ADD_CARRY, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ADD_CARRY, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SUB, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SUB, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_MUL, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MUL, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_MUL_HI, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MUL_HI, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DIV, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DIV, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_MUL_ADD, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MUL_ADD, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_MUL_SUB, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_MUL_SUB, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_NEG, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_NEG, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ABS, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ABS, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SQRT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SQRT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_RSQRT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_RSQRT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_POW2, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_POW2, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_LOG2, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_LOG2, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DOT_PRODUCT_3, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DOT_PRODUCT_3, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_DOT_PRODUCT_4, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_DOT_PRODUCT_4, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_AND, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_AND, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8, SIG_TYPE_I8)) { + Reg8 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.and(dest, src2); + } else if (dest == src2) { + e.and(dest, src1); + } else { + e.mov(dest, src1); + e.and(dest, src2); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8, SIG_TYPE_I8C)) { + Reg8 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.and(dest, i->src2.value->constant.i8); + } else { + e.mov(dest, src1); + e.and(dest, i->src2.value->constant.i8); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I8, SIG_TYPE_I8C, SIG_TYPE_I8)) { + Reg8 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.and(dest, i->src1.value->constant.i8); + } else { + e.mov(dest, src2); + e.and(dest, i->src1.value->constant.i8); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16, SIG_TYPE_I16)) { + Reg16 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.and(dest, src2); + } else if (dest == src2) { + e.and(dest, src1); + } else { + e.mov(dest, src1); + e.and(dest, src2); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16, SIG_TYPE_I16C)) { + Reg16 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.and(dest, i->src2.value->constant.i16); + } else { + e.mov(dest, src1); + e.and(dest, i->src2.value->constant.i16); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16C, SIG_TYPE_I16)) { + Reg16 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.and(dest, i->src1.value->constant.i16); + } else { + e.mov(dest, src2); + e.and(dest, i->src1.value->constant.i16); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32, SIG_TYPE_I32)) { + Reg32 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.and(dest, src2); + } else if (dest == src2) { + e.and(dest, src1); + } else { + e.mov(dest, src1); + e.and(dest, src2); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32, SIG_TYPE_I32C)) { + Reg32 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.and(dest, i->src2.value->constant.i32); + } else { + e.mov(dest, src1); + e.and(dest, i->src2.value->constant.i32); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32C, SIG_TYPE_I32)) { + Reg32 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.and(dest, i->src1.value->constant.i32); + } else { + e.mov(dest, src2); + e.and(dest, i->src1.value->constant.i32); + } + e.EndOp(dest, src2); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64, SIG_TYPE_I64)) { + Reg64 dest, src1, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0, + i->src2.value, src2, 0); + if (dest == src1) { + e.and(dest, src2); + } else if (dest == src2) { + e.and(dest, src1); + } else { + e.mov(dest, src1); + e.and(dest, src2); + } + e.EndOp(dest, src1, src2); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64, SIG_TYPE_I64C)) { + Reg64 dest, src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest == src1) { + e.mov(e.rax, i->src2.value->constant.i64); + e.and(dest, e.rax); + } else { + e.mov(e.rax, i->src2.value->constant.i64); + e.mov(dest, src1); + e.and(dest, e.rax); + } + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64C, SIG_TYPE_I64)) { + Reg64 dest, src2; + e.BeginOp(i->dest, dest, REG_DEST, + i->src2.value, src2, 0); + if (dest == src2) { + e.mov(e.rax, i->src1.value->constant.i64); + e.and(dest, e.rax); + } else { + e.mov(e.rax, i->src1.value->constant.i64); + e.mov(dest, src2); + e.and(dest, e.rax); + } + e.EndOp(dest, src2); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_OR, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_OR, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_XOR, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_XOR, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_NOT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_NOT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SHL, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SHL, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_SHL, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_SHL, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SHR, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SHR, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_SHR, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_SHR, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SHA, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SHA, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_VECTOR_SHA, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_VECTOR_SHA, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ROTATE_LEFT, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_ROTATE_LEFT, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I8, SIG_TYPE_I8C)) { + Reg8 dest; + Reg8 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest != src1) { + e.mov(dest, src1); + } + e.rol(dest, i->src2.value->constant.i8); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I16, SIG_TYPE_I8C)) { + Reg8 dest; + Reg16 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest != src1) { + e.mov(dest, src1); + } + e.rol(dest, i->src2.value->constant.i8); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I32, SIG_TYPE_I8C)) { + Reg8 dest; + Reg32 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest != src1) { + e.mov(dest, src1); + } + e.rol(dest, i->src2.value->constant.i8); + e.EndOp(dest, src1); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I64, SIG_TYPE_I8C)) { + Reg8 dest; + Reg64 src1; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src1, 0); + if (dest != src1) { + e.mov(dest, src1); + } + e.rol(dest, i->src2.value->constant.i8); + e.EndOp(dest, src1); + } else { + UNIMPLEMENTED_SEQ(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_BYTE_SWAP, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_BYTE_SWAP, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_I16, SIG_TYPE_I16)) { + Reg16 d, s1; + e.BeginOp(i->dest, d, REG_DEST | REG_ABCD, + i->src1.value, s1, 0); + if (d != s1) { + e.mov(d, s1); + e.xchg(d.cvt8(), Reg8(d.getIdx() + 4)); + } else { + e.xchg(d.cvt8(), Reg8(d.getIdx() + 4)); + } + e.EndOp(d, s1); + } else if (i->Match(SIG_TYPE_I32, SIG_TYPE_I32)) { + Reg32 d, s1; + e.BeginOp(i->dest, d, REG_DEST, + i->src1.value, s1, 0); + if (d != s1) { + e.mov(d, s1); + e.bswap(d); + } else { + e.bswap(d); + } + e.EndOp(d, s1); + } else if (i->Match(SIG_TYPE_I64, SIG_TYPE_I64)) { + Reg64 d, s1; + e.BeginOp(i->dest, d, REG_DEST, + i->src1.value, s1, 0); + if (d != s1) { + e.mov(d, s1); + e.bswap(d); + } else { + e.bswap(d); + } + e.EndOp(d, s1); + } else { + ASSERT_INVALID_TYPE(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_CNTLZ, [](X64Emitter& e, Instr*& instr) { - UNIMPLEMENTED_SEQ(); - instr = instr->next; + table->AddSequence(OPCODE_CNTLZ, [](X64Emitter& e, Instr*& i) { + if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I8)) { + Reg8 dest; + Reg8 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.bsr(dest.cvt16(), src.cvt16()); + // ZF = 1 if zero + e.mov(e.eax, 16); + e.cmovz(dest.cvt32(), e.eax); + e.sub(dest, 8); + e.xor(dest, 0x7); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I16)) { + Reg8 dest; + Reg16 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.bsr(dest.cvt16(), src); + // ZF = 1 if zero + e.mov(e.eax, 16); + e.cmovz(dest.cvt32(), e.eax); + e.xor(dest, 0xF); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I32)) { + Reg8 dest; + Reg32 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.bsr(dest.cvt32(), src); + // ZF = 1 if zero + e.mov(e.eax, 32); + e.cmovz(dest.cvt32(), e.eax); + e.xor(dest, 0x1F); + e.EndOp(dest, src); + } else if (i->Match(SIG_TYPE_IGNORE, SIG_TYPE_I64)) { + Reg8 dest; + Reg64 src; + e.BeginOp(i->dest, dest, REG_DEST, + i->src1.value, src, 0); + e.bsr(dest, src); + // ZF = 1 if zero + e.mov(e.eax, 64); + e.cmovz(dest.cvt32(), e.eax); + e.xor(dest, 0x3F); + e.EndOp(dest, src); + } else { + UNIMPLEMENTED_SEQ(); + } + i = i->next; return true; }); - table->AddSequence(OPCODE_INSERT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_INSERT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_EXTRACT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_EXTRACT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SPLAT, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SPLAT, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_PERMUTE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_PERMUTE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_SWIZZLE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_SWIZZLE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_PACK, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_PACK, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_UNPACK, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_UNPACK, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); @@ -689,27 +1733,27 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // Atomic // -------------------------------------------------------------------------- - table->AddSequence(OPCODE_COMPARE_EXCHANGE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_COMPARE_EXCHANGE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ATOMIC_EXCHANGE, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ATOMIC_EXCHANGE, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ATOMIC_ADD, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ATOMIC_ADD, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); - table->AddSequence(OPCODE_ATOMIC_SUB, [](X64Emitter& e, Instr*& instr) { + table->AddSequence(OPCODE_ATOMIC_SUB, [](X64Emitter& e, Instr*& i) { UNIMPLEMENTED_SEQ(); - instr = instr->next; + i = i->next; return true; }); } diff --git a/src/alloy/backend/x64/x64_emitter.cc b/src/alloy/backend/x64/x64_emitter.cc index 3a6b81b1c..24ce7e5f8 100644 --- a/src/alloy/backend/x64/x64_emitter.cc +++ b/src/alloy/backend/x64/x64_emitter.cc @@ -39,6 +39,7 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator) : code_cache_(backend->code_cache()), allocator_(allocator), CodeGenerator(MAX_CODE_SIZE, AutoGrow, allocator) { + xe_zero_struct(®_state_, sizeof(reg_state_)); } X64Emitter::~X64Emitter() { @@ -79,6 +80,17 @@ void* X64Emitter::Emplace(X64CodeCache* code_cache) { } int X64Emitter::Emit(HIRBuilder* builder) { + // These are the registers we will not be using. All others are fare game. + const uint32_t reserved_regs = + GetRegBit(rax) | + GetRegBit(rcx) | + GetRegBit(rdx) | + GetRegBit(rsp) | + GetRegBit(rbp) | + GetRegBit(rsi) | + GetRegBit(rdi) | + GetRegBit(xmm0); + // Function prolog. // Must be 16b aligned. // Windows is very strict about the form of this and the epilog: @@ -109,6 +121,11 @@ int X64Emitter::Emit(HIRBuilder* builder) { label = label->next; } + // Reset reg allocation state. + // If we start keeping regs across blocks this needs to change. + // We mark a few active so that the allocator doesn't use them. + reg_state_.active_regs = reg_state_.live_regs = reserved_regs; + // Add instructions. // The table will process sequences of instructions to (try to) // generate optimal code. @@ -129,3 +146,68 @@ int X64Emitter::Emit(HIRBuilder* builder) { return 0; } + +void X64Emitter::FindFreeRegs( + Value* v0, uint32_t& v0_idx, uint32_t v0_flags) { + // If the value is already in a register, use it. + if (v0->reg != -1) { + // Already in a register. Mark active and return. + v0_idx = v0->reg; + reg_state_.active_regs |= 1 << v0_idx; + return; + } + + uint32_t avail_regs = 0; + if (IsIntType(v0->type)) { + if (v0_flags & REG_ABCD) { + avail_regs = B00001111; + } else { + avail_regs = 0xFFFF; + } + } else { + avail_regs = 0xFFFF0000; + } + uint32_t free_regs = avail_regs & ~reg_state_.active_regs; + if (free_regs) { + // Just take one. + _BitScanReverse((DWORD*)&v0_idx, free_regs); + } else { + // Need to evict something. + XEASSERTALWAYS(); + } + + reg_state_.active_regs |= 1 << v0_idx; + reg_state_.live_regs |= 1 << v0_idx; + v0->reg = v0_idx; + reg_state_.reg_values[v0_idx] = v0; +} + +void X64Emitter::FindFreeRegs( + Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + Value* v1, uint32_t& v1_idx, uint32_t v1_flags) { + // TODO(benvanik): support REG_DEST reuse/etc. + FindFreeRegs(v0, v0_idx, v0_flags); + FindFreeRegs(v1, v1_idx, v1_flags); +} + +void X64Emitter::FindFreeRegs( + Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + Value* v1, uint32_t& v1_idx, uint32_t v1_flags, + Value* v2, uint32_t& v2_idx, uint32_t v2_flags) { + // TODO(benvanik): support REG_DEST reuse/etc. + FindFreeRegs(v0, v0_idx, v0_flags); + FindFreeRegs(v1, v1_idx, v1_flags); + FindFreeRegs(v2, v2_idx, v2_flags); +} + +void X64Emitter::FindFreeRegs( + Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + Value* v1, uint32_t& v1_idx, uint32_t v1_flags, + Value* v2, uint32_t& v2_idx, uint32_t v2_flags, + Value* v3, uint32_t& v3_idx, uint32_t v3_flags) { + // TODO(benvanik): support REG_DEST reuse/etc. + FindFreeRegs(v0, v0_idx, v0_flags); + FindFreeRegs(v1, v1_idx, v1_flags); + FindFreeRegs(v2, v2_idx, v2_flags); + FindFreeRegs(v3, v3_idx, v3_flags); +} diff --git a/src/alloy/backend/x64/x64_emitter.h b/src/alloy/backend/x64/x64_emitter.h index 987f28753..85e03ec4d 100644 --- a/src/alloy/backend/x64/x64_emitter.h +++ b/src/alloy/backend/x64/x64_emitter.h @@ -12,9 +12,12 @@ #include +#include + #include XEDECLARECLASS2(alloy, hir, HIRBuilder); +XEDECLARECLASS2(alloy, hir, Instr); namespace alloy { namespace backend { @@ -23,6 +26,11 @@ namespace x64 { class X64Backend; class X64CodeCache; +enum RegisterFlags { + REG_DEST = (1 << 0), + REG_ABCD = (1 << 1), +}; + // Unfortunately due to the design of xbyak we have to pass this to the ctor. class XbyakAllocator : public Xbyak::Allocator { public: @@ -39,6 +47,91 @@ public: int Emit(hir::HIRBuilder* builder, void*& out_code_address, size_t& out_code_size); +public: + template + void BeginOp(hir::Value* v0, V0& r0, uint32_t r0_flags) { + uint32_t v0_idx; + FindFreeRegs(v0, v0_idx, r0_flags); + SetupReg(v0_idx, r0); + } + template + void BeginOp(hir::Value* v0, V0& r0, uint32_t r0_flags, + hir::Value* v1, V1& r1, uint32_t r1_flags) { + uint32_t v0_idx, v1_idx; + FindFreeRegs(v0, v0_idx, r0_flags, + v1, v1_idx, r1_flags); + SetupReg(v0_idx, r0); + SetupReg(v1_idx, r1); + } + template + void BeginOp(hir::Value* v0, V0& r0, uint32_t r0_flags, + hir::Value* v1, V1& r1, uint32_t r1_flags, + hir::Value* v2, V2& r2, uint32_t r2_flags) { + uint32_t v0_idx, v1_idx, v2_idx; + FindFreeRegs(v0, v0_idx, r0_flags, + v1, v1_idx, r1_flags, + v2, v2_idx, r2_flags); + SetupReg(v0_idx, r0); + SetupReg(v1_idx, r1); + SetupReg(v2_idx, r2); + } + template + void BeginOp(hir::Value* v0, V0& r0, uint32_t r0_flags, + hir::Value* v1, V1& r1, uint32_t r1_flags, + hir::Value* v2, V2& r2, uint32_t r2_flags, + hir::Value* v3, V3& r3, uint32_t r3_flags) { + uint32_t v0_idx, v1_idx, v2_idx, v3_idx; + FindFreeRegs(v0, v0_idx, r0_flags, + v1, v1_idx, r1_flags, + v2, v2_idx, r2_flags, + v3, v3_idx, r3_flags); + SetupReg(v0_idx, r0); + SetupReg(v1_idx, r1); + SetupReg(v2_idx, r2); + SetupReg(v3_idx, r3); + } + template + void EndOp(V0& r0) { + reg_state_.active_regs = reg_state_.active_regs ^ GetRegBit(r0); + } + template + void EndOp(V0& r0, V1& r1) { + reg_state_.active_regs = reg_state_.active_regs ^ ( + GetRegBit(r0) | GetRegBit(r1)); + } + template + void EndOp(V0& r0, V1& r1, V2& r2) { + reg_state_.active_regs = reg_state_.active_regs ^ ( + GetRegBit(r0) | GetRegBit(r1) | GetRegBit(r2)); + } + template + void EndOp(V0& r0, V1& r1, V2& r2, V3& r3) { + reg_state_.active_regs = reg_state_.active_regs ^ ( + GetRegBit(r0) | GetRegBit(r1) | GetRegBit(r2) | GetRegBit(r3)); + } + + void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags); + void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + hir::Value* v1, uint32_t& v1_idx, uint32_t v1_flags); + void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + hir::Value* v1, uint32_t& v1_idx, uint32_t v1_flags, + hir::Value* v2, uint32_t& v2_idx, uint32_t v2_flags); + void FindFreeRegs(hir::Value* v0, uint32_t& v0_idx, uint32_t v0_flags, + hir::Value* v1, uint32_t& v1_idx, uint32_t v1_flags, + hir::Value* v2, uint32_t& v2_idx, uint32_t v2_flags, + hir::Value* v3, uint32_t& v3_idx, uint32_t v3_flags); + + static void SetupReg(uint32_t idx, Xbyak::Reg8& r) { r = Xbyak::Reg8(idx); } + static void SetupReg(uint32_t idx, Xbyak::Reg16& r) { r = Xbyak::Reg16(idx); } + static void SetupReg(uint32_t idx, Xbyak::Reg32& r) { r = Xbyak::Reg32(idx); } + static void SetupReg(uint32_t idx, Xbyak::Reg64& r) { r = Xbyak::Reg64(idx); } + static void SetupReg(uint32_t idx, Xbyak::Xmm& r) { r = Xbyak::Xmm(idx - 16); } + static uint32_t GetRegBit(const Xbyak::Reg8& r) { return 1 << r.getIdx(); } + static uint32_t GetRegBit(const Xbyak::Reg16& r) { return 1 << r.getIdx(); } + static uint32_t GetRegBit(const Xbyak::Reg32& r) { return 1 << r.getIdx(); } + static uint32_t GetRegBit(const Xbyak::Reg64& r) { return 1 << r.getIdx(); } + static uint32_t GetRegBit(const Xbyak::Xmm& r) { return 1 << (16 + r.getIdx()); } + private: void* Emplace(X64CodeCache* code_cache); int Emit(hir::HIRBuilder* builder); @@ -47,6 +140,16 @@ private: X64Backend* backend_; X64CodeCache* code_cache_; XbyakAllocator* allocator_; + + struct { + // Registers currently active within a begin/end op block. These + // cannot be reused. + uint32_t active_regs; + // Registers with values in them. + uint32_t live_regs; + // Current register values. + hir::Value* reg_values[32]; + } reg_state_; }; diff --git a/src/alloy/backend/x64/x64_function.cc b/src/alloy/backend/x64/x64_function.cc index bebb609db..86c1ab845 100644 --- a/src/alloy/backend/x64/x64_function.cc +++ b/src/alloy/backend/x64/x64_function.cc @@ -41,7 +41,9 @@ int X64Function::RemoveBreakpointImpl(Breakpoint* breakpoint) { } int X64Function::CallImpl(ThreadState* thread_state, uint64_t return_address) { - typedef void(*call_t)(ThreadState* thread_state, uint64_t return_address); - ((call_t)machine_code_)(thread_state, return_address); + //typedef void(*call_t)(ThreadState* thread_state, uint64_t return_address); + //((call_t)machine_code_)(thread_state, return_address); + typedef void(*call_t)(ThreadState* thread_state, uint8_t* membase); + ((call_t)machine_code_)(thread_state, thread_state->memory()->membase()); return 0; } diff --git a/src/alloy/compiler/compiler_passes.h b/src/alloy/compiler/compiler_passes.h index 69da71b10..d22758980 100644 --- a/src/alloy/compiler/compiler_passes.h +++ b/src/alloy/compiler/compiler_passes.h @@ -14,7 +14,6 @@ #include #include #include -#include //#include #include diff --git a/src/alloy/compiler/passes/finalization_pass.cc b/src/alloy/compiler/passes/finalization_pass.cc index d79bf3d2f..d7fa967bf 100644 --- a/src/alloy/compiler/passes/finalization_pass.cc +++ b/src/alloy/compiler/passes/finalization_pass.cc @@ -49,7 +49,15 @@ int FinalizationPass::Run(HIRBuilder* builder) { label = label->next; } - // ? + // ? remove useless jumps? + + // Renumber all instructions to make liveness tracking easier. + uint32_t n = 0; + auto instr = block->instr_head; + while (instr) { + instr->ordinal = n++; + instr = instr->next; + } block = block->next; } diff --git a/src/alloy/compiler/passes/register_allocation_pass.cc b/src/alloy/compiler/passes/register_allocation_pass.cc deleted file mode 100644 index ab0fac30b..000000000 --- a/src/alloy/compiler/passes/register_allocation_pass.cc +++ /dev/null @@ -1,51 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - -#include -#include -#include - -using namespace alloy; -using namespace alloy::backend; -using namespace alloy::compiler; -using namespace alloy::compiler::passes; -using namespace alloy::frontend; -using namespace alloy::hir; -using namespace alloy::runtime; - - -RegisterAllocationPass::RegisterAllocationPass(Backend* backend) : - CompilerPass() { - // TODO(benvanik): query backend info (register layout, etc). -} - -RegisterAllocationPass::~RegisterAllocationPass() { -} - -int RegisterAllocationPass::Run(HIRBuilder* builder) { - // Run through each block and give each dest value a register. - // This pass is currently really dumb, and will over spill and other badness. - - auto block = builder->first_block(); - while (block) { - if (ProcessBlock(block)) { - return 1; - } - block = block->next; - } - - return 0; -} - -int RegisterAllocationPass::ProcessBlock(Block* block) { - // - return 0; -} diff --git a/src/alloy/compiler/passes/register_allocation_pass.h b/src/alloy/compiler/passes/register_allocation_pass.h deleted file mode 100644 index 0f99c25f2..000000000 --- a/src/alloy/compiler/passes/register_allocation_pass.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2014 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#ifndef ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_ -#define ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_ - -#include - -XEDECLARECLASS2(alloy, backend, Backend); - - -namespace alloy { -namespace compiler { -namespace passes { - - -class RegisterAllocationPass : public CompilerPass { -public: - RegisterAllocationPass(backend::Backend* backend); - virtual ~RegisterAllocationPass(); - - virtual int Run(hir::HIRBuilder* builder); - -private: - int ProcessBlock(hir::Block* block); -}; - - -} // namespace passes -} // namespace compiler -} // namespace alloy - - -#endif // ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_ diff --git a/src/alloy/compiler/passes/sources.gypi b/src/alloy/compiler/passes/sources.gypi index b3b055ad3..b8866f72c 100644 --- a/src/alloy/compiler/passes/sources.gypi +++ b/src/alloy/compiler/passes/sources.gypi @@ -9,8 +9,6 @@ 'dead_code_elimination_pass.h', 'finalization_pass.cc', 'finalization_pass.h', - 'register_allocation_pass.cc', - 'register_allocation_pass.h', #'dead_store_elimination_pass.cc', #'dead_store_elimination_pass.h', 'simplification_pass.cc', diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index bfc8ee365..21ba0941f 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -50,9 +50,6 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : //compiler_->AddPass(new passes::DeadStoreEliminationPass()); compiler_->AddPass(new passes::DeadCodeEliminationPass()); - // After register allocation instructions should not be added/removed. - compiler_->AddPass(new passes::RegisterAllocationPass(backend)); - // Must come last. The HIR is not really HIR after this. compiler_->AddPass(new passes::FinalizationPass()); } diff --git a/src/alloy/hir/hir_builder.cc b/src/alloy/hir/hir_builder.cc index 99bde707d..508d37e13 100644 --- a/src/alloy/hir/hir_builder.cc +++ b/src/alloy/hir/hir_builder.cc @@ -420,6 +420,7 @@ Value* HIRBuilder::AllocValue(TypeName type) { value->def = NULL; value->use_head = NULL; value->tag = NULL; + value->reg = -1; return value; } @@ -432,6 +433,7 @@ Value* HIRBuilder::CloneValue(Value* source) { value->def = NULL; value->use_head = NULL; value->tag = NULL; + value->reg = -1; return value; } diff --git a/src/alloy/hir/instr.cc b/src/alloy/hir/instr.cc index 53b41b181..35349f28e 100644 --- a/src/alloy/hir/instr.cc +++ b/src/alloy/hir/instr.cc @@ -48,6 +48,19 @@ void Instr::set_src3(Value* value) { src3_use = value ? value->AddUse(block->arena, this) : NULL; } +bool Instr::Match(SignatureType dest_req, + SignatureType src1_req, + SignatureType src2_req, + SignatureType src3_req) const { + #define TO_SIG_TYPE(v) \ + (v ? (v->IsConstant() ? SignatureType((v->type + 1) | SIG_TYPE_C) : SignatureType(v->type + 1)) : SIG_TYPE_X) + return + ((dest_req == SIG_TYPE_IGNORE) || (dest_req == TO_SIG_TYPE(dest))) && + ((src1_req == SIG_TYPE_IGNORE) || (src1_req == TO_SIG_TYPE(src1.value))) && + ((src2_req == SIG_TYPE_IGNORE) || (src2_req == TO_SIG_TYPE(src2.value))) && + ((src3_req == SIG_TYPE_IGNORE) || (src3_req == TO_SIG_TYPE(src3.value))); +} + void Instr::Replace(const OpcodeInfo* opcode, uint16_t flags) { this->opcode = opcode; this->flags = flags; diff --git a/src/alloy/hir/instr.h b/src/alloy/hir/instr.h index 764c62ef8..42b3c36bf 100644 --- a/src/alloy/hir/instr.h +++ b/src/alloy/hir/instr.h @@ -24,6 +24,25 @@ namespace hir { class Block; class Label; +enum SignatureType { + SIG_TYPE_X = 0, + SIG_TYPE_I8 = 1, + SIG_TYPE_I16 = 2, + SIG_TYPE_I32 = 3, + SIG_TYPE_I64 = 4, + SIG_TYPE_F32 = 5, + SIG_TYPE_F64 = 6, + SIG_TYPE_V128 = 7, + SIG_TYPE_C = (1 << 3), + SIG_TYPE_I8C = SIG_TYPE_C | SIG_TYPE_I8, + SIG_TYPE_I16C = SIG_TYPE_C | SIG_TYPE_I16, + SIG_TYPE_I32C = SIG_TYPE_C | SIG_TYPE_I32, + SIG_TYPE_I64C = SIG_TYPE_C | SIG_TYPE_I64, + SIG_TYPE_F32C = SIG_TYPE_C | SIG_TYPE_F32, + SIG_TYPE_F64C = SIG_TYPE_C | SIG_TYPE_F64, + SIG_TYPE_V128C = SIG_TYPE_C | SIG_TYPE_V128, + SIG_TYPE_IGNORE = 0xFF, +}; class Instr { public: @@ -33,6 +52,7 @@ public: const OpcodeInfo* opcode; uint16_t flags; + uint16_t ordinal; typedef union { runtime::FunctionInfo* symbol_info; @@ -54,6 +74,11 @@ public: void set_src2(Value* value); void set_src3(Value* value); + bool Match(SignatureType dest = SIG_TYPE_X, + SignatureType src1 = SIG_TYPE_X, + SignatureType src2 = SIG_TYPE_X, + SignatureType src3 = SIG_TYPE_X) const; + void Replace(const OpcodeInfo* opcode, uint16_t flags); void Remove(); }; diff --git a/src/alloy/hir/value.cc b/src/alloy/hir/value.cc index 43d40d647..a684c6f2b 100644 --- a/src/alloy/hir/value.cc +++ b/src/alloy/hir/value.cc @@ -36,6 +36,23 @@ void Value::RemoveUse(Use* use) { } } +uint32_t Value::AsUint32() { + XEASSERT(IsConstant()); + switch (type) { + case INT8_TYPE: + return constant.i8; + case INT16_TYPE: + return constant.i16; + case INT32_TYPE: + return constant.i32; + case INT64_TYPE: + return (uint32_t)constant.i64; + default: + XEASSERTALWAYS(); + return 0; + } +} + uint64_t Value::AsUint64() { XEASSERT(IsConstant()); switch (type) { diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index 3bc3bfdb7..ba0db526a 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -21,17 +21,22 @@ class Instr; enum TypeName { - INT8_TYPE, - INT16_TYPE, - INT32_TYPE, - INT64_TYPE, - FLOAT32_TYPE, - FLOAT64_TYPE, - VEC128_TYPE, + // Many tables rely on this ordering. + INT8_TYPE = 0, + INT16_TYPE = 1, + INT32_TYPE = 2, + INT64_TYPE = 3, + FLOAT32_TYPE = 4, + FLOAT64_TYPE = 5, + VEC128_TYPE = 6, MAX_TYPENAME, }; +static bool IsIntType(TypeName type_name) { + return type_name < 4; +} + enum ValueFlags { VALUE_IS_CONSTANT = (1 << 1), }; @@ -59,7 +64,7 @@ public: TypeName type; uint32_t flags; - uint32_t reserved; + uint32_t reg; ConstantValue constant; Instr* def; @@ -174,6 +179,7 @@ public: (other->flags & VALUE_IS_CONSTANT) && constant.i64 != other->constant.i64; } + uint32_t AsUint32(); uint64_t AsUint64(); void Cast(TypeName target_type);