Very, very basic branching. Most compares not yet implemented.

This commit is contained in:
Ben Vanik 2013-05-24 18:28:52 -07:00
parent 7e3268621d
commit 692f85ed4f
3 changed files with 290 additions and 278 deletions

View File

@ -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);
// } // }

View File

@ -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_;

View File

@ -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();