Removing llvm backend.

This commit is contained in:
Ben Vanik 2013-05-25 04:28:21 -07:00
parent eb22289dc7
commit edb3aabdd4
20 changed files with 0 additions and 5575 deletions

View File

@ -1,41 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_EMIT_H_
#define XENIA_CPU_LLVMBE_EMIT_H_
#include <xenia/cpu/ppc/instr.h>
namespace xe {
namespace cpu {
namespace llvmbe {
void RegisterEmitCategoryALU();
void RegisterEmitCategoryControl();
void RegisterEmitCategoryFPU();
void RegisterEmitCategoryMemory();
#define XEEMITTER(name, opcode, format) int InstrEmit_##name
#define XEREGISTERINSTR(name, opcode) \
RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name);
#define XEINSTRNOTIMPLEMENTED()
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_EMIT_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,713 +0,0 @@
/*
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/emit.h>
#include <xenia/cpu/llvmbe/emitter_context.h>
#include <xenia/cpu/ppc/state.h>
using namespace llvm;
using namespace xe::cpu;
using namespace xe::cpu::ppc;
using namespace xe::cpu::sdb;
namespace xe {
namespace cpu {
namespace llvmbe {
int XeEmitIndirectBranchTo(
EmitterContext& e, IRBuilder<>& b, const char* src, uint32_t cia,
bool lk, uint32_t reg) {
// TODO(benvanik): run a DFA pass to see if we can detect whether this is
// a normal function return that is pulling the LR from the stack that
// it set in the prolog. If so, we can omit the dynamic check!
// NOTE: we avoid spilling registers until we know that the target is not
// a basic block within this function.
Value* target;
switch (reg) {
case kXEPPCRegLR:
target = e.lr_value();
break;
case kXEPPCRegCTR:
target = e.ctr_value();
break;
default:
XEASSERTALWAYS();
return 1;
}
// Dynamic test when branching to LR, which is usually used for the return.
// We only do this if LK=0 as returns wouldn't set LR.
// Ideally it's a return and we can just do a simple ret and be done.
// If it's not, we fall through to the full indirection logic.
if (!lk && reg == kXEPPCRegLR) {
BasicBlock* next_block = e.GetNextBasicBlock();
BasicBlock* mismatch_bb = BasicBlock::Create(*e.context(), "lr_mismatch",
e.gen_fn(), next_block);
Value* lr_cmp = b.CreateICmpEQ(target, ++(e.gen_fn()->arg_begin()));
// The return block will spill registers for us.
b.CreateCondBr(lr_cmp, e.GetReturnBasicBlock(), mismatch_bb);
b.SetInsertPoint(mismatch_bb);
}
// Defer to the generator, which will do fancy things.
bool likely_local = !lk && reg == kXEPPCRegCTR;
return e.GenerateIndirectionBranch(cia, target, lk, likely_local);
}
int XeEmitBranchTo(
EmitterContext& e, IRBuilder<>& b, const char* src, uint32_t cia,
bool lk) {
// Get the basic block and switch behavior based on outgoing type.
FunctionBlock* fn_block = e.fn_block();
switch (fn_block->outgoing_type) {
case FunctionBlock::kTargetBlock:
{
BasicBlock* target_bb = e.GetBasicBlock(fn_block->outgoing_address);
XEASSERTNOTNULL(target_bb);
b.CreateBr(target_bb);
break;
}
case FunctionBlock::kTargetFunction:
{
// Spill all registers to memory.
// TODO(benvanik): only spill ones used by the target function? Use
// calling convention flags on the function to not spill temp
// registers?
e.SpillRegisters();
XEASSERTNOTNULL(fn_block->outgoing_function);
Function* target_fn = e.GetFunction(fn_block->outgoing_function);
Function::arg_iterator args = e.gen_fn()->arg_begin();
Value* state_ptr = args;
BasicBlock* next_bb = e.GetNextBasicBlock();
if (!lk || !next_bb) {
// Tail. No need to refill the local register values, just return.
// We optimize this by passing in the LR from our parent instead of the
// next instruction. This allows the return from our callee to pop
// all the way up.
b.CreateCall2(target_fn, state_ptr, ++args);
b.CreateRetVoid();
} else {
// Will return here eventually.
// Refill registers from state.
b.CreateCall2(target_fn, state_ptr, b.getInt64(cia + 4));
e.FillRegisters();
b.CreateBr(next_bb);
}
break;
}
case FunctionBlock::kTargetLR:
{
// An indirect jump.
printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegLR);
}
case FunctionBlock::kTargetCTR:
{
// An indirect jump.
printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegCTR);
}
default:
case FunctionBlock::kTargetNone:
XEASSERTALWAYS();
return 1;
}
return 0;
}
XEEMITTER(bx, 0x48000000, I )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// if AA then
// NIA <- EXTS(LI || 0b00)
// else
// NIA <- CIA + EXTS(LI || 0b00)
// if LK then
// LR <- CIA + 4
uint32_t nia;
if (i.I.AA) {
nia = XEEXTS26(i.I.LI << 2);
} else {
nia = i.address + XEEXTS26(i.I.LI << 2);
}
if (i.I.LK) {
e.update_lr_value(b.getInt32(i.address + 4));
}
return XeEmitBranchTo(e, b, "bx", i.address, i.I.LK);
}
XEEMITTER(bcx, 0x40000000, B )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// if ¬BO[2] then
// CTR <- CTR - 1
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3])
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
// if ctr_ok & cond_ok then
// if AA then
// NIA <- EXTS(BD || 0b00)
// else
// NIA <- CIA + EXTS(BD || 0b00)
// if LK then
// LR <- CIA + 4
// NOTE: the condition bits are reversed!
// 01234 (docs)
// 43210 (real)
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
// The docs say always, though...
if (i.B.LK) {
e.update_lr_value(b.getInt32(i.address + 4));
}
Value* ctr_ok = NULL;
if (XESELECTBITS(i.B.BO, 2, 2)) {
// Ignore ctr.
} else {
// Decrement counter.
Value* ctr = e.ctr_value();
ctr = b.CreateSub(ctr, b.getInt64(1));
e.update_ctr_value(ctr);
// Ctr check.
if (XESELECTBITS(i.B.BO, 1, 1)) {
ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0));
} else {
ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0));
}
}
Value* cond_ok = NULL;
if (XESELECTBITS(i.B.BO, 4, 4)) {
// Ignore cond.
} else {
Value* cr = e.cr_value(i.B.BI >> 2);
cr = b.CreateAnd(cr, 1 << (i.B.BI & 3));
if (XESELECTBITS(i.B.BO, 3, 3)) {
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
} else {
cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
}
}
// We do a bit of optimization here to make the llvm assembly easier to read.
Value* ok = NULL;
if (ctr_ok && cond_ok) {
ok = b.CreateAnd(ctr_ok, cond_ok);
} else if (ctr_ok) {
ok = ctr_ok;
} else if (cond_ok) {
ok = cond_ok;
}
// Handle unconditional branches without extra fluff.
BasicBlock* original_bb = b.GetInsertBlock();
if (ok) {
char name[32];
xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
BasicBlock* next_block = e.GetNextBasicBlock();
BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
next_block);
b.CreateCondBr(ok, branch_bb, next_block);
b.SetInsertPoint(branch_bb);
}
// Note that this occurs entirely within the branch true block.
uint32_t nia;
if (i.B.AA) {
nia = XEEXTS26(i.B.BD << 2);
} else {
nia = i.address + XEEXTS26(i.B.BD << 2);
}
if (XeEmitBranchTo(e, b, "bcx", i.address, i.B.LK)) {
return 1;
}
b.SetInsertPoint(original_bb);
return 0;
}
XEEMITTER(bcctrx, 0x4C000420, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
// if cond_ok then
// NIA <- CTR[0:61] || 0b00
// if LK then
// LR <- CIA + 4
// NOTE: the condition bits are reversed!
// 01234 (docs)
// 43210 (real)
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
// The docs say always, though...
if (i.XL.LK) {
e.update_lr_value(b.getInt32(i.address + 4));
}
Value* cond_ok = NULL;
if (XESELECTBITS(i.XL.BO, 4, 4)) {
// Ignore cond.
} else {
Value* cr = e.cr_value(i.XL.BI >> 2);
cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3));
if (XESELECTBITS(i.XL.BO, 3, 3)) {
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
} else {
cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
}
}
// We do a bit of optimization here to make the llvm assembly easier to read.
Value* ok = NULL;
if (cond_ok) {
ok = cond_ok;
}
// Handle unconditional branches without extra fluff.
BasicBlock* original_bb = b.GetInsertBlock();
if (ok) {
char name[32];
xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcctrx", i.address);
BasicBlock* next_block = e.GetNextBasicBlock();
XEASSERTNOTNULL(next_block);
BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
next_block);
b.CreateCondBr(ok, branch_bb, next_block);
b.SetInsertPoint(branch_bb);
}
// Note that this occurs entirely within the branch true block.
if (XeEmitBranchTo(e, b, "bcctrx", i.address, i.XL.LK)) {
return 1;
}
b.SetInsertPoint(original_bb);
return 0;
}
XEEMITTER(bclrx, 0x4C000020, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// if ¬BO[2] then
// CTR <- CTR - 1
// ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]
// cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
// if ctr_ok & cond_ok then
// NIA <- LR[0:61] || 0b00
// if LK then
// LR <- CIA + 4
// NOTE: the condition bits are reversed!
// 01234 (docs)
// 43210 (real)
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
// The docs say always, though...
if (i.XL.LK) {
e.update_lr_value(b.getInt32(i.address + 4));
}
Value* ctr_ok = NULL;
if (XESELECTBITS(i.XL.BO, 2, 2)) {
// Ignore ctr.
} else {
// Decrement counter.
Value* ctr = e.ctr_value();
ctr = b.CreateSub(ctr, b.getInt64(1));
// Ctr check.
if (XESELECTBITS(i.XL.BO, 1, 1)) {
ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0));
} else {
ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0));
}
}
Value* cond_ok = NULL;
if (XESELECTBITS(i.XL.BO, 4, 4)) {
// Ignore cond.
} else {
Value* cr = e.cr_value(i.XL.BI >> 2);
cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3));
if (XESELECTBITS(i.XL.BO, 3, 3)) {
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
} else {
cond_ok = b.CreateICmpEQ(cr, b.getInt64(0));
}
}
// We do a bit of optimization here to make the llvm assembly easier to read.
Value* ok = NULL;
if (ctr_ok && cond_ok) {
ok = b.CreateAnd(ctr_ok, cond_ok);
} else if (ctr_ok) {
ok = ctr_ok;
} else if (cond_ok) {
ok = cond_ok;
}
// Handle unconditional branches without extra fluff.
BasicBlock* original_bb = b.GetInsertBlock();
if (ok) {
char name[32];
xesnprintfa(name, XECOUNT(name), "loc_%.8X_bclrx", i.address);
BasicBlock* next_block = e.GetNextBasicBlock();
XEASSERTNOTNULL(next_block);
BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(),
next_block);
b.CreateCondBr(ok, branch_bb, next_block);
b.SetInsertPoint(branch_bb);
}
// Note that this occurs entirely within the branch true block.
if (XeEmitBranchTo(e, b, "bclrx", i.address, i.XL.LK)) {
return 1;
}
b.SetInsertPoint(original_bb);
return 0;
}
// Condition register logical (A-23)
XEEMITTER(crand, 0x4C000202, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(crandc, 0x4C000102, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(creqv, 0x4C000242, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(crnand, 0x4C0001C2, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(crnor, 0x4C000042, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(cror, 0x4C000382, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(crorc, 0x4C000342, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(crxor, 0x4C000182, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mcrf, 0x4C000000, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// System linkage (A-24)
XEEMITTER(sc, 0x44000002, SC )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Trap (A-25)
int XeEmitTrap(EmitterContext& e, IRBuilder<>& b, InstrData& i,
Value* va, Value* vb, uint32_t TO) {
// if (a < b) & TO[0] then TRAP
// if (a > b) & TO[1] then TRAP
// if (a = b) & TO[2] then TRAP
// if (a <u b) & TO[3] then TRAP
// if (a >u b) & TO[4] then TRAP
// Bits swapped:
// 01234
// 43210
if (!TO) {
return 0;
}
BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.gen_fn(),
e.GetNextBasicBlock());
BasicBlock* trap_bb = BasicBlock::Create(*e.context(), "", e.gen_fn(),
after_bb);
// Create the basic blocks (so we can chain).
std::vector<BasicBlock*> bbs;
if (TO & (1 << 4)) {
bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
}
if (TO & (1 << 3)) {
bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
}
if (TO & (1 << 2)) {
bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
}
if (TO & (1 << 1)) {
bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
}
if (TO & (1 << 0)) {
bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb));
}
bbs.push_back(after_bb);
// Jump to the first bb.
b.CreateBr(bbs.front());
// Setup each basic block.
std::vector<BasicBlock*>::iterator it = bbs.begin();
if (TO & (1 << 4)) {
// a < b
BasicBlock* bb = *(it++);
b.SetInsertPoint(bb);
Value* cmp = b.CreateICmpSLT(va, vb);
b.CreateCondBr(cmp, trap_bb, *it);
}
if (TO & (1 << 3)) {
// a > b
BasicBlock* bb = *(it++);
b.SetInsertPoint(bb);
Value* cmp = b.CreateICmpSGT(va, vb);
b.CreateCondBr(cmp, trap_bb, *it);
}
if (TO & (1 << 2)) {
// a = b
BasicBlock* bb = *(it++);
b.SetInsertPoint(bb);
Value* cmp = b.CreateICmpEQ(va, vb);
b.CreateCondBr(cmp, trap_bb, *it);
}
if (TO & (1 << 1)) {
// a <u b
BasicBlock* bb = *(it++);
b.SetInsertPoint(bb);
Value* cmp = b.CreateICmpULT(va, vb);
b.CreateCondBr(cmp, trap_bb, *it);
}
if (TO & (1 << 0)) {
// a >u b
BasicBlock* bb = *(it++);
b.SetInsertPoint(bb);
Value* cmp = b.CreateICmpUGT(va, vb);
b.CreateCondBr(cmp, trap_bb, *it);
}
// Create trap BB.
b.SetInsertPoint(trap_bb);
e.SpillRegisters();
// TODO(benvanik): use @llvm.debugtrap? could make debugging better
b.CreateCall2(e.gen_module()->getFunction("XeTrap"),
e.gen_fn()->arg_begin(),
b.getInt32(i.address));
b.CreateBr(after_bb);
// Resume.
b.SetInsertPoint(after_bb);
return 0;
}
XEEMITTER(td, 0x7C000088, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// a <- (RA)
// b <- (RB)
// if (a < b) & TO[0] then TRAP
// if (a > b) & TO[1] then TRAP
// if (a = b) & TO[2] then TRAP
// if (a <u b) & TO[3] then TRAP
// if (a >u b) & TO[4] then TRAP
return XeEmitTrap(e, b, i,
e.gpr_value(i.X.RA),
e.gpr_value(i.X.RB),
i.X.RT);
}
XEEMITTER(tdi, 0x08000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// a <- (RA)
// if (a < EXTS(SI)) & TO[0] then TRAP
// if (a > EXTS(SI)) & TO[1] then TRAP
// if (a = EXTS(SI)) & TO[2] then TRAP
// if (a <u EXTS(SI)) & TO[3] then TRAP
// if (a >u EXTS(SI)) & TO[4] then TRAP
return XeEmitTrap(e, b, i,
e.gpr_value(i.D.RA),
b.getInt64(XEEXTS16(i.D.DS)),
i.D.RT);
}
XEEMITTER(tw, 0x7C000008, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// a <- EXTS((RA)[32:63])
// b <- EXTS((RB)[32:63])
// if (a < b) & TO[0] then TRAP
// if (a > b) & TO[1] then TRAP
// if (a = b) & TO[2] then TRAP
// if (a <u b) & TO[3] then TRAP
// if (a >u b) & TO[4] then TRAP
return XeEmitTrap(e, b, i,
b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RA),
b.getInt32Ty()),
b.getInt64Ty()),
b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RB),
b.getInt32Ty()),
b.getInt64Ty()),
i.X.RT);
}
XEEMITTER(twi, 0x0C000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// a <- EXTS((RA)[32:63])
// if (a < EXTS(SI)) & TO[0] then TRAP
// if (a > EXTS(SI)) & TO[1] then TRAP
// if (a = EXTS(SI)) & TO[2] then TRAP
// if (a <u EXTS(SI)) & TO[3] then TRAP
// if (a >u EXTS(SI)) & TO[4] then TRAP
return XeEmitTrap(e, b, i,
b.CreateSExt(b.CreateTrunc(e.gpr_value(i.D.RA),
b.getInt32Ty()),
b.getInt64Ty()),
b.getInt64(XEEXTS16(i.D.DS)),
i.D.RT);
}
// Processor control (A-26)
XEEMITTER(mfcr, 0x7C000026, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mfspr, 0x7C0002A6, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// n <- spr[5:9] || spr[0:4]
// if length(SPR(n)) = 64 then
// RT <- SPR(n)
// else
// RT <- i32.0 || SPR(n)
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
Value* v = NULL;
switch (n) {
case 1:
// XER
v = e.xer_value();
break;
case 8:
// LR
v = e.lr_value();
break;
case 9:
// CTR
v = e.ctr_value();
break;
default:
XEINSTRNOTIMPLEMENTED();
return 1;
}
e.update_gpr_value(i.XFX.RT, v);
return 0;
}
XEEMITTER(mftb, 0x7C0002E6, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtcrf, 0x7C000120, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtspr, 0x7C0003A6, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// n <- spr[5:9] || spr[0:4]
// if length(SPR(n)) = 64 then
// SPR(n) <- (RS)
// else
// SPR(n) <- (RS)[32:63]
Value* v = e.gpr_value(i.XFX.RT);
const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F);
switch (n) {
case 1:
// XER
e.update_xer_value(v);
break;
case 8:
// LR
e.update_lr_value(v);
break;
case 9:
// CTR
e.update_ctr_value(v);
break;
default:
XEINSTRNOTIMPLEMENTED();
return 1;
}
return 0;
}
void RegisterEmitCategoryControl() {
XEREGISTERINSTR(bx, 0x48000000);
XEREGISTERINSTR(bcx, 0x40000000);
XEREGISTERINSTR(bcctrx, 0x4C000420);
XEREGISTERINSTR(bclrx, 0x4C000020);
XEREGISTERINSTR(crand, 0x4C000202);
XEREGISTERINSTR(crandc, 0x4C000102);
XEREGISTERINSTR(creqv, 0x4C000242);
XEREGISTERINSTR(crnand, 0x4C0001C2);
XEREGISTERINSTR(crnor, 0x4C000042);
XEREGISTERINSTR(cror, 0x4C000382);
XEREGISTERINSTR(crorc, 0x4C000342);
XEREGISTERINSTR(crxor, 0x4C000182);
XEREGISTERINSTR(mcrf, 0x4C000000);
XEREGISTERINSTR(sc, 0x44000002);
XEREGISTERINSTR(td, 0x7C000088);
XEREGISTERINSTR(tdi, 0x08000000);
XEREGISTERINSTR(tw, 0x7C000008);
XEREGISTERINSTR(twi, 0x0C000000);
XEREGISTERINSTR(mfcr, 0x7C000026);
XEREGISTERINSTR(mfspr, 0x7C0002A6);
XEREGISTERINSTR(mftb, 0x7C0002E6);
XEREGISTERINSTR(mtcrf, 0x7C000120);
XEREGISTERINSTR(mtspr, 0x7C0003A6);
}
} // namespace llvmbe
} // namespace cpu
} // namespace xe

View File

@ -1,296 +0,0 @@
/*
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/emit.h>
#include <xenia/cpu/llvmbe/emitter_context.h>
using namespace llvm;
using namespace xe::cpu;
using namespace xe::cpu::ppc;
namespace xe {
namespace cpu {
namespace llvmbe {
// Floating-point arithmetic (A-8)
XEEMITTER(faddx, 0xFC00002A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(faddsx, 0xEC00002A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fdivx, 0xFC000024, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fdivsx, 0xEC000024, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmulx, 0xFC000032, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmulsx, 0xEC000032, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fresx, 0xEC000030, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(frsqrtex, 0xFC000034, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsubx, 0xFC000028, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsubsx, 0xEC000028, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fselx, 0xFC00002E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsqrtx, 0xFC00002C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fsqrtsx, 0xEC00002C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point multiply-add (A-9)
XEEMITTER(fmaddx, 0xFC00003A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmaddsx, 0xEC00003A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmsubx, 0xFC000038, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmsubsx, 0xEC000038, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmaddx, 0xFC00003E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmaddsx, 0xEC00003E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmsubx, 0xFC00003C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnmsubsx, 0xEC00003C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point rounding and conversion (A-10)
XEEMITTER(fcfidx, 0xFC00069C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctidx, 0xFC00065C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctidzx, 0xFC00065E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctiwx, 0xFC00001C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fctiwzx, 0xFC00001E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(frspx, 0xFC000018, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point compare (A-11)
XEEMITTER(fcmpo, 0xFC000040, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fcmpu, 0xFC000000, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
// if (FRA) is a NaN or (FRB) is a NaN then
// c <- 0b0001
// else if (FRA) < (FRB) then
// c <- 0b1000
// else if (FRA) > (FRB) then
// c <- 0b0100
// else {
// c <- 0b0010
// }
// FPCC <- c
// CR[4*BF:4*BF+3] <- c
// if (FRA) is an SNaN or (FRB) is an SNaN then
// VXSNAN <- 1
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point status and control register (A
XEEMITTER(mcrfs, 0xFC000080, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mffsx, 0xFC00048E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsb0x, 0xFC00008C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsb1x, 0xFC00004C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(mtfsfix, 0xFC00010C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
// Floating-point move (A-21)
XEEMITTER(fabsx, 0xFC000210, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fmrx, 0xFC000090, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnabsx, 0xFC000110, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
XEEMITTER(fnegx, 0xFC000050, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
void RegisterEmitCategoryFPU() {
XEREGISTERINSTR(faddx, 0xFC00002A);
XEREGISTERINSTR(faddsx, 0xEC00002A);
XEREGISTERINSTR(fdivx, 0xFC000024);
XEREGISTERINSTR(fdivsx, 0xEC000024);
XEREGISTERINSTR(fmulx, 0xFC000032);
XEREGISTERINSTR(fmulsx, 0xEC000032);
XEREGISTERINSTR(fresx, 0xEC000030);
XEREGISTERINSTR(frsqrtex, 0xFC000034);
XEREGISTERINSTR(fsubx, 0xFC000028);
XEREGISTERINSTR(fsubsx, 0xEC000028);
XEREGISTERINSTR(fselx, 0xFC00002E);
XEREGISTERINSTR(fsqrtx, 0xFC00002C);
XEREGISTERINSTR(fsqrtsx, 0xEC00002C);
XEREGISTERINSTR(fmaddx, 0xFC00003A);
XEREGISTERINSTR(fmaddsx, 0xEC00003A);
XEREGISTERINSTR(fmsubx, 0xFC000038);
XEREGISTERINSTR(fmsubsx, 0xEC000038);
XEREGISTERINSTR(fnmaddx, 0xFC00003E);
XEREGISTERINSTR(fnmaddsx, 0xEC00003E);
XEREGISTERINSTR(fnmsubx, 0xFC00003C);
XEREGISTERINSTR(fnmsubsx, 0xEC00003C);
XEREGISTERINSTR(fcfidx, 0xFC00069C);
XEREGISTERINSTR(fctidx, 0xFC00065C);
XEREGISTERINSTR(fctidzx, 0xFC00065E);
XEREGISTERINSTR(fctiwx, 0xFC00001C);
XEREGISTERINSTR(fctiwzx, 0xFC00001E);
XEREGISTERINSTR(frspx, 0xFC000018);
XEREGISTERINSTR(fcmpo, 0xFC000040);
XEREGISTERINSTR(fcmpu, 0xFC000000);
XEREGISTERINSTR(mcrfs, 0xFC000080);
XEREGISTERINSTR(mffsx, 0xFC00048E);
XEREGISTERINSTR(mtfsb0x, 0xFC00008C);
XEREGISTERINSTR(mtfsb1x, 0xFC00004C);
XEREGISTERINSTR(mtfsfx, 0xFC00058E);
XEREGISTERINSTR(mtfsfix, 0xFC00010C);
XEREGISTERINSTR(fabsx, 0xFC000210);
XEREGISTERINSTR(fmrx, 0xFC000090);
XEREGISTERINSTR(fnabsx, 0xFC000110);
XEREGISTERINSTR(fnegx, 0xFC000050);
}
} // namespace llvmbe
} // namespace cpu
} // namespace xe

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,146 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_
#define XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_
#include <llvm/IR/Attributes.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <xenia/cpu/sdb.h>
#include <xenia/cpu/ppc/instr.h>
namespace xe {
namespace cpu {
namespace llvmbe {
class EmitterContext {
public:
EmitterContext(
xe_memory_ref memory,
llvm::LLVMContext* context, llvm::Module* gen_module);
~EmitterContext();
int Init(sdb::FunctionSymbol* fn, llvm::Function* gen_fn);
llvm::LLVMContext* context();
llvm::Module* gen_module();
sdb::FunctionSymbol* fn();
llvm::Function* gen_fn();
sdb::FunctionBlock* fn_block();
void PushInsertPoint();
void PopInsertPoint();
void GenerateBasicBlocks();
llvm::BasicBlock* GetBasicBlock(uint32_t address);
llvm::BasicBlock* GetNextBasicBlock();
llvm::BasicBlock* GetReturnBasicBlock();
llvm::Function* GetFunction(sdb::FunctionSymbol* symbol);
int GenerateIndirectionBranch(uint32_t cia, llvm::Value* target,
bool lk, bool likely_local);
llvm::Value* LoadStateValue(uint32_t offset, llvm::Type* type,
const char* name = "");
void StoreStateValue(uint32_t offset, llvm::Type* type, llvm::Value* value);
llvm::Value* cia_value();
llvm::Value* SetupLocal(llvm::Type* type, const char* name);
void FillRegisters();
void SpillRegisters();
llvm::Value* xer_value();
void update_xer_value(llvm::Value* value);
void update_xer_with_overflow(llvm::Value* value);
void update_xer_with_carry(llvm::Value* value);
void update_xer_with_overflow_and_carry(llvm::Value* value);
llvm::Value* lr_value();
void update_lr_value(llvm::Value* value);
llvm::Value* ctr_value();
void update_ctr_value(llvm::Value* value);
llvm::Value* cr_value(uint32_t n);
void update_cr_value(uint32_t n, llvm::Value* value);
void update_cr_with_cond(uint32_t n, llvm::Value* lhs, llvm::Value* rhs,
bool is_signed);
llvm::Value* gpr_value(uint32_t n);
void update_gpr_value(uint32_t n, llvm::Value* value);
llvm::Value* fpr_value(uint32_t n);
void update_fpr_value(uint32_t n, llvm::Value* value);
llvm::Value* GetMembase();
llvm::Value* GetMemoryAddress(uint32_t cia, llvm::Value* addr);
llvm::Value* ReadMemory(
uint32_t cia, llvm::Value* addr, uint32_t size, bool acquire = false);
void WriteMemory(
uint32_t cia, llvm::Value* addr, uint32_t size, llvm::Value* value,
bool release = false);
private:
void GenerateSharedBlocks();
int PrepareBasicBlock(sdb::FunctionBlock* block);
void GenerateBasicBlock(sdb::FunctionBlock* block);
void SetupLocals();
xe_memory_ref memory_;
llvm::LLVMContext* context_;
llvm::Module* gen_module_;
llvm::IRBuilder<>* builder_;
llvm::FunctionType* fn_type_;
sdb::FunctionSymbol* fn_;
llvm::Function* gen_fn_;
sdb::FunctionBlock* fn_block_;
llvm::BasicBlock* return_block_;
llvm::BasicBlock* internal_indirection_block_;
llvm::BasicBlock* external_indirection_block_;
llvm::BasicBlock* bb_;
std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock::iterator> >
insert_points_;
std::map<uint32_t, llvm::BasicBlock*> bbs_;
// Address of the instruction being generated.
uint32_t cia_;
ppc::InstrAccessBits access_bits_;
struct {
llvm::Value* indirection_target;
llvm::Value* indirection_cia;
llvm::Value* xer;
llvm::Value* lr;
llvm::Value* ctr;
llvm::Value* cr[8];
llvm::Value* gpr[32];
llvm::Value* fpr[32];
} locals_;
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_

View File

@ -1,78 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_backend.h>
#include <llvm/ExecutionEngine/Interpreter.h>
#include <llvm/ExecutionEngine/JIT.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/TargetSelect.h>
#include <xenia/cpu/llvmbe/emit.h>
#include <xenia/cpu/llvmbe/llvm_jit.h>
using namespace llvm;
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::llvmbe;
namespace {
void InitializeIfNeeded();
void CleanupOnShutdown();
void InitializeIfNeeded() {
static bool has_initialized = false;
if (has_initialized) {
return;
}
has_initialized = true;
LLVMLinkInInterpreter();
LLVMLinkInJIT();
InitializeNativeTarget();
llvm_start_multithreaded();
llvmbe::RegisterEmitCategoryALU();
llvmbe::RegisterEmitCategoryControl();
llvmbe::RegisterEmitCategoryFPU();
llvmbe::RegisterEmitCategoryMemory();
atexit(CleanupOnShutdown);
}
void CleanupOnShutdown() {
llvm_shutdown();
}
}
LLVMBackend::LLVMBackend() :
Backend() {
InitializeIfNeeded();
}
LLVMBackend::~LLVMBackend() {
}
CodeUnitBuilder* LLVMBackend::CreateCodeUnitBuilder() {
return NULL;
}
LibraryLoader* LLVMBackend::CreateLibraryLoader() {
return NULL;
}
JIT* LLVMBackend::CreateJIT(xe_memory_ref memory, FunctionTable* fn_table) {
return new LLVMJIT(memory, fn_table);
}

View File

@ -1,43 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_BACKEND_H_
#define XENIA_CPU_LLVMBE_LLVM_BACKEND_H_
#include <xenia/common.h>
#include <xenia/cpu/backend.h>
namespace xe {
namespace cpu {
namespace llvmbe {
class LLVMBackend : public Backend {
public:
LLVMBackend();
virtual ~LLVMBackend();
virtual CodeUnitBuilder* CreateCodeUnitBuilder();
virtual LibraryLinker* CreateLibraryLinker();
virtual LibraryLoader* CreateLibraryLoader();
virtual JIT* CreateJIT(xe_memory_ref memory, FunctionTable* fn_table);
protected:
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_LLVM_BACKEND_H_

View File

@ -1,264 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_code_unit_builder.h>
#include <llvm/DIBuilder.h>
#include <llvm/Linker.h>
#include <llvm/PassManager.h>
#include <llvm/DebugInfo.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Attributes.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <xenia/cpu/cpu-private.h>
#include <xenia/cpu/llvmbe/emitter_context.h>
using namespace llvm;
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::llvmbe;
using namespace xe::cpu::sdb;
LLVMCodeUnitBuilder::LLVMCodeUnitBuilder(
xe_memory_ref memory, LLVMContext* context) :
CodeUnitBuilder(memory),
context_(context) {
}
LLVMCodeUnitBuilder::~LLVMCodeUnitBuilder() {
Reset();
}
Module* LLVMCodeUnitBuilder::module() {
return module_;
}
int LLVMCodeUnitBuilder::Init(const char* module_name,
const char* module_path) {
Reset();
// Create LLVM module.
module_ = new Module(module_name, *context_);
// Create the emitter used to generate functions.
emitter_ = new EmitterContext(memory_, context_, module_);
// Setup optimization pass.
fpm_ = new FunctionPassManager(module_);
if (FLAGS_optimize_ir_functions) {
PassManagerBuilder pmb;
pmb.OptLevel = 3;
pmb.SizeLevel = 0;
pmb.Inliner = createFunctionInliningPass();
pmb.Vectorize = true;
pmb.LoopVectorize = true;
pmb.populateFunctionPassManager(*fpm_);
}
// TODO(benvanik): disable verifier in release builds?
fpm_->add(createVerifierPass());
// Setup a debug info builder.
// This is used when creating any debug info. We may want to go more
// fine grained than this, but for now it's something.
char dir[XE_MAX_PATH];
XEIGNORE(xestrcpya(dir, XECOUNT(dir), module_path));
char* slash = xestrrchra(dir, '/');
if (slash) {
*(slash + 1) = 0;
}
di_builder_ = new DIBuilder(*module_);
di_builder_->createCompileUnit(
dwarf::DW_LANG_C99, //0x8010,
StringRef(module_name),
StringRef(dir),
StringRef("xenia"),
true,
StringRef(""),
0);
cu_ = (MDNode*)di_builder_->getCU();
return 0;
}
int LLVMCodeUnitBuilder::MakeFunction(FunctionSymbol* symbol) {
return MakeFunction(symbol, NULL);
}
int LLVMCodeUnitBuilder::MakeFunction(FunctionSymbol* symbol,
Function** out_fn) {
int result_code = 0;
// Create the function (and setup args/attributes/etc).
Function* fn = emitter_->GetFunction(symbol);
// If already defined, ignore.
if (!fn->isDeclaration()) {
if (out_fn) {
*out_fn = fn;
}
return 0;
}
switch (symbol->type) {
case FunctionSymbol::User:
result_code = MakeUserFunction(symbol, fn);
break;
case FunctionSymbol::Kernel:
if (symbol->kernel_export && symbol->kernel_export->is_implemented) {
result_code = MakePresentImportFunction(symbol, fn);
} else {
result_code = MakeMissingImportFunction(symbol, fn);
}
break;
default:
XEASSERTALWAYS();
return 1;
}
if (result_code) {
return result_code;
}
// Run the optimizer on the function.
// Doing this here keeps the size of the IR small and speeds up the later
// passes.
OptimizeFunction(fn);
// Add to map for processing later.
functions_.insert(std::pair<uint32_t, Function*>(symbol->start_address, fn));
if (out_fn) {
*out_fn = fn;
}
return 0;
}
int LLVMCodeUnitBuilder::MakeUserFunction(FunctionSymbol* symbol,
Function* fn) {
// Setup emitter.
emitter_->Init(symbol, fn);
// Emit.
emitter_->GenerateBasicBlocks();
return 0;
}
int LLVMCodeUnitBuilder::MakePresentImportFunction(FunctionSymbol* symbol,
Function* fn) {
LLVMContext& context = *context_;
// Pick names.
// We have both the shim function pointer and the shim data pointer.
char shim_name[256];
xesnprintfa(shim_name, XECOUNT(shim_name),
"__shim_%s", symbol->kernel_export->name);
char shim_data_name[256];
xesnprintfa(shim_data_name, XECOUNT(shim_data_name),
"__shim_data_%s", symbol->kernel_export->name);
// Hardcoded to 64bits.
Type* intPtrTy = IntegerType::get(context, 64);
Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
// Declare shim function.
std::vector<Type*> shimArgs;
shimArgs.push_back(int8PtrTy);
shimArgs.push_back(int8PtrTy);
FunctionType* shimTy = FunctionType::get(
Type::getVoidTy(context), shimArgs, false);
Function* shim = Function::Create(
shimTy, Function::ExternalLinkage, shim_name, module_);
GlobalVariable* shim_data = new GlobalVariable(
*module_, int8PtrTy, false, GlobalValue::ExternalLinkage, 0,
shim_data_name);
shim_data->setInitializer(ConstantExpr::getIntToPtr(
ConstantInt::get(intPtrTy, 0), int8PtrTy));
BasicBlock* block = BasicBlock::Create(context, "entry", fn);
IRBuilder<> b(block);
if (FLAGS_trace_kernel_calls) {
Value* traceKernelCall = module_->getFunction("XeTraceKernelCall");
b.CreateCall4(
traceKernelCall,
fn->arg_begin(),
b.getInt64(symbol->start_address),
++fn->arg_begin(),
b.getInt64((uint64_t)symbol->kernel_export));
}
b.CreateCall2(
shim,
fn->arg_begin(),
b.CreateLoad(shim_data));
b.CreateRetVoid();
return 0;
}
int LLVMCodeUnitBuilder::MakeMissingImportFunction(FunctionSymbol* symbol,
Function* fn) {
BasicBlock* block = BasicBlock::Create(*context_, "entry", fn);
IRBuilder<> b(block);
if (FLAGS_trace_kernel_calls) {
Value* traceKernelCall = module_->getFunction("XeTraceKernelCall");
b.CreateCall4(
traceKernelCall,
fn->arg_begin(),
b.getInt64(symbol->start_address),
++fn->arg_begin(),
b.getInt64((uint64_t)symbol->kernel_export));
}
b.CreateRetVoid();
return 0;
}
void LLVMCodeUnitBuilder::OptimizeFunction(Function* fn) {
//fn->dump();
fpm_->run(*fn);
fn->dump();
}
int LLVMCodeUnitBuilder::Finalize() {
// Finalize debug info.
di_builder_->finalize();
// TODO(benvanik): run module optimizations, if enabled.
return 0;
}
void LLVMCodeUnitBuilder::Reset() {
functions_.clear();
delete emitter_;
emitter_ = NULL;
delete di_builder_;
di_builder_ = NULL;
delete fpm_;
fpm_ = NULL;
delete module_;
module_ = NULL;
}

View File

@ -1,77 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_
#define XENIA_CPU_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/code_unit_builder.h>
#include <xenia/cpu/sdb.h>
namespace llvm {
class DIBuilder;
class Function;
class FunctionPassManager;
class LLVMContext;
class Module;
class MDNode;
}
namespace xe {
namespace cpu {
namespace llvmbe {
class EmitterContext;
class LLVMCodeUnitBuilder : public CodeUnitBuilder {
public:
LLVMCodeUnitBuilder(xe_memory_ref memory, llvm::LLVMContext* context);
virtual ~LLVMCodeUnitBuilder();
llvm::Module* module();
virtual int Init(const char* module_name, const char* module_path);
virtual int MakeFunction(sdb::FunctionSymbol* symbol);
int MakeFunction(sdb::FunctionSymbol* symbol, llvm::Function** out_fn);
virtual int Finalize();
virtual void Reset();
private:
llvm::Function* CreateFunctionDeclaration(const char* name);
int MakeUserFunction(sdb::FunctionSymbol* symbol,
llvm::Function* f);
int MakePresentImportFunction(sdb::FunctionSymbol* symbol,
llvm::Function* f);
int MakeMissingImportFunction(sdb::FunctionSymbol* symbol,
llvm::Function* f);
void OptimizeFunction(llvm::Function* f);
llvm::LLVMContext* context_;
llvm::Module* module_;
llvm::FunctionPassManager* fpm_;
llvm::DIBuilder* di_builder_;
llvm::MDNode* cu_;
EmitterContext* emitter_;
std::map<uint32_t, llvm::Function*> functions_;
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_

View File

@ -1,96 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_exports.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
using namespace llvm;
using namespace xe;
using namespace xe::cpu;
void xe::cpu::llvmbe::SetupLlvmExports(
GlobalExports* global_exports,
Module* module, const DataLayout* dl, ExecutionEngine* engine) {
LLVMContext& context = module->getContext();
Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
// Control methods:
std::vector<Type*> trapArgs;
trapArgs.push_back(int8PtrTy);
trapArgs.push_back(Type::getInt32Ty(context));
FunctionType* trapTy = FunctionType::get(
Type::getVoidTy(context), trapArgs, false);
engine->addGlobalMapping(Function::Create(
trapTy, Function::ExternalLinkage, "XeTrap",
module), (void*)(global_exports->XeTrap));
std::vector<Type*> indirectBranchArgs;
indirectBranchArgs.push_back(int8PtrTy);
indirectBranchArgs.push_back(Type::getInt64Ty(context));
indirectBranchArgs.push_back(Type::getInt64Ty(context));
FunctionType* indirectBranchTy = FunctionType::get(
Type::getVoidTy(context), indirectBranchArgs, false);
engine->addGlobalMapping(Function::Create(
indirectBranchTy, Function::ExternalLinkage, "XeIndirectBranch",
module), (void*)(global_exports->XeIndirectBranch));
// Debugging methods:
std::vector<Type*> invalidInstructionArgs;
invalidInstructionArgs.push_back(int8PtrTy);
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
invalidInstructionArgs.push_back(Type::getInt32Ty(context));
FunctionType* invalidInstructionTy = FunctionType::get(
Type::getVoidTy(context), invalidInstructionArgs, false);
engine->addGlobalMapping(Function::Create(
invalidInstructionTy, Function::ExternalLinkage, "XeInvalidInstruction",
module), (void*)(global_exports->XeInvalidInstruction));
std::vector<Type*> accessViolationArgs;
accessViolationArgs.push_back(int8PtrTy);
accessViolationArgs.push_back(Type::getInt32Ty(context));
accessViolationArgs.push_back(Type::getInt64Ty(context));
FunctionType* accessViolationTy = FunctionType::get(
Type::getVoidTy(context), accessViolationArgs, false);
engine->addGlobalMapping(Function::Create(
accessViolationTy, Function::ExternalLinkage, "XeAccessViolation",
module), (void*)(global_exports->XeAccessViolation));
// Tracing methods:
std::vector<Type*> traceCallArgs;
traceCallArgs.push_back(int8PtrTy);
traceCallArgs.push_back(Type::getInt64Ty(context));
traceCallArgs.push_back(Type::getInt64Ty(context));
traceCallArgs.push_back(Type::getInt64Ty(context));
FunctionType* traceCallTy = FunctionType::get(
Type::getVoidTy(context), traceCallArgs, false);
std::vector<Type*> traceInstructionArgs;
traceInstructionArgs.push_back(int8PtrTy);
traceInstructionArgs.push_back(Type::getInt32Ty(context));
traceInstructionArgs.push_back(Type::getInt32Ty(context));
FunctionType* traceInstructionTy = FunctionType::get(
Type::getVoidTy(context), traceInstructionArgs, false);
engine->addGlobalMapping(Function::Create(
traceCallTy, Function::ExternalLinkage, "XeTraceKernelCall",
module), (void*)(global_exports->XeTraceKernelCall));
engine->addGlobalMapping(Function::Create(
traceCallTy, Function::ExternalLinkage, "XeTraceUserCall",
module), (void*)(global_exports->XeTraceUserCall));
engine->addGlobalMapping(Function::Create(
traceInstructionTy, Function::ExternalLinkage, "XeTraceInstruction",
module), (void*)(global_exports->XeTraceInstruction));
}

View File

@ -1,42 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_
#define XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/global_exports.h>
namespace llvm {
class ExecutionEngine;
class Module;
class DataLayout;
}
namespace xe {
namespace cpu {
namespace llvmbe {
void SetupLlvmExports(
GlobalExports* global_exports,
llvm::Module* module, const llvm::DataLayout* dl,
llvm::ExecutionEngine* engine);
} // llvmbe
} // cpu
} // xe
#endif // XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_

View File

@ -1,211 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_jit.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/JIT.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <xenia/cpu/exec_module.h>
#include <xenia/cpu/llvmbe/llvm_code_unit_builder.h>
#include <xenia/cpu/llvmbe/llvm_exports.h>
#include <xenia/cpu/sdb.h>
using namespace llvm;
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::llvmbe;
using namespace xe::cpu::sdb;
LLVMJIT::LLVMJIT(xe_memory_ref memory, FunctionTable* fn_table) :
JIT(memory, fn_table),
context_(NULL), engine_(NULL), module_(NULL), cub_(NULL) {
}
LLVMJIT::~LLVMJIT() {
delete cub_;
if (engine_) {
engine_->removeModule(module_);
}
delete engine_;
delete context_;
}
//namespace {
//void* LazyFunctionCreator(const std::string& name) {
// printf("lazy: %s", name.c_str());
// return NULL;
//}
//}
int LLVMJIT::Setup() {
int result_code = 1;
std::string error_message;
context_ = new LLVMContext();
// Create a shared code unit builder used while JITing.
// Since there's only one we'll need to lock when generating code.
// In the future we could try to generate new code in separate CUBs and then
// link into the main module under the lock.
cub_ = new LLVMCodeUnitBuilder(memory_, context_);
result_code = cub_->Init("jit", "");
if (result_code) {
return result_code;
}
module_ = cub_->module();
EngineBuilder builder(module_);
builder.setEngineKind(EngineKind::JIT);
builder.setErrorStr(&error_message);
builder.setOptLevel(CodeGenOpt::None);
//builder.setOptLevel(CodeGenOpt::Aggressive);
//builder.setJITMemoryManager(jmm);
//builder.setTargetOptions();
builder.setAllocateGVsWithCode(false);
//builder.setUseMCJIT(true);
engine_ = builder.create();
XEEXPECTNOTNULL(engine_);
//engine_->DisableSymbolSearching();
//engine_->InstallLazyFunctionCreator(LazyFunctionCreator);
XEEXPECTZERO(InjectGlobals());
result_code = 0;
XECLEANUP:
return result_code;
}
int LLVMJIT::InjectGlobals() {
LLVMContext& context = *context_;
const DataLayout* dl = engine_->getDataLayout();
Type* intPtrTy = dl->getIntPtrType(context);
Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
GlobalVariable* gv;
// xe_memory_base
// This is the base void* pointer to the memory space.
gv = new GlobalVariable(
*module_,
int8PtrTy,
true,
GlobalValue::ExternalLinkage,
0,
"xe_memory_base");
// Align to 64b - this makes SSE faster.
gv->setAlignment(64);
gv->setInitializer(ConstantExpr::getIntToPtr(
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
int8PtrTy));
// Setup global exports (the Xe* functions called by generated code).
GlobalExports global_exports;
cpu::GetGlobalExports(&global_exports);
SetupLlvmExports(&global_exports, module_, dl, engine_);
return 0;
}
int LLVMJIT::InitModule(ExecModule* module) {
SymbolDatabase* sdb = module->sdb();
Module* cub_module = cub_->module();
// Setup all imports (as needed).
std::vector<FunctionSymbol*> functions;
if (sdb->GetAllFunctions(functions)) {
return 1;
}
int result_code = 0;
for (std::vector<FunctionSymbol*>::iterator it = functions.begin();
it != functions.end(); ++it) {
FunctionSymbol* symbol = *it;
if (symbol->type == FunctionSymbol::Kernel) {
// Generate the function.
Function* fn = NULL;
result_code = cub_->MakeFunction(symbol, &fn);
if (result_code) {
XELOGE("Unable to generate import %s", symbol->name());
return result_code;
}
// Set global mappings for shim and data.
char shim_name[256];
xesnprintfa(shim_name, XECOUNT(shim_name),
"__shim_%s", symbol->kernel_export->name);
Function* shim = cub_module->getFunction(shim_name);
if (shim) {
engine_->updateGlobalMapping(
shim, (void*)symbol->kernel_export->function_data.shim);
}
char shim_data_name[256];
xesnprintfa(shim_data_name, XECOUNT(shim_data_name),
"__shim_data_%s", symbol->kernel_export->name);
GlobalVariable* shim_data = cub_module->getGlobalVariable(shim_data_name);
if (shim_data) {
engine_->updateGlobalMapping(
shim_data, (void*)symbol->kernel_export->function_data.shim_data);
}
}
}
return 0;
}
int LLVMJIT::UninitModule(ExecModule* module) {
return 0;
}
FunctionPointer LLVMJIT::GenerateFunction(FunctionSymbol* symbol) {
// In theory this is only called when required, so just assume we need to
// generate it.
// Lock the function for adding.
// If this fails it means the function exists and we don't need to generate
// it.
FunctionPointer ptr = fn_table_->BeginAddFunction(symbol->start_address);
if (ptr) {
return ptr;
}
printf("generating %s...\n", symbol->name());
Function* fn = NULL;
int result_code = cub_->MakeFunction(symbol, &fn);
if (result_code) {
XELOGE("Unable to generate function %s", symbol->name());
return NULL;
}
// LLVM requires all functions called to be defined at the time of
// getPointerToFunction, so this does a recursive depth-first walk
// to generate them.
for (std::vector<FunctionCall>::iterator it = symbol->outgoing_calls.begin();
it != symbol->outgoing_calls.end(); ++it) {
FunctionSymbol* target = it->target;
printf("needs dep fn %s\n", target->name());
GenerateFunction(target);
}
// Generate the machine code.
ptr = (FunctionPointer)engine_->getPointerToFunction(fn);
// Add to the function table.
fn_table_->AddFunction(symbol->start_address, ptr);
return ptr;
}

View File

@ -1,64 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_JIT_H_
#define XENIA_CPU_LLVMBE_LLVM_JIT_H_
#include <xenia/core.h>
#include <xenia/cpu/function_table.h>
#include <xenia/cpu/jit.h>
#include <xenia/cpu/ppc.h>
#include <xenia/cpu/sdb.h>
namespace llvm {
class ExecutionEngine;
class LLVMContext;
class Module;
}
namespace xe {
namespace cpu {
namespace llvmbe {
class LLVMCodeUnitBuilder;
class LLVMJIT : public JIT {
public:
LLVMJIT(xe_memory_ref memory, FunctionTable* fn_table);
virtual ~LLVMJIT();
virtual int Setup();
virtual int InitModule(ExecModule* module);
virtual int UninitModule(ExecModule* module);
virtual FunctionPointer GenerateFunction(sdb::FunctionSymbol* symbol);
protected:
int InjectGlobals();
llvm::LLVMContext* context_;
llvm::ExecutionEngine* engine_;
llvm::Module* module_;
LLVMCodeUnitBuilder* cub_;
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_LLVM_JIT_H_

View File

@ -1,24 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_library_linker.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::llvmbe;
LLVMLibraryLinker::LLVMLibraryLinker(
xe_memory_ref memory, kernel::ExportResolver* export_resolver) :
LibraryLinker(memory, export_resolver) {
}
LLVMLibraryLinker::~LLVMLibraryLinker() {
}

View File

@ -1,37 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_LIBRARY_LINKER_H_
#define XENIA_CPU_LLVMBE_LLVM_LIBRARY_LINKER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/library_linker.h>
namespace xe {
namespace cpu {
namespace llvmbe {
class LLVMLibraryLinker : public LibraryLinker {
public:
LLVMLibraryLinker(xe_memory_ref memory,
kernel::ExportResolver* export_resolver);
virtual ~LLVMLibraryLinker();
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_LLVM_LIBRARY_LINKER_H_

View File

@ -1,24 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/llvmbe/llvm_library_loader.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::llvmbe;
LLVMLibraryLoader::LLVMLibraryLoader(
xe_memory_ref memory, kernel::ExportResolver* export_resolver) :
LibraryLoader(memory, export_resolver) {
}
LLVMLibraryLoader::~LLVMLibraryLoader() {
}

View File

@ -1,37 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_CPU_LLVMBE_LLVM_LIBRARY_LOADER_H_
#define XENIA_CPU_LLVMBE_LLVM_LIBRARY_LOADER_H_
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/cpu/library_loader.h>
namespace xe {
namespace cpu {
namespace llvmbe {
class LLVMLibraryLoader : public LibraryLoader {
public:
LLVMLibraryLoader(xe_memory_ref memory,
kernel::ExportResolver* export_resolver);
virtual ~LLVMLibraryLoader();
};
} // namespace llvmbe
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_LLVMBE_LLVM_LIBRARY_LOADER_H_

View File

@ -1,24 +0,0 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'emit.h',
'emit_alu.cc',
'emit_control.cc',
'emit_fpu.cc',
'emit_memory.cc',
'emitter_context.cc',
'emitter_context.h',
'llvm_backend.cc',
'llvm_backend.h',
'llvm_code_unit_builder.cc',
'llvm_code_unit_builder.h',
'llvm_exports.cc',
'llvm_exports.h',
'llvm_jit.cc',
'llvm_jit.h',
'llvm_library_linker.cc',
'llvm_library_linker.h',
'llvm_library_loader.cc',
'llvm_library_loader.h',
],
}