Very, very basic branching. Most compares not yet implemented.
This commit is contained in:
parent
7e3268621d
commit
692f85ed4f
|
@ -24,71 +24,78 @@ namespace cpu {
|
||||||
namespace x64 {
|
namespace x64 {
|
||||||
|
|
||||||
|
|
||||||
// int XeEmitIndirectBranchTo(
|
int XeEmitIndirectBranchTo(
|
||||||
// X64Emitter& e, X86Compiler& c, const char* src, uint32_t cia,
|
X64Emitter& e, X86Compiler& c, const char* src, uint32_t cia,
|
||||||
// bool lk, uint32_t reg) {
|
bool lk, uint32_t reg) {
|
||||||
// // TODO(benvanik): run a DFA pass to see if we can detect whether this is
|
// 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
|
// 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!
|
// 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
|
// NOTE: we avoid spilling registers until we know that the target is not
|
||||||
// // a basic block within this function.
|
// a basic block within this function.
|
||||||
|
|
||||||
// jit_value_t target;
|
GpVar target;
|
||||||
// switch (reg) {
|
switch (reg) {
|
||||||
// case kXEPPCRegLR:
|
case kXEPPCRegLR:
|
||||||
// target = e.lr_value();
|
target = e.lr_value();
|
||||||
// break;
|
break;
|
||||||
// case kXEPPCRegCTR:
|
case kXEPPCRegCTR:
|
||||||
// target = e.ctr_value();
|
target = e.ctr_value();
|
||||||
// break;
|
break;
|
||||||
// default:
|
default:
|
||||||
// XEASSERTALWAYS();
|
XEASSERTALWAYS();
|
||||||
// return 1;
|
return 1;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // Dynamic test when branching to LR, which is usually used for the return.
|
// 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.
|
// 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.
|
// 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 it's not, we fall through to the full indirection logic.
|
||||||
// if (!lk && reg == kXEPPCRegLR) {
|
if (!lk && reg == kXEPPCRegLR) {
|
||||||
// // The return block will spill registers for us.
|
// The return block will spill registers for us.
|
||||||
// // TODO(benvanik): 'lr_mismatch' debug info.
|
// TODO(benvanik): 'lr_mismatch' debug info.
|
||||||
// jit_value_t lr_cmp = jit_insn_eq(f, target, jit_value_get_param(f, 1));
|
c.test(target, c.getGpArg(1));
|
||||||
// e.branch_to_return_if(lr_cmp);
|
// TODO(benvanik): evaluate hint here.
|
||||||
// }
|
c.je(e.GetReturnLabel(), kCondHintLikely);
|
||||||
|
}
|
||||||
|
|
||||||
// // Defer to the generator, which will do fancy things.
|
// Defer to the generator, which will do fancy things.
|
||||||
// bool likely_local = !lk && reg == kXEPPCRegCTR;
|
bool likely_local = !lk && reg == kXEPPCRegCTR;
|
||||||
// return e.GenerateIndirectionBranch(cia, target, lk, likely_local);
|
return e.GenerateIndirectionBranch(cia, target, lk, likely_local);
|
||||||
// }
|
}
|
||||||
|
|
||||||
int XeEmitBranchTo(
|
int XeEmitBranchTo(
|
||||||
X64Emitter& e, X86Compiler& c, const char* src, uint32_t cia,
|
X64Emitter& e, X86Compiler& c, const char* src, uint32_t cia,
|
||||||
bool lk, void* condition = NULL) {
|
bool lk, GpVar* condition = NULL) {
|
||||||
FunctionBlock* fn_block = e.fn_block();
|
FunctionBlock* fn_block = e.fn_block();
|
||||||
|
|
||||||
// Fast-path for branches to other blocks.
|
// Fast-path for branches to other blocks.
|
||||||
// Only valid when not tracing branches.
|
// Only valid when not tracing branches.
|
||||||
if (fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
if (!FLAGS_trace_branches &&
|
||||||
|
fn_block->outgoing_type == FunctionBlock::kTargetBlock) {
|
||||||
|
XEASSERT(!lk);
|
||||||
|
Label target_label = e.GetBlockLabel(fn_block->outgoing_address);
|
||||||
if (condition) {
|
if (condition) {
|
||||||
XEASSERTALWAYS();
|
// Fast test -- if condition passed then jump to target.
|
||||||
|
// TODO(benvanik): need to spill here? somehow?
|
||||||
|
c.test(*condition, *condition);
|
||||||
|
c.jnz(target_label);
|
||||||
} else {
|
} else {
|
||||||
//e.TraceBranch(cia);
|
// TODO(benvanik): need to spill here?
|
||||||
//e.SpillRegisters();
|
//e.SpillRegisters();
|
||||||
//c.jmp(e.GetBlockLabel(fn_block->outgoing_address));
|
c.jmp(target_label);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only branch of conditionals when we have one.
|
// Only branch of conditionals when we have one.
|
||||||
//jit_label_t post_jump_label = jit_label_undefined;
|
Label post_jump_label;
|
||||||
if (condition) {
|
if (condition) {
|
||||||
// TODO(benvanik): add debug info for this?
|
// TODO(benvanik): add debug info for this?
|
||||||
// char name[32];
|
post_jump_label = c.newLabel();
|
||||||
// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address);
|
c.test(*condition, *condition);
|
||||||
//jit_insn_branch_if_not(f, condition, &post_jump_label);
|
// TODO(benvanik): experiment with various hints?
|
||||||
XEASSERTALWAYS();
|
c.jz(post_jump_label, kCondHintNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
e.TraceBranch(cia);
|
e.TraceBranch(cia);
|
||||||
|
@ -97,9 +104,9 @@ int XeEmitBranchTo(
|
||||||
int result = 0;
|
int result = 0;
|
||||||
switch (fn_block->outgoing_type) {
|
switch (fn_block->outgoing_type) {
|
||||||
case FunctionBlock::kTargetBlock:
|
case FunctionBlock::kTargetBlock:
|
||||||
// Taken care of above.
|
// Often taken care of above, when not tracing branches.
|
||||||
XEASSERTALWAYS();
|
XEASSERT(!lk);
|
||||||
result = 1;
|
c.jmp(e.GetBlockLabel(fn_block->outgoing_address));
|
||||||
break;
|
break;
|
||||||
case FunctionBlock::kTargetFunction:
|
case FunctionBlock::kTargetFunction:
|
||||||
{
|
{
|
||||||
|
@ -134,18 +141,14 @@ int XeEmitBranchTo(
|
||||||
{
|
{
|
||||||
// An indirect jump.
|
// An indirect jump.
|
||||||
printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
|
printf("INDIRECT JUMP VIA LR: %.8X\n", cia);
|
||||||
XEASSERTALWAYS();
|
result = XeEmitIndirectBranchTo(e, c, src, cia, lk, kXEPPCRegLR);
|
||||||
//result = XeEmitIndirectBranchTo(e, c, src, cia, lk, kXEPPCRegLR);
|
|
||||||
c.ret();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FunctionBlock::kTargetCTR:
|
case FunctionBlock::kTargetCTR:
|
||||||
{
|
{
|
||||||
// An indirect jump.
|
// An indirect jump.
|
||||||
printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
|
printf("INDIRECT JUMP VIA CTR: %.8X\n", cia);
|
||||||
XEASSERTALWAYS();
|
result = XeEmitIndirectBranchTo(e, c, src, cia, lk, kXEPPCRegCTR);
|
||||||
//result = XeEmitIndirectBranchTo(e, c, src, cia, lk, kXEPPCRegCTR);
|
|
||||||
c.ret();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -156,8 +159,7 @@ int XeEmitBranchTo(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (condition) {
|
if (condition) {
|
||||||
XEASSERTALWAYS();
|
c.bind(post_jump_label);
|
||||||
//jit_insn_label(f, &post_jump_label);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -202,61 +204,71 @@ XEEMITTER(bcx, 0x40000000, B )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
// 01234 (docs)
|
// 01234 (docs)
|
||||||
// 43210 (real)
|
// 43210 (real)
|
||||||
|
|
||||||
// // TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
// // The docs say always, though...
|
// The docs say always, though...
|
||||||
// if (i.B.LK) {
|
if (i.B.LK) {
|
||||||
// e.update_lr_value(e.get_uint64(i.address + 4));
|
e.update_lr_value(imm(i.address + 4));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// jit_value_t ctr_ok = NULL;
|
// TODO(benvanik): optimize to just use x64 ops.
|
||||||
// if (XESELECTBITS(i.B.BO, 2, 2)) {
|
// Need to handle the case where both ctr and cond set.
|
||||||
// // Ignore ctr.
|
|
||||||
// } else {
|
|
||||||
// // Decrement counter.
|
|
||||||
// jit_value_t ctr = e.ctr_value();
|
|
||||||
// ctr = jit_insn_sub(f, ctr, e.get_int64(1));
|
|
||||||
// e.update_ctr_value(ctr);
|
|
||||||
|
|
||||||
// // Ctr check.
|
GpVar ctr_ok;
|
||||||
// if (XESELECTBITS(i.B.BO, 1, 1)) {
|
if (XESELECTBITS(i.B.BO, 2, 2)) {
|
||||||
// ctr_ok = jit_insn_eq(f, ctr, e.get_int64(0));
|
// Ignore ctr.
|
||||||
// } else {
|
} else {
|
||||||
// ctr_ok = jit_insn_ne(f, ctr, e.get_int64(0));
|
// Decrement counter.
|
||||||
// }
|
GpVar ctr(c.newGpVar());
|
||||||
// }
|
c.mov(ctr, e.ctr_value());
|
||||||
|
c.dec(ctr);
|
||||||
|
e.update_ctr_value(ctr);
|
||||||
|
|
||||||
// jit_value_t cond_ok = NULL;
|
// Ctr check.
|
||||||
// if (XESELECTBITS(i.B.BO, 4, 4)) {
|
c.test(ctr, imm(0));
|
||||||
// // Ignore cond.
|
ctr_ok = c.newGpVar();
|
||||||
// } else {
|
if (XESELECTBITS(i.B.BO, 1, 1)) {
|
||||||
// jit_value_t cr = e.cr_value(i.B.BI >> 2);
|
c.sete(ctr_ok);
|
||||||
// cr = jit_insn_and(f, cr, e.get_uint32(1 << (i.B.BI & 3)));
|
} else {
|
||||||
// if (XESELECTBITS(i.B.BO, 3, 3)) {
|
c.setne(ctr_ok);
|
||||||
// cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
}
|
||||||
// } else {
|
}
|
||||||
// cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // We do a bit of optimization here to make the llvm assembly easier to read.
|
GpVar cond_ok;
|
||||||
// jit_value_t ok = NULL;
|
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
||||||
// if (ctr_ok && cond_ok) {
|
// Ignore cond.
|
||||||
// ok = jit_insn_and(f, ctr_ok, cond_ok);
|
} else {
|
||||||
// } else if (ctr_ok) {
|
GpVar cr(c.newGpVar());
|
||||||
// ok = ctr_ok;
|
c.mov(cr, e.cr_value(i.XL.BI >> 2));
|
||||||
// } else if (cond_ok) {
|
c.and_(cr, imm(1 << (i.XL.BI & 3)));
|
||||||
// ok = cond_ok;
|
c.test(cr, imm(0));
|
||||||
// }
|
cond_ok = c.newGpVar();
|
||||||
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
|
c.setne(cond_ok);
|
||||||
|
} else {
|
||||||
|
c.sete(cond_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// uint32_t nia;
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
// if (i.B.AA) {
|
GpVar* ok = NULL;
|
||||||
// nia = XEEXTS26(i.B.BD << 2);
|
if (ctr_ok.getId() != kInvalidValue && cond_ok.getId() != kInvalidValue) {
|
||||||
// } else {
|
c.and_(ctr_ok, cond_ok);
|
||||||
// nia = i.address + XEEXTS26(i.B.BD << 2);
|
ok = &ctr_ok;
|
||||||
// }
|
} else if (ctr_ok.getId() != kInvalidValue) {
|
||||||
// if (XeEmitBranchTo(e, c, "bcx", i.address, i.B.LK, ok)) {
|
ok = &ctr_ok;
|
||||||
// return 1;
|
} else if (cond_ok.getId() != kInvalidValue) {
|
||||||
// }
|
ok = &cond_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, c, "bcx", i.address, i.B.LK, ok)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -272,34 +284,37 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
// 01234 (docs)
|
// 01234 (docs)
|
||||||
// 43210 (real)
|
// 43210 (real)
|
||||||
|
|
||||||
// // TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
// // The docs say always, though...
|
// The docs say always, though...
|
||||||
// if (i.XL.LK) {
|
if (i.XL.LK) {
|
||||||
// e.update_lr_value(e.get_uint64(i.address + 4));
|
e.update_lr_value(imm(i.address + 4));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// jit_value_t cond_ok = NULL;
|
GpVar cond_ok;
|
||||||
// if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
// // Ignore cond.
|
// Ignore cond.
|
||||||
// } else {
|
} else {
|
||||||
// jit_value_t cr = e.cr_value(i.XL.BI >> 2);
|
GpVar cr(c.newGpVar());
|
||||||
// cr = jit_insn_and(f, cr, e.get_uint64(1 << (i.XL.BI & 3)));
|
c.mov(cr, e.cr_value(i.XL.BI >> 2));
|
||||||
// if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
c.and_(cr, imm(1 << (i.XL.BI & 3)));
|
||||||
// cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
c.test(cr, imm(0));
|
||||||
// } else {
|
cond_ok = c.newGpVar();
|
||||||
// cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
// }
|
c.setne(cond_ok);
|
||||||
// }
|
} else {
|
||||||
|
c.sete(cond_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// // We do a bit of optimization here to make the llvm assembly easier to read.
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
// jit_value_t ok = NULL;
|
GpVar* ok = NULL;
|
||||||
// if (cond_ok) {
|
if (cond_ok.getId() != kInvalidValue) {
|
||||||
// ok = cond_ok;
|
ok = &cond_ok;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (XeEmitBranchTo(e, c, "bcctrx", i.address, i.XL.LK, ok)) {
|
if (XeEmitBranchTo(e, c, "bcctrx", i.address, i.XL.LK, ok)) {
|
||||||
// return 1;
|
return 1;
|
||||||
// }
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -318,54 +333,62 @@ XEEMITTER(bclrx, 0x4C000020, XL )(X64Emitter& e, X86Compiler& c, InstrDat
|
||||||
// 01234 (docs)
|
// 01234 (docs)
|
||||||
// 43210 (real)
|
// 43210 (real)
|
||||||
|
|
||||||
// // TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
// TODO(benvanik): this may be wrong and overwrite LRs when not desired!
|
||||||
// // The docs say always, though...
|
// The docs say always, though...
|
||||||
// if (i.XL.LK) {
|
if (i.XL.LK) {
|
||||||
// e.update_lr_value(e.get_uint64(i.address + 4));
|
e.update_lr_value(imm(i.address + 4));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// jit_value_t ctr_ok = NULL;
|
GpVar ctr_ok;
|
||||||
// if (XESELECTBITS(i.XL.BO, 2, 2)) {
|
if (XESELECTBITS(i.XL.BO, 2, 2)) {
|
||||||
// // Ignore ctr.
|
// Ignore ctr.
|
||||||
// } else {
|
} else {
|
||||||
// // Decrement counter.
|
// Decrement counter.
|
||||||
// jit_value_t ctr = e.ctr_value();
|
GpVar ctr(c.newGpVar());
|
||||||
// ctr = jit_insn_sub(f, ctr, e.get_int64(1));
|
c.mov(ctr, e.ctr_value());
|
||||||
|
c.dec(ctr);
|
||||||
|
e.update_ctr_value(ctr);
|
||||||
|
|
||||||
// // Ctr check.
|
// Ctr check.
|
||||||
// if (XESELECTBITS(i.XL.BO, 1, 1)) {
|
c.test(ctr, imm(0));
|
||||||
// ctr_ok = jit_insn_eq(f, ctr, e.get_int64(0));
|
ctr_ok = c.newGpVar();
|
||||||
// } else {
|
if (XESELECTBITS(i.XL.BO, 1, 1)) {
|
||||||
// ctr_ok = jit_insn_ne(f, ctr, e.get_int64(0));
|
c.sete(ctr_ok);
|
||||||
// }
|
} else {
|
||||||
// }
|
c.setne(ctr_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// jit_value_t cond_ok = NULL;
|
GpVar cond_ok;
|
||||||
// if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
// // Ignore cond.
|
// Ignore cond.
|
||||||
// } else {
|
} else {
|
||||||
// jit_value_t cr = e.cr_value(i.XL.BI >> 2);
|
GpVar cr(c.newGpVar());
|
||||||
// cr = jit_insn_and(f, cr, e.get_uint32(1 << (i.XL.BI & 3)));
|
c.mov(cr, e.cr_value(i.XL.BI >> 2));
|
||||||
// if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
c.and_(cr, imm(1 << (i.XL.BI & 3)));
|
||||||
// cond_ok = jit_insn_ne(f, cr, e.get_int64(0));
|
c.test(cr, imm(0));
|
||||||
// } else {
|
cond_ok = c.newGpVar();
|
||||||
// cond_ok = jit_insn_eq(f, cr, e.get_int64(0));
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
// }
|
c.setne(cond_ok);
|
||||||
// }
|
} else {
|
||||||
|
c.sete(cond_ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// // We do a bit of optimization here to make the llvm assembly easier to read.
|
// We do a bit of optimization here to make the llvm assembly easier to read.
|
||||||
// jit_value_t ok = NULL;
|
GpVar* ok = NULL;
|
||||||
// if (ctr_ok && cond_ok) {
|
if (ctr_ok.getId() != kInvalidValue && cond_ok.getId() != kInvalidValue) {
|
||||||
// ok = jit_insn_and(f, ctr_ok, cond_ok);
|
c.and_(ctr_ok, cond_ok);
|
||||||
// } else if (ctr_ok) {
|
ok = &ctr_ok;
|
||||||
// ok = ctr_ok;
|
} else if (ctr_ok.getId() != kInvalidValue) {
|
||||||
// } else if (cond_ok) {
|
ok = &ctr_ok;
|
||||||
// ok = cond_ok;
|
} else if (cond_ok.getId() != kInvalidValue) {
|
||||||
// }
|
ok = &cond_ok;
|
||||||
|
}
|
||||||
|
|
||||||
// if (XeEmitBranchTo(e, c, "bclrx", i.address, i.XL.LK, ok)) {
|
if (XeEmitBranchTo(e, c, "bclrx", i.address, i.XL.LK, ok)) {
|
||||||
// return 1;
|
return 1;
|
||||||
// }
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -480,35 +503,35 @@ int XeEmitTrap(X64Emitter& e, X86Compiler& c, InstrData& i,
|
||||||
// // a < b
|
// // a < b
|
||||||
// BasicBlock* bb = *(it++);
|
// BasicBlock* bb = *(it++);
|
||||||
// b.SetInsertPoint(bb);
|
// b.SetInsertPoint(bb);
|
||||||
// jit_value_t cmp = b.CreateICmpSLT(va, vb);
|
// GpVar cmp = b.CreateICmpSLT(va, vb);
|
||||||
// b.CreateCondBr(cmp, trap_bb, *it);
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
// }
|
// }
|
||||||
// if (TO & (1 << 3)) {
|
// if (TO & (1 << 3)) {
|
||||||
// // a > b
|
// // a > b
|
||||||
// BasicBlock* bb = *(it++);
|
// BasicBlock* bb = *(it++);
|
||||||
// b.SetInsertPoint(bb);
|
// b.SetInsertPoint(bb);
|
||||||
// jit_value_t cmp = b.CreateICmpSGT(va, vb);
|
// GpVar cmp = b.CreateICmpSGT(va, vb);
|
||||||
// b.CreateCondBr(cmp, trap_bb, *it);
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
// }
|
// }
|
||||||
// if (TO & (1 << 2)) {
|
// if (TO & (1 << 2)) {
|
||||||
// // a = b
|
// // a = b
|
||||||
// BasicBlock* bb = *(it++);
|
// BasicBlock* bb = *(it++);
|
||||||
// b.SetInsertPoint(bb);
|
// b.SetInsertPoint(bb);
|
||||||
// jit_value_t cmp = b.CreateICmpEQ(va, vb);
|
// GpVar cmp = b.CreateICmpEQ(va, vb);
|
||||||
// b.CreateCondBr(cmp, trap_bb, *it);
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
// }
|
// }
|
||||||
// if (TO & (1 << 1)) {
|
// if (TO & (1 << 1)) {
|
||||||
// // a <u b
|
// // a <u b
|
||||||
// BasicBlock* bb = *(it++);
|
// BasicBlock* bb = *(it++);
|
||||||
// b.SetInsertPoint(bb);
|
// b.SetInsertPoint(bb);
|
||||||
// jit_value_t cmp = b.CreateICmpULT(va, vb);
|
// GpVar cmp = b.CreateICmpULT(va, vb);
|
||||||
// b.CreateCondBr(cmp, trap_bb, *it);
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
// }
|
// }
|
||||||
// if (TO & (1 << 0)) {
|
// if (TO & (1 << 0)) {
|
||||||
// // a >u b
|
// // a >u b
|
||||||
// BasicBlock* bb = *(it++);
|
// BasicBlock* bb = *(it++);
|
||||||
// b.SetInsertPoint(bb);
|
// b.SetInsertPoint(bb);
|
||||||
// jit_value_t cmp = b.CreateICmpUGT(va, vb);
|
// GpVar cmp = b.CreateICmpUGT(va, vb);
|
||||||
// b.CreateCondBr(cmp, trap_bb, *it);
|
// b.CreateCondBr(cmp, trap_bb, *it);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
|
@ -609,23 +609,15 @@ void X64Emitter::GenerateBasicBlock(FunctionBlock* block) {
|
||||||
// TODO(benvanik): finish up BB
|
// TODO(benvanik): finish up BB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label& X64Emitter::GetReturnLabel() {
|
||||||
|
return return_block_;
|
||||||
|
}
|
||||||
|
|
||||||
Label& X64Emitter::GetBlockLabel(uint32_t address) {
|
Label& X64Emitter::GetBlockLabel(uint32_t address) {
|
||||||
std::map<uint32_t, Label>::iterator it = bbs_.find(address);
|
std::map<uint32_t, Label>::iterator it = bbs_.find(address);
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int X64Emitter::branch_to_return() {
|
|
||||||
// return jit_insn_branch(fn_, &return_block_);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int X64Emitter::branch_to_return_if(jit_value_t value) {
|
|
||||||
// return jit_insn_branch_if(fn_, value, &return_block_);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int X64Emitter::branch_to_return_if_not(jit_value_t value) {
|
|
||||||
// return jit_insn_branch_if_not(fn_, value, &return_block_);
|
|
||||||
// }
|
|
||||||
|
|
||||||
int X64Emitter::CallFunction(FunctionSymbol* target_symbol,
|
int X64Emitter::CallFunction(FunctionSymbol* target_symbol,
|
||||||
GpVar& lr, bool tail) {
|
GpVar& lr, bool tail) {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
|
@ -824,100 +816,100 @@ void X64Emitter::TraceBranch(uint32_t cia) {
|
||||||
call->setArgument(2, arg2);
|
call->setArgument(2, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// int X64Emitter::GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
|
int X64Emitter::GenerateIndirectionBranch(uint32_t cia, GpVar& target,
|
||||||
// bool lk, bool likely_local) {
|
bool lk, bool likely_local) {
|
||||||
// // This function is called by the control emitters when they know that an
|
// This function is called by the control emitters when they know that an
|
||||||
// // indirect branch is required.
|
// indirect branch is required.
|
||||||
// // It first tries to see if the branch is to an address within the function
|
// It first tries to see if the branch is to an address within the function
|
||||||
// // and, if so, uses a local switch table. If that fails because we don't know
|
// and, if so, uses a local switch table. If that fails because we don't know
|
||||||
// // the block the function is regenerated (ACK!). If the target is external
|
// the block the function is regenerated (ACK!). If the target is external
|
||||||
// // then an external call occurs.
|
// then an external call occurs.
|
||||||
|
|
||||||
// // TODO(benvanik): port indirection.
|
// TODO(benvanik): port indirection.
|
||||||
// //XEASSERTALWAYS();
|
//XEASSERTALWAYS();
|
||||||
|
|
||||||
// // BasicBlock* next_block = GetNextBasicBlock();
|
// BasicBlock* next_block = GetNextBasicBlock();
|
||||||
|
|
||||||
// // PushInsertPoint();
|
// PushInsertPoint();
|
||||||
|
|
||||||
// // // Request builds of the indirection blocks on demand.
|
// // Request builds of the indirection blocks on demand.
|
||||||
// // // We can't build here because we don't know what registers will be needed
|
// // We can't build here because we don't know what registers will be needed
|
||||||
// // // yet, so we just create the blocks and let GenerateSharedBlocks handle it
|
// // yet, so we just create the blocks and let GenerateSharedBlocks handle it
|
||||||
// // // after we are done with all user instructions.
|
// // after we are done with all user instructions.
|
||||||
// // if (!external_indirection_block_) {
|
// if (!external_indirection_block_) {
|
||||||
// // // Setup locals in the entry block.
|
// // Setup locals in the entry block.
|
||||||
// // b.SetInsertPoint(&fn_->getEntryBlock());
|
// b.SetInsertPoint(&fn_->getEntryBlock());
|
||||||
// // locals_.indirection_target = b.CreateAlloca(
|
// locals_.indirection_target = b.CreateAlloca(
|
||||||
// // jit_type_nuint, 0, "indirection_target");
|
// jit_type_nuint, 0, "indirection_target");
|
||||||
// // locals_.indirection_cia = b.CreateAlloca(
|
// locals_.indirection_cia = b.CreateAlloca(
|
||||||
// // jit_type_nuint, 0, "indirection_cia");
|
// jit_type_nuint, 0, "indirection_cia");
|
||||||
|
|
||||||
// // external_indirection_block_ = BasicBlock::Create(
|
// external_indirection_block_ = BasicBlock::Create(
|
||||||
// // *context_, "external_indirection_block", fn_, return_block_);
|
// *context_, "external_indirection_block", fn_, return_block_);
|
||||||
// // }
|
// }
|
||||||
// // if (likely_local && !internal_indirection_block_) {
|
// if (likely_local && !internal_indirection_block_) {
|
||||||
// // internal_indirection_block_ = BasicBlock::Create(
|
// internal_indirection_block_ = BasicBlock::Create(
|
||||||
// // *context_, "internal_indirection_block", fn_, return_block_);
|
// *context_, "internal_indirection_block", fn_, return_block_);
|
||||||
// // }
|
// }
|
||||||
|
|
||||||
// // PopInsertPoint();
|
// PopInsertPoint();
|
||||||
|
|
||||||
// // // Check to see if the target address is within the function.
|
// // Check to see if the target address is within the function.
|
||||||
// // // If it is jump to that basic block. If the basic block is not found it means
|
// // If it is jump to that basic block. If the basic block is not found it means
|
||||||
// // // we have a jump inside the function that wasn't identified via static
|
// // we have a jump inside the function that wasn't identified via static
|
||||||
// // // analysis. These are bad as they require function regeneration.
|
// // analysis. These are bad as they require function regeneration.
|
||||||
// // if (likely_local) {
|
// if (likely_local) {
|
||||||
// // // Note that we only support LK=0, as we are using shared tables.
|
// // Note that we only support LK=0, as we are using shared tables.
|
||||||
// // XEASSERT(!lk);
|
// XEASSERT(!lk);
|
||||||
// // b.CreateStore(target, locals_.indirection_target);
|
// b.CreateStore(target, locals_.indirection_target);
|
||||||
// // b.CreateStore(b.getInt64(cia), locals_.indirection_cia);
|
// b.CreateStore(b.getInt64(cia), locals_.indirection_cia);
|
||||||
// // jit_value_t symbol_ge_cmp = b.CreateICmpUGE(target, b.getInt64(symbol_->start_address));
|
// jit_value_t symbol_ge_cmp = b.CreateICmpUGE(target, b.getInt64(symbol_->start_address));
|
||||||
// // jit_value_t symbol_l_cmp = b.CreateICmpULT(target, b.getInt64(symbol_->end_address));
|
// jit_value_t symbol_l_cmp = b.CreateICmpULT(target, b.getInt64(symbol_->end_address));
|
||||||
// // jit_value_t symbol_target_cmp = jit_insn_and(fn_, symbol_ge_cmp, symbol_l_cmp);
|
// jit_value_t symbol_target_cmp = jit_insn_and(fn_, symbol_ge_cmp, symbol_l_cmp);
|
||||||
// // b.CreateCondBr(symbol_target_cmp,
|
// b.CreateCondBr(symbol_target_cmp,
|
||||||
// // internal_indirection_block_, external_indirection_block_);
|
// internal_indirection_block_, external_indirection_block_);
|
||||||
// // return 0;
|
// return 0;
|
||||||
// // }
|
// }
|
||||||
|
|
||||||
// // // If we are LK=0 jump to the shared indirection block. This prevents us
|
// // If we are LK=0 jump to the shared indirection block. This prevents us
|
||||||
// // // from needing to fill the registers again after the call and shares more
|
// // from needing to fill the registers again after the call and shares more
|
||||||
// // // code.
|
// // code.
|
||||||
// // if (!lk) {
|
// if (!lk) {
|
||||||
// // b.CreateStore(target, locals_.indirection_target);
|
// b.CreateStore(target, locals_.indirection_target);
|
||||||
// // b.CreateStore(b.getInt64(cia), locals_.indirection_cia);
|
// b.CreateStore(b.getInt64(cia), locals_.indirection_cia);
|
||||||
// // b.CreateBr(external_indirection_block_);
|
// b.CreateBr(external_indirection_block_);
|
||||||
// // } else {
|
// } else {
|
||||||
// // // Slowest path - spill, call the external function, and fill.
|
// // Slowest path - spill, call the external function, and fill.
|
||||||
// // // We should avoid this at all costs.
|
// // We should avoid this at all costs.
|
||||||
|
|
||||||
// // // Spill registers. We could probably share this.
|
// // Spill registers. We could probably share this.
|
||||||
// // SpillRegisters();
|
// SpillRegisters();
|
||||||
|
|
||||||
// // // Issue the full indirection branch.
|
// // Issue the full indirection branch.
|
||||||
// // jit_value_t branch_args[] = {
|
// jit_value_t branch_args[] = {
|
||||||
// // jit_value_get_param(fn_, 0),
|
// jit_value_get_param(fn_, 0),
|
||||||
// // target,
|
// target,
|
||||||
// // get_uint64(cia),
|
// get_uint64(cia),
|
||||||
// // };
|
// };
|
||||||
// // jit_insn_call_native(
|
// jit_insn_call_native(
|
||||||
// // fn_,
|
// fn_,
|
||||||
// // "XeIndirectBranch",
|
// "XeIndirectBranch",
|
||||||
// // global_exports_.XeIndirectBranch,
|
// global_exports_.XeIndirectBranch,
|
||||||
// // global_export_signature_3_,
|
// global_export_signature_3_,
|
||||||
// // branch_args, XECOUNT(branch_args),
|
// branch_args, XECOUNT(branch_args),
|
||||||
// // 0);
|
// 0);
|
||||||
|
|
||||||
// // if (next_block) {
|
// if (next_block) {
|
||||||
// // // Only refill if not a tail call.
|
// // Only refill if not a tail call.
|
||||||
// // FillRegisters();
|
// FillRegisters();
|
||||||
// // b.CreateBr(next_block);
|
// b.CreateBr(next_block);
|
||||||
// // } else {
|
// } else {
|
||||||
// // jit_insn_return(fn_, NULL);
|
// jit_insn_return(fn_, NULL);
|
||||||
// // }
|
// }
|
||||||
// // }
|
// }
|
||||||
|
|
||||||
// return 0;
|
return 0;
|
||||||
// }
|
}
|
||||||
|
|
||||||
void X64Emitter::SetupLocals() {
|
void X64Emitter::SetupLocals() {
|
||||||
X86Compiler& c = compiler_;
|
X86Compiler& c = compiler_;
|
||||||
|
|
|
@ -41,22 +41,19 @@ public:
|
||||||
sdb::FunctionSymbol* symbol();
|
sdb::FunctionSymbol* symbol();
|
||||||
sdb::FunctionBlock* fn_block();
|
sdb::FunctionBlock* fn_block();
|
||||||
|
|
||||||
|
AsmJit::Label& GetReturnLabel();
|
||||||
AsmJit::Label& GetBlockLabel(uint32_t address);
|
AsmJit::Label& GetBlockLabel(uint32_t address);
|
||||||
int CallFunction(sdb::FunctionSymbol* target_symbol, AsmJit::GpVar& lr,
|
int CallFunction(sdb::FunctionSymbol* target_symbol, AsmJit::GpVar& lr,
|
||||||
bool tail);
|
bool tail);
|
||||||
|
|
||||||
// int branch_to_return();
|
|
||||||
// int branch_to_return_if(jit_value_t value);
|
|
||||||
// int branch_to_return_if_not(jit_value_t value);
|
|
||||||
|
|
||||||
void TraceKernelCall();
|
void TraceKernelCall();
|
||||||
void TraceUserCall();
|
void TraceUserCall();
|
||||||
void TraceInstruction(ppc::InstrData& i);
|
void TraceInstruction(ppc::InstrData& i);
|
||||||
void TraceInvalidInstruction(ppc::InstrData& i);
|
void TraceInvalidInstruction(ppc::InstrData& i);
|
||||||
void TraceBranch(uint32_t cia);
|
void TraceBranch(uint32_t cia);
|
||||||
|
|
||||||
// int GenerateIndirectionBranch(uint32_t cia, jit_value_t target,
|
int GenerateIndirectionBranch(uint32_t cia, AsmJit::GpVar& target,
|
||||||
// bool lk, bool likely_local);
|
bool lk, bool likely_local);
|
||||||
|
|
||||||
void FillRegisters();
|
void FillRegisters();
|
||||||
void SpillRegisters();
|
void SpillRegisters();
|
||||||
|
|
Loading…
Reference in New Issue