Cleaning up function registers and setting up CR.
This commit is contained in:
parent
9b3d96a8ae
commit
733fe85d37
|
@ -41,6 +41,9 @@ public:
|
||||||
llvm::Function* gen_fn();
|
llvm::Function* gen_fn();
|
||||||
sdb::FunctionBlock* fn_block();
|
sdb::FunctionBlock* fn_block();
|
||||||
|
|
||||||
|
void PushInsertPoint();
|
||||||
|
void PopInsertPoint();
|
||||||
|
|
||||||
void GenerateBasicBlocks();
|
void GenerateBasicBlocks();
|
||||||
llvm::BasicBlock* GetBasicBlock(uint32_t address);
|
llvm::BasicBlock* GetBasicBlock(uint32_t address);
|
||||||
llvm::BasicBlock* GetNextBasicBlock();
|
llvm::BasicBlock* GetNextBasicBlock();
|
||||||
|
@ -57,8 +60,7 @@ public:
|
||||||
|
|
||||||
llvm::Value* cia_value();
|
llvm::Value* cia_value();
|
||||||
|
|
||||||
llvm::Value* SetupRegisterLocal(uint32_t offset, llvm::Type* type,
|
llvm::Value* SetupLocal(llvm::Type* type, const char* name);
|
||||||
const char* name);
|
|
||||||
void FillRegisters();
|
void FillRegisters();
|
||||||
void SpillRegisters();
|
void SpillRegisters();
|
||||||
|
|
||||||
|
@ -69,8 +71,8 @@ public:
|
||||||
llvm::Value* ctr_value();
|
llvm::Value* ctr_value();
|
||||||
void update_ctr_value(llvm::Value* value);
|
void update_ctr_value(llvm::Value* value);
|
||||||
|
|
||||||
llvm::Value* cr_value();
|
llvm::Value* cr_value(uint32_t n);
|
||||||
void update_cr_value(llvm::Value* value);
|
void update_cr_value(uint32_t n, llvm::Value* value);
|
||||||
|
|
||||||
llvm::Value* gpr_value(uint32_t n);
|
llvm::Value* gpr_value(uint32_t n);
|
||||||
void update_gpr_value(uint32_t n, llvm::Value* value);
|
void update_gpr_value(uint32_t n, llvm::Value* value);
|
||||||
|
@ -84,6 +86,12 @@ private:
|
||||||
void GenerateSharedBlocks();
|
void GenerateSharedBlocks();
|
||||||
void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb);
|
void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb);
|
||||||
|
|
||||||
|
void setup_xer();
|
||||||
|
void setup_lr();
|
||||||
|
void setup_ctr();
|
||||||
|
void setup_cr(uint32_t n);
|
||||||
|
void setup_gpr(uint32_t n);
|
||||||
|
|
||||||
xe_memory_ref memory_;
|
xe_memory_ref memory_;
|
||||||
sdb::SymbolDatabase* sdb_;
|
sdb::SymbolDatabase* sdb_;
|
||||||
sdb::FunctionSymbol* fn_;
|
sdb::FunctionSymbol* fn_;
|
||||||
|
@ -97,6 +105,9 @@ private:
|
||||||
llvm::BasicBlock* bb_;
|
llvm::BasicBlock* bb_;
|
||||||
llvm::IRBuilder<>* builder_;
|
llvm::IRBuilder<>* builder_;
|
||||||
|
|
||||||
|
std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock::iterator> >
|
||||||
|
insert_points_;
|
||||||
|
|
||||||
std::map<uint32_t, llvm::BasicBlock*> bbs_;
|
std::map<uint32_t, llvm::BasicBlock*> bbs_;
|
||||||
|
|
||||||
// Address of the instruction being generated.
|
// Address of the instruction being generated.
|
||||||
|
@ -109,7 +120,7 @@ private:
|
||||||
llvm::Value* xer;
|
llvm::Value* xer;
|
||||||
llvm::Value* lr;
|
llvm::Value* lr;
|
||||||
llvm::Value* ctr;
|
llvm::Value* ctr;
|
||||||
llvm::Value* cr;
|
llvm::Value* cr[8];
|
||||||
llvm::Value* gpr[32];
|
llvm::Value* gpr[32];
|
||||||
} locals_;
|
} locals_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,6 +62,18 @@ static inline int32_t XEEXTS16(uint32_t v) {
|
||||||
static inline int32_t XEEXTS26(uint32_t v) {
|
static inline int32_t XEEXTS26(uint32_t v) {
|
||||||
return v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v);
|
return v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v);
|
||||||
}
|
}
|
||||||
|
static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) {
|
||||||
|
// if mstart ≤ mstop then
|
||||||
|
// mask[mstart:mstop] = ones
|
||||||
|
// mask[all other bits] = zeros
|
||||||
|
// else
|
||||||
|
// mask[mstart:63] = ones
|
||||||
|
// mask[0:mstop] = ones
|
||||||
|
// mask[all other bits] = zeros
|
||||||
|
uint64_t value =
|
||||||
|
(UINT64_MAX >> mstart) ^ ((mstop >= 63) ? 0 : UINT64_MAX >> (mstop + 1));
|
||||||
|
return mstart <= mstop ? value : ~value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -242,23 +242,25 @@ XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
|
|
||||||
void XeEmitCompareCore(FunctionGenerator& g, IRBuilder<>& b,
|
void XeEmitCompareCore(FunctionGenerator& g, IRBuilder<>& b,
|
||||||
Value* lhs, Value* rhs, uint32_t BF, bool is_signed) {
|
Value* lhs, Value* rhs, uint32_t BF, bool is_signed) {
|
||||||
|
// bit0 = RA < RB
|
||||||
|
// bit1 = RA > RB
|
||||||
|
// bit2 = RA = RB
|
||||||
|
// bit3 = XER[SO]
|
||||||
|
// Bits are reversed:
|
||||||
|
// 0123
|
||||||
|
// 3210
|
||||||
|
|
||||||
Value* is_lt = is_signed ?
|
Value* is_lt = is_signed ?
|
||||||
b.CreateICmpSLT(lhs, rhs) : b.CreateICmpULT(lhs, rhs);
|
b.CreateICmpSLT(lhs, rhs) : b.CreateICmpULT(lhs, rhs);
|
||||||
Value* is_gt = is_signed ?
|
Value* is_gt = is_signed ?
|
||||||
b.CreateICmpSGT(lhs, rhs) : b.CreateICmpUGT(lhs, rhs);
|
b.CreateICmpSGT(lhs, rhs) : b.CreateICmpUGT(lhs, rhs);
|
||||||
|
Value* cp = b.CreateSelect(is_gt, b.getInt8(1 << 2), b.getInt8(1 << 1));
|
||||||
Value* cp = b.CreateSelect(is_gt, b.getInt8(0x2), b.getInt8(0x1));
|
Value* c = b.CreateSelect(is_lt, b.getInt8(1 << 3), cp);
|
||||||
Value* c = b.CreateSelect(is_lt, b.getInt8(0x4), cp);
|
|
||||||
c = b.CreateZExt(c, b.getInt64Ty());
|
|
||||||
|
|
||||||
// TODO(benvanik): set bit 4 to XER[SO]
|
// TODO(benvanik): set bit 4 to XER[SO]
|
||||||
|
|
||||||
// Insert the 4 bits into their location in the CR.
|
// Insert the 4 bits into their location in the CR.
|
||||||
Value* cr = g.cr_value();
|
g.update_cr_value(BF, c);
|
||||||
uint32_t mask = XEBITMASK((4 + BF) * 4, (4 + BF) * 4 + 4);
|
|
||||||
cr = b.CreateAnd(cr, mask);
|
|
||||||
cr = b.CreateOr(cr, b.CreateShl(c, (4 + BF) * 4));
|
|
||||||
g.update_cr_value(cr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
|
||||||
|
@ -660,14 +662,6 @@ XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if mstart ≤ mstop then
|
|
||||||
// mask[mstart:mstop] = ones
|
|
||||||
// mask[all other bits] = zeros
|
|
||||||
// else
|
|
||||||
// mask[mstart:63] = ones
|
|
||||||
// mask[0:mstop] = ones
|
|
||||||
// mask[all other bits] = zeros
|
|
||||||
|
|
||||||
// // ROTL32(x, y) = rotl(i64.(x||x), y)
|
// // ROTL32(x, y) = rotl(i64.(x||x), y)
|
||||||
// Value* v = b.CreateZExt(b.CreateTrunc(g.gpr_value(i.M.RS)), b.getInt64Ty());
|
// Value* v = b.CreateZExt(b.CreateTrunc(g.gpr_value(i.M.RS)), b.getInt64Ty());
|
||||||
// v = b.CreateOr(b.CreateLShr(v, 32), v);
|
// v = b.CreateOr(b.CreateLShr(v, 32), v);
|
||||||
|
|
|
@ -172,7 +172,6 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
} else {
|
} else {
|
||||||
// Decrement counter.
|
// Decrement counter.
|
||||||
Value* ctr = g.ctr_value();
|
Value* ctr = g.ctr_value();
|
||||||
ctr = g.ctr_value();
|
|
||||||
ctr = b.CreateSub(ctr, b.getInt64(1));
|
ctr = b.CreateSub(ctr, b.getInt64(1));
|
||||||
|
|
||||||
// Ctr check.
|
// Ctr check.
|
||||||
|
@ -187,8 +186,8 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
if (XESELECTBITS(i.B.BO, 4, 4)) {
|
||||||
// Ignore cond.
|
// Ignore cond.
|
||||||
} else {
|
} else {
|
||||||
Value* cr = g.cr_value();
|
Value* cr = g.cr_value(i.B.BI >> 2);
|
||||||
cr = b.CreateAnd(cr, XEBITMASK(i.B.BI, i.B.BI));
|
cr = b.CreateAnd(cr, 1 << (i.B.BI >> 2));
|
||||||
if (XESELECTBITS(i.B.BO, 3, 3)) {
|
if (XESELECTBITS(i.B.BO, 3, 3)) {
|
||||||
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,8 +255,8 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
// Ignore cond.
|
// Ignore cond.
|
||||||
} else {
|
} else {
|
||||||
Value* cr = g.cr_value();
|
Value* cr = g.cr_value(i.XL.BI >> 2);
|
||||||
cr = b.CreateAnd(cr, XEBITMASK(i.XL.BI, i.XL.BI));
|
cr = b.CreateAnd(cr, 1 << (i.XL.BI >> 2));
|
||||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
||||||
} else {
|
} else {
|
||||||
|
@ -321,7 +320,6 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
} else {
|
} else {
|
||||||
// Decrement counter.
|
// Decrement counter.
|
||||||
Value* ctr = g.ctr_value();
|
Value* ctr = g.ctr_value();
|
||||||
ctr = g.ctr_value();
|
|
||||||
ctr = b.CreateSub(ctr, b.getInt64(1));
|
ctr = b.CreateSub(ctr, b.getInt64(1));
|
||||||
|
|
||||||
// Ctr check.
|
// Ctr check.
|
||||||
|
@ -336,8 +334,8 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I
|
||||||
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
if (XESELECTBITS(i.XL.BO, 4, 4)) {
|
||||||
// Ignore cond.
|
// Ignore cond.
|
||||||
} else {
|
} else {
|
||||||
Value* cr = g.cr_value();
|
Value* cr = g.cr_value(i.XL.BI >> 2);
|
||||||
cr = b.CreateAnd(cr, XEBITMASK(i.XL.BI, i.XL.BI));
|
cr = b.CreateAnd(cr, 1 << (i.XL.BI >> 2));
|
||||||
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
if (XESELECTBITS(i.XL.BO, 3, 3)) {
|
||||||
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
cond_ok = b.CreateICmpNE(cr, b.getInt64(0));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -61,7 +61,9 @@ FunctionGenerator::FunctionGenerator(
|
||||||
locals_.xer = NULL;
|
locals_.xer = NULL;
|
||||||
locals_.lr = NULL;
|
locals_.lr = NULL;
|
||||||
locals_.ctr = NULL;
|
locals_.ctr = NULL;
|
||||||
locals_.cr = NULL;
|
for (size_t n = 0; n < XECOUNT(locals_.cr); n++) {
|
||||||
|
locals_.cr[n] = NULL;
|
||||||
|
}
|
||||||
for (size_t n = 0; n < XECOUNT(locals_.gpr); n++) {
|
for (size_t n = 0; n < XECOUNT(locals_.gpr); n++) {
|
||||||
locals_.gpr[n] = NULL;
|
locals_.gpr[n] = NULL;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +97,19 @@ FunctionBlock* FunctionGenerator::fn_block() {
|
||||||
return fn_block_;
|
return fn_block_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::PushInsertPoint() {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
insert_points_.push_back(std::pair<BasicBlock*, BasicBlock::iterator>(
|
||||||
|
b.GetInsertBlock(), b.GetInsertPoint()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::PopInsertPoint() {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
std::pair<BasicBlock*, BasicBlock::iterator> back = insert_points_.back();
|
||||||
|
b.SetInsertPoint(back.first, back.second);
|
||||||
|
insert_points_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
void FunctionGenerator::GenerateBasicBlocks() {
|
void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
// Always add an entry block.
|
// Always add an entry block.
|
||||||
BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_);
|
BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_);
|
||||||
|
@ -132,10 +147,6 @@ void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
bbs_.insert(std::pair<uint32_t, BasicBlock*>(block->start_address, bb));
|
bbs_.insert(std::pair<uint32_t, BasicBlock*>(block->start_address, bb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry always jumps to the first bb.
|
|
||||||
builder_->SetInsertPoint(entry);
|
|
||||||
builder_->CreateBr(bbs_.begin()->second);
|
|
||||||
|
|
||||||
// Pass 2 fills in instructions.
|
// Pass 2 fills in instructions.
|
||||||
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
||||||
it != fn_->blocks.end(); ++it) {
|
it != fn_->blocks.end(); ++it) {
|
||||||
|
@ -153,6 +164,13 @@ void FunctionGenerator::GenerateSharedBlocks() {
|
||||||
|
|
||||||
Value* indirect_branch = gen_module_->getGlobalVariable("XeIndirectBranch");
|
Value* indirect_branch = gen_module_->getGlobalVariable("XeIndirectBranch");
|
||||||
|
|
||||||
|
// Setup initial register fill in the entry block.
|
||||||
|
// We can only do this once all the locals have been created.
|
||||||
|
b.SetInsertPoint(&gen_fn_->getEntryBlock());
|
||||||
|
FillRegisters();
|
||||||
|
// Entry always falls through to the second block.
|
||||||
|
b.CreateBr(bbs_.begin()->second);
|
||||||
|
|
||||||
// Setup the spill block in return.
|
// Setup the spill block in return.
|
||||||
b.SetInsertPoint(return_block_);
|
b.SetInsertPoint(return_block_);
|
||||||
SpillRegisters();
|
SpillRegisters();
|
||||||
|
@ -316,8 +334,7 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target,
|
||||||
IRBuilder<>& b = *builder_;
|
IRBuilder<>& b = *builder_;
|
||||||
BasicBlock* next_block = GetNextBasicBlock();
|
BasicBlock* next_block = GetNextBasicBlock();
|
||||||
|
|
||||||
BasicBlock* insert_bb = b.GetInsertBlock();
|
PushInsertPoint();
|
||||||
BasicBlock::iterator insert_bbi = b.GetInsertPoint();
|
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -325,8 +342,7 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target,
|
||||||
// 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.
|
||||||
builder_->SetInsertPoint(&gen_fn_->getEntryBlock(),
|
builder_->SetInsertPoint(&gen_fn_->getEntryBlock());
|
||||||
gen_fn_->getEntryBlock().begin());
|
|
||||||
locals_.indirection_target = b.CreateAlloca(
|
locals_.indirection_target = b.CreateAlloca(
|
||||||
b.getInt64Ty(), 0, "indirection_target");
|
b.getInt64Ty(), 0, "indirection_target");
|
||||||
locals_.indirection_cia = b.CreateAlloca(
|
locals_.indirection_cia = b.CreateAlloca(
|
||||||
|
@ -340,7 +356,7 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target,
|
||||||
*context_, "internal_indirection_block", gen_fn_, return_block_);
|
*context_, "internal_indirection_block", gen_fn_, return_block_);
|
||||||
}
|
}
|
||||||
|
|
||||||
b.SetInsertPoint(insert_bb, insert_bbi);
|
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
|
||||||
|
@ -394,42 +410,37 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target,
|
||||||
|
|
||||||
Value* FunctionGenerator::LoadStateValue(uint32_t offset, Type* type,
|
Value* FunctionGenerator::LoadStateValue(uint32_t offset, Type* type,
|
||||||
const char* name) {
|
const char* name) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
PointerType* pointerTy = PointerType::getUnqual(type);
|
PointerType* pointerTy = PointerType::getUnqual(type);
|
||||||
Function::arg_iterator args = gen_fn_->arg_begin();
|
Function::arg_iterator args = gen_fn_->arg_begin();
|
||||||
Value* statePtr = args;
|
Value* statePtr = args;
|
||||||
Value* address = builder_->CreateConstInBoundsGEP1_64(
|
Value* address = b.CreateConstInBoundsGEP1_64(statePtr, offset);
|
||||||
statePtr, offset);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
Value* ptr = builder_->CreatePointerCast(address, pointerTy);
|
return b.CreateLoad(ptr, name);
|
||||||
return builder_->CreateLoad(ptr, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type,
|
void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type,
|
||||||
Value* value) {
|
Value* value) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
PointerType* pointerTy = PointerType::getUnqual(type);
|
PointerType* pointerTy = PointerType::getUnqual(type);
|
||||||
Function::arg_iterator args = gen_fn_->arg_begin();
|
Function::arg_iterator args = gen_fn_->arg_begin();
|
||||||
Value* statePtr = args;
|
Value* statePtr = args;
|
||||||
Value* address = builder_->CreateConstInBoundsGEP1_64(
|
Value* address = b.CreateConstInBoundsGEP1_64(statePtr, offset);
|
||||||
statePtr, offset);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
Value* ptr = builder_->CreatePointerCast(address, pointerTy);
|
b.CreateStore(value, ptr);
|
||||||
builder_->CreateStore(value, ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::cia_value() {
|
Value* FunctionGenerator::cia_value() {
|
||||||
return builder_->getInt32(cia_);
|
return builder_->getInt32(cia_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::SetupRegisterLocal(uint32_t offset, llvm::Type* type,
|
Value* FunctionGenerator::SetupLocal(llvm::Type* type, const char* name) {
|
||||||
const char* name) {
|
IRBuilder<>& b = *builder_;
|
||||||
// Insert into the entry block.
|
// Insert into the entry block.
|
||||||
BasicBlock* insert_bb = builder_->GetInsertBlock();
|
PushInsertPoint();
|
||||||
BasicBlock::iterator insert_bbi = builder_->GetInsertPoint();
|
b.SetInsertPoint(&gen_fn_->getEntryBlock());
|
||||||
builder_->SetInsertPoint(&gen_fn_->getEntryBlock(),
|
Value* v = b.CreateAlloca(type, 0, name);
|
||||||
gen_fn_->getEntryBlock().begin());
|
PopInsertPoint();
|
||||||
|
|
||||||
Value* v = builder_->CreateAlloca(type, 0, name);
|
|
||||||
builder_->CreateStore(LoadStateValue(offset, type), v);
|
|
||||||
|
|
||||||
builder_->SetInsertPoint(insert_bb, insert_bbi);
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,36 +449,51 @@ void FunctionGenerator::FillRegisters() {
|
||||||
// It should be called on function entry for initial setup and after any
|
// It should be called on function entry for initial setup and after any
|
||||||
// calls that may modify the registers.
|
// calls that may modify the registers.
|
||||||
|
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
if (locals_.xer) {
|
if (locals_.xer) {
|
||||||
builder_->CreateStore(LoadStateValue(
|
b.CreateStore(LoadStateValue(
|
||||||
offsetof(xe_ppc_state_t, xer),
|
offsetof(xe_ppc_state_t, xer),
|
||||||
builder_->getInt64Ty()), locals_.xer);
|
b.getInt64Ty()), locals_.xer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals_.lr) {
|
if (locals_.lr) {
|
||||||
builder_->CreateStore(LoadStateValue(
|
b.CreateStore(LoadStateValue(
|
||||||
offsetof(xe_ppc_state_t, lr),
|
offsetof(xe_ppc_state_t, lr),
|
||||||
builder_->getInt64Ty()), locals_.lr);
|
b.getInt64Ty()), locals_.lr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals_.ctr) {
|
if (locals_.ctr) {
|
||||||
builder_->CreateStore(LoadStateValue(
|
b.CreateStore(LoadStateValue(
|
||||||
offsetof(xe_ppc_state_t, ctr),
|
offsetof(xe_ppc_state_t, ctr),
|
||||||
builder_->getInt64Ty()), locals_.ctr);
|
b.getInt64Ty()), locals_.ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals_.cr) {
|
// Fill the split CR values by extracting each one from the CR.
|
||||||
builder_->CreateStore(LoadStateValue(
|
// This could probably be done faster via an extractvalues or something.
|
||||||
offsetof(xe_ppc_state_t, cr),
|
// Perhaps we could also change it to be a vector<8*i8>.
|
||||||
builder_->getInt64Ty()), locals_.cr);
|
Value* cr = NULL;
|
||||||
|
for (size_t n = 0; n < XECOUNT(locals_.cr); n++) {
|
||||||
|
Value* cr_n = locals_.cr[n];
|
||||||
|
if (!cr_n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!cr) {
|
||||||
|
cr = LoadStateValue(
|
||||||
|
offsetof(xe_ppc_state_t, cr),
|
||||||
|
b.getInt64Ty());
|
||||||
|
}
|
||||||
|
b.CreateStore(
|
||||||
|
b.CreateTrunc(b.CreateAnd(b.CreateLShr(cr, (28 - n * 4)), 0xF),
|
||||||
|
b.getInt8Ty()), cr_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we skip zero.
|
// Note that we skip zero.
|
||||||
for (uint32_t n = 1; n < XECOUNT(locals_.gpr); n++) {
|
for (uint32_t n = 1; n < XECOUNT(locals_.gpr); n++) {
|
||||||
if (locals_.gpr[n]) {
|
if (locals_.gpr[n]) {
|
||||||
builder_->CreateStore(LoadStateValue(
|
b.CreateStore(LoadStateValue(
|
||||||
offsetof(xe_ppc_state_t, r) + 8 * n,
|
offsetof(xe_ppc_state_t, r) + 8 * n,
|
||||||
builder_->getInt64Ty()), locals_.gpr[n]);
|
b.getInt64Ty()), locals_.gpr[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,33 +504,49 @@ void FunctionGenerator::SpillRegisters() {
|
||||||
//
|
//
|
||||||
// TODO(benvanik): only flush if actually required, or selective flushes.
|
// TODO(benvanik): only flush if actually required, or selective flushes.
|
||||||
|
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
if (locals_.xer) {
|
if (locals_.xer) {
|
||||||
StoreStateValue(
|
StoreStateValue(
|
||||||
offsetof(xe_ppc_state_t, xer),
|
offsetof(xe_ppc_state_t, xer),
|
||||||
builder_->getInt64Ty(),
|
b.getInt64Ty(),
|
||||||
builder_->CreateLoad(locals_.xer));
|
b.CreateLoad(locals_.xer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals_.lr) {
|
if (locals_.lr) {
|
||||||
StoreStateValue(
|
StoreStateValue(
|
||||||
offsetof(xe_ppc_state_t, lr),
|
offsetof(xe_ppc_state_t, lr),
|
||||||
builder_->getInt64Ty(),
|
b.getInt64Ty(),
|
||||||
builder_->CreateLoad(locals_.lr));
|
b.CreateLoad(locals_.lr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals_.ctr) {
|
if (locals_.ctr) {
|
||||||
StoreStateValue(
|
StoreStateValue(
|
||||||
offsetof(xe_ppc_state_t, ctr),
|
offsetof(xe_ppc_state_t, ctr),
|
||||||
builder_->getInt64Ty(),
|
b.getInt64Ty(),
|
||||||
builder_->CreateLoad(locals_.ctr));
|
b.CreateLoad(locals_.ctr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stitch together all split CR values.
|
||||||
// TODO(benvanik): don't flush across calls?
|
// TODO(benvanik): don't flush across calls?
|
||||||
if (locals_.cr) {
|
Value* cr = NULL;
|
||||||
|
for (size_t n = 0; n < XECOUNT(locals_.cr); n++) {
|
||||||
|
Value* cr_n = locals_.cr[n];
|
||||||
|
if (!cr_n) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cr_n = b.CreateZExt(b.CreateLoad(cr_n), b.getInt64Ty());
|
||||||
|
if (!cr) {
|
||||||
|
cr = b.CreateShl(cr_n, n * 4);
|
||||||
|
} else {
|
||||||
|
cr = b.CreateOr(cr, b.CreateShl(cr_n, n * 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cr) {
|
||||||
StoreStateValue(
|
StoreStateValue(
|
||||||
offsetof(xe_ppc_state_t, cr),
|
offsetof(xe_ppc_state_t, cr),
|
||||||
builder_->getInt64Ty(),
|
b.getInt64Ty(),
|
||||||
builder_->CreateLoad(locals_.cr));
|
cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we skip zero.
|
// Note that we skip zero.
|
||||||
|
@ -513,130 +555,177 @@ void FunctionGenerator::SpillRegisters() {
|
||||||
if (v) {
|
if (v) {
|
||||||
StoreStateValue(
|
StoreStateValue(
|
||||||
offsetof(xe_ppc_state_t, r) + 8 * n,
|
offsetof(xe_ppc_state_t, r) + 8 * n,
|
||||||
builder_->getInt64Ty(),
|
b.getInt64Ty(),
|
||||||
builder_->CreateLoad(locals_.gpr[n]));
|
b.CreateLoad(locals_.gpr[n]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::xer_value() {
|
void FunctionGenerator::setup_xer() {
|
||||||
if (!locals_.xer) {
|
IRBuilder<>& b = *builder_;
|
||||||
locals_.xer = SetupRegisterLocal(
|
|
||||||
offsetof(xe_ppc_state_t, xer),
|
if (locals_.xer) {
|
||||||
builder_->getInt64Ty(),
|
return;
|
||||||
"xer");
|
|
||||||
}
|
}
|
||||||
return locals_.xer;
|
|
||||||
|
locals_.xer = SetupLocal(b.getInt64Ty(), "xer");
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::xer_value() {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
setup_xer();
|
||||||
|
|
||||||
|
return b.CreateLoad(locals_.xer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::update_xer_value(Value* value) {
|
void FunctionGenerator::update_xer_value(Value* value) {
|
||||||
// Ensure the register is local.
|
IRBuilder<>& b = *builder_;
|
||||||
xer_value();
|
|
||||||
|
setup_xer();
|
||||||
|
|
||||||
// Extend to 64bits if needed.
|
// Extend to 64bits if needed.
|
||||||
if (!value->getType()->isIntegerTy(64)) {
|
if (!value->getType()->isIntegerTy(64)) {
|
||||||
value = builder_->CreateZExt(value, builder_->getInt64Ty());
|
value = b.CreateZExt(value, b.getInt64Ty());
|
||||||
}
|
}
|
||||||
builder_->CreateStore(value, locals_.xer);
|
b.CreateStore(value, locals_.xer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::setup_lr() {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
if (locals_.lr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
locals_.lr = SetupLocal(b.getInt64Ty(), "lr");
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::lr_value() {
|
Value* FunctionGenerator::lr_value() {
|
||||||
if (!locals_.lr) {
|
IRBuilder<>& b = *builder_;
|
||||||
locals_.lr = SetupRegisterLocal(
|
|
||||||
offsetof(xe_ppc_state_t, lr),
|
setup_lr();
|
||||||
builder_->getInt64Ty(),
|
|
||||||
"lr");
|
return b.CreateLoad(locals_.lr);
|
||||||
}
|
|
||||||
return builder_->CreateLoad(locals_.lr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::update_lr_value(Value* value) {
|
void FunctionGenerator::update_lr_value(Value* value) {
|
||||||
// Ensure the register is local.
|
IRBuilder<>& b = *builder_;
|
||||||
lr_value();
|
|
||||||
|
setup_lr();
|
||||||
|
|
||||||
// Extend to 64bits if needed.
|
// Extend to 64bits if needed.
|
||||||
if (!value->getType()->isIntegerTy(64)) {
|
if (!value->getType()->isIntegerTy(64)) {
|
||||||
value = builder_->CreateZExt(value, builder_->getInt64Ty());
|
value = b.CreateZExt(value, b.getInt64Ty());
|
||||||
}
|
}
|
||||||
builder_->CreateStore(value, locals_.lr);
|
b.CreateStore(value, locals_.lr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::setup_ctr() {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
if (locals_.ctr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
locals_.ctr = SetupLocal(b.getInt64Ty(), "ctr");
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::ctr_value() {
|
Value* FunctionGenerator::ctr_value() {
|
||||||
if (!locals_.ctr) {
|
IRBuilder<>& b = *builder_;
|
||||||
locals_.ctr = SetupRegisterLocal(
|
|
||||||
offsetof(xe_ppc_state_t, ctr),
|
setup_ctr();
|
||||||
builder_->getInt64Ty(),
|
|
||||||
"ctr");
|
return b.CreateLoad(locals_.ctr);
|
||||||
}
|
|
||||||
return builder_->CreateLoad(locals_.ctr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::update_ctr_value(Value* value) {
|
void FunctionGenerator::update_ctr_value(Value* value) {
|
||||||
// Ensure the register is local.
|
IRBuilder<>& b = *builder_;
|
||||||
ctr_value();
|
|
||||||
|
setup_ctr();
|
||||||
|
|
||||||
// Extend to 64bits if needed.
|
// Extend to 64bits if needed.
|
||||||
if (!value->getType()->isIntegerTy(64)) {
|
if (!value->getType()->isIntegerTy(64)) {
|
||||||
value = builder_->CreateZExt(value, builder_->getInt64Ty());
|
value = b.CreateZExt(value, b.getInt64Ty());
|
||||||
}
|
}
|
||||||
builder_->CreateStore(value, locals_.ctr);
|
b.CreateStore(value, locals_.ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::cr_value() {
|
void FunctionGenerator::setup_cr(uint32_t n) {
|
||||||
if (!locals_.cr) {
|
IRBuilder<>& b = *builder_;
|
||||||
locals_.cr = SetupRegisterLocal(
|
|
||||||
offsetof(xe_ppc_state_t, cr),
|
XEASSERT(n >= 0 && n < 8);
|
||||||
builder_->getInt64Ty(),
|
if (locals_.cr[n]) {
|
||||||
"cr");
|
return;
|
||||||
}
|
}
|
||||||
return builder_->CreateLoad(locals_.cr);
|
|
||||||
|
char name[32];
|
||||||
|
xesnprintfa(name, XECOUNT(name), "cr_f%d", n);
|
||||||
|
locals_.cr[n] = SetupLocal(b.getInt8Ty(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::update_cr_value(Value* value) {
|
Value* FunctionGenerator::cr_value(uint32_t n) {
|
||||||
// Ensure the register is local.
|
IRBuilder<>& b = *builder_;
|
||||||
cr_value();
|
|
||||||
|
|
||||||
// Extend to 64bits if needed.
|
setup_cr(n);
|
||||||
if (!value->getType()->isIntegerTy(64)) {
|
|
||||||
value = builder_->CreateZExt(value, builder_->getInt64Ty());
|
Value* v = b.CreateLoad(locals_.cr[n]);
|
||||||
|
v = b.CreateZExt(v, b.getInt64Ty());
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_cr_value(uint32_t n, Value* value) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
setup_cr(n);
|
||||||
|
|
||||||
|
value = b.CreateTrunc(value, b.getInt8Ty());
|
||||||
|
b.CreateStore(value, locals_.cr[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::setup_gpr(uint32_t n) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
if (locals_.gpr[n]) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
builder_->CreateStore(value, locals_.cr);
|
|
||||||
|
char name[30];
|
||||||
|
xesnprintfa(name, XECOUNT(name), "gpr_r%d", n);
|
||||||
|
locals_.gpr[n] = SetupLocal(b.getInt64Ty(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::gpr_value(uint32_t n) {
|
Value* FunctionGenerator::gpr_value(uint32_t n) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
XEASSERT(n >= 0 && n < 32);
|
XEASSERT(n >= 0 && n < 32);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
// Always force zero to a constant - this should help LLVM.
|
// Always force zero to a constant - this should help LLVM.
|
||||||
return builder_->getInt64(0);
|
return b.getInt64(0);
|
||||||
}
|
}
|
||||||
if (!locals_.gpr[n]) {
|
|
||||||
char name[30];
|
setup_gpr(n);
|
||||||
xesnprintfa(name, XECOUNT(name), "gpr_r%d", n);
|
|
||||||
locals_.gpr[n] = SetupRegisterLocal(
|
return b.CreateLoad(locals_.gpr[n]);
|
||||||
offsetof(xe_ppc_state_t, r) + 8 * n,
|
|
||||||
builder_->getInt64Ty(),
|
|
||||||
name);
|
|
||||||
}
|
|
||||||
return builder_->CreateLoad(locals_.gpr[n]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) {
|
void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) {
|
||||||
XEASSERT(n >= 0 && n < 32);
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
|
XEASSERT(n >= 0 && n < 32);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
// Ignore writes to zero.
|
// Ignore writes to zero.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the register is local.
|
setup_gpr(n);
|
||||||
gpr_value(n);
|
|
||||||
|
|
||||||
// Extend to 64bits if needed.
|
// Extend to 64bits if needed.
|
||||||
if (!value->getType()->isIntegerTy(64)) {
|
if (!value->getType()->isIntegerTy(64)) {
|
||||||
value = builder_->CreateZExt(value, builder_->getInt64Ty());
|
value = b.CreateZExt(value, b.getInt64Ty());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder_->CreateStore(value, locals_.gpr[n]);
|
b.CreateStore(value, locals_.gpr[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::GetMembase() {
|
Value* FunctionGenerator::GetMembase() {
|
||||||
|
@ -649,19 +738,21 @@ Value* FunctionGenerator::memory_addr(uint32_t addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
Type* dataTy = NULL;
|
Type* dataTy = NULL;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
dataTy = builder_->getInt8Ty();
|
dataTy = b.getInt8Ty();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
dataTy = builder_->getInt16Ty();
|
dataTy = b.getInt16Ty();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
dataTy = builder_->getInt32Ty();
|
dataTy = b.getInt32Ty();
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
dataTy = builder_->getInt64Ty();
|
dataTy = b.getInt64Ty();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
XEASSERTALWAYS();
|
XEASSERTALWAYS();
|
||||||
|
@ -669,25 +760,27 @@ Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
|
||||||
}
|
}
|
||||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||||
|
|
||||||
Value* address = builder_->CreateInBoundsGEP(GetMembase(), addr);
|
Value* address = b.CreateInBoundsGEP(GetMembase(), addr);
|
||||||
Value* ptr = builder_->CreatePointerCast(address, pointerTy);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
return builder_->CreateLoad(ptr);
|
return b.CreateLoad(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
||||||
|
IRBuilder<>& b = *builder_;
|
||||||
|
|
||||||
Type* dataTy = NULL;
|
Type* dataTy = NULL;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
dataTy = builder_->getInt8Ty();
|
dataTy = b.getInt8Ty();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
dataTy = builder_->getInt16Ty();
|
dataTy = b.getInt16Ty();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
dataTy = builder_->getInt32Ty();
|
dataTy = b.getInt32Ty();
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
dataTy = builder_->getInt64Ty();
|
dataTy = b.getInt64Ty();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
XEASSERTALWAYS();
|
XEASSERTALWAYS();
|
||||||
|
@ -695,12 +788,12 @@ void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) {
|
||||||
}
|
}
|
||||||
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
PointerType* pointerTy = PointerType::getUnqual(dataTy);
|
||||||
|
|
||||||
Value* address = builder_->CreateInBoundsGEP(GetMembase(), addr);
|
Value* address = b.CreateInBoundsGEP(GetMembase(), addr);
|
||||||
Value* ptr = builder_->CreatePointerCast(address, pointerTy);
|
Value* ptr = b.CreatePointerCast(address, pointerTy);
|
||||||
|
|
||||||
// Truncate, if required.
|
// Truncate, if required.
|
||||||
if (value->getType() != dataTy) {
|
if (value->getType() != dataTy) {
|
||||||
value = builder_->CreateTrunc(value, dataTy);
|
value = b.CreateTrunc(value, dataTy);
|
||||||
}
|
}
|
||||||
builder_->CreateStore(value, ptr);
|
b.CreateStore(value, ptr);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue