Setting up locals in codegen based on disassembly results.

This commit is contained in:
Ben Vanik 2013-01-29 17:47:34 -08:00
parent d3054839b7
commit 9c86c29140
4 changed files with 103 additions and 104 deletions

View File

@ -93,12 +93,7 @@ private:
void GenerateSharedBlocks();
void PrepareBasicBlock(sdb::FunctionBlock* block);
void GenerateBasicBlock(sdb::FunctionBlock* block);
void setup_xer();
void setup_lr();
void setup_ctr();
void setup_cr(uint32_t n);
void setup_gpr(uint32_t n);
void SetupLocals();
xe_memory_ref memory_;
sdb::SymbolDatabase* sdb_;

View File

@ -311,7 +311,9 @@ XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, I
g.update_gpr_value(i.XO.RT, v);
// If we are OE=1 we need to clear the overflow bit.
g.update_xer_with_overflow(b.getInt1(0));
if (i.XO.OE) {
g.update_xer_with_overflow(b.getInt1(0));
}
if (i.XO.Rc) {
// With cr0 update.
@ -1018,10 +1020,10 @@ XEDISASMR(ori, 0x60000000, D )(InstrData& i, InstrDisasm& d) {
d.Init("no-op", "OR Immediate", 0);
} else {
d.Init("ori", "OR Immediate", 0);
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
d.AddUImmOperand(i.D.DS, 2);
}
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kWrite);
d.AddRegOperand(InstrRegister::kGPR, i.D.RT, InstrRegister::kRead);
d.AddUImmOperand(i.D.DS, 2);
return d.Finish();
}
XEEMITTER(ori, 0x60000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {

View File

@ -275,6 +275,7 @@ XEDISASMR(bcctrx, 0x4C000420, XL )(InstrData& i, InstrDisasm& d) {
}
d.AddUImmOperand(i.XL.BO, 1);
d.AddUImmOperand(i.XL.BI, 1);
d.AddCTR(InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
@ -352,6 +353,7 @@ XEDISASMR(bclrx, 0x4C000020, XL )(InstrData& i, InstrDisasm& d) {
}
d.AddUImmOperand(i.XL.BO, 1);
d.AddUImmOperand(i.XL.BI, 1);
d.AddLR(InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
@ -591,6 +593,12 @@ int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i,
return 0;
}
XEDISASMR(td, 0x7C000088, X )(InstrData& i, InstrDisasm& d) {
d.Init("td", "Trap Doubleword", 0);
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
// a <- (RA)
// b <- (RB)
@ -605,6 +613,11 @@ XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, I
i.X.RT);
}
XEDISASMR(tdi, 0x08000000, D )(InstrData& i, InstrDisasm& d) {
d.Init("tdi", "Trap Doubleword Immediate", 0);
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
// a <- (RA)
// if (a < EXTS(SI)) & TO[0] then TRAP
@ -618,6 +631,12 @@ XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, IRBuilder<>& b, I
i.D.RT);
}
XEDISASMR(tw, 0x7C000008, X )(InstrData& i, InstrDisasm& d) {
d.Init("tw", "Trap Word", 0);
d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead);
d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
// a <- EXTS((RA)[32:63])
// b <- EXTS((RB)[32:63])
@ -636,6 +655,11 @@ XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, I
i.X.RT);
}
XEDISASMR(twi, 0x0C000000, D )(InstrData& i, InstrDisasm& d) {
d.Init("twi", "Trap Word Immediate", 0);
d.AddRegOperand(InstrRegister::kGPR, i.D.RA, InstrRegister::kRead);
return d.Finish();
}
XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
// a <- EXTS((RA)[32:63])
// if (a < EXTS(SI)) & TO[0] then TRAP
@ -782,10 +806,10 @@ void RegisterEmitCategoryControl() {
XEREGISTEREMITTER(crxor, 0x4C000182);
XEREGISTEREMITTER(mcrf, 0x4C000000);
XEREGISTEREMITTER(sc, 0x44000002);
XEREGISTEREMITTER(td, 0x7C000088);
XEREGISTEREMITTER(tdi, 0x08000000);
XEREGISTEREMITTER(tw, 0x7C000008);
XEREGISTEREMITTER(twi, 0x0C000000);
XEREGISTERINSTR(td, 0x7C000088);
XEREGISTERINSTR(tdi, 0x08000000);
XEREGISTERINSTR(tw, 0x7C000008);
XEREGISTERINSTR(twi, 0x0C000000);
XEREGISTEREMITTER(mfcr, 0x7C000026);
XEREGISTERINSTR(mfspr, 0x7C0002A6);
XEREGISTEREMITTER(mftb, 0x7C0002E6);

View File

@ -155,6 +155,9 @@ void FunctionGenerator::GenerateBasicBlocks() {
PrepareBasicBlock(block);
}
// Setup all local variables now that we know what we need.
SetupLocals();
// Pass 2 fills in instructions.
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
it != fn_->blocks.end(); ++it) {
@ -240,8 +243,11 @@ void FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) {
continue;
}
// We really need to know the registers modified, so die if we've been lazy
// and haven't implemented the disassemble method yet.
ppc::InstrDisasm d;
i.type->disassemble(i, d);
XEASSERTNOTNULL(i.type->disassemble);
XEASSERTZERO(i.type->disassemble(i, d));
// Accumulate access bits.
access_bits.Extend(d.access_bits);
@ -488,8 +494,43 @@ void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type,
b.CreateStore(value, ptr);
}
Value* FunctionGenerator::cia_value() {
return builder_->getInt32(cia_);
void FunctionGenerator::SetupLocals() {
IRBuilder<>& b = *builder_;
uint64_t spr_t = access_bits_.spr;
if (spr_t & 0x3) {
locals_.xer = SetupLocal(b.getInt64Ty(), "xer");
}
spr_t >>= 2;
if (spr_t & 0x3) {
locals_.lr = SetupLocal(b.getInt64Ty(), "lr");
}
spr_t >>= 2;
if (spr_t & 0x3) {
locals_.ctr = SetupLocal(b.getInt64Ty(), "ctr");
}
spr_t >>= 2;
// TODO: FPCSR
char name[32];
uint64_t cr_t = access_bits_.cr;
for (int n = 0; n < 8; n++) {
if (cr_t & 3) {
xesnprintfa(name, XECOUNT(name), "cr%d", n);
locals_.cr[n] = SetupLocal(b.getInt8Ty(), name);
}
cr_t >>= 2;
}
uint64_t gpr_t = access_bits_.gpr;
for (int n = 0; n < 32; n++) {
if (gpr_t & 3) {
xesnprintfa(name, XECOUNT(name), "r%d", n);
locals_.gpr[n] = SetupLocal(b.getInt64Ty(), name);
}
gpr_t >>= 2;
}
}
Value* FunctionGenerator::SetupLocal(llvm::Type* type, const char* name) {
@ -502,11 +543,18 @@ Value* FunctionGenerator::SetupLocal(llvm::Type* type, const char* name) {
return v;
}
Value* FunctionGenerator::cia_value() {
return builder_->getInt32(cia_);
}
void FunctionGenerator::FillRegisters() {
// This updates all of the local register values from the state memory.
// It should be called on function entry for initial setup and after any
// calls that may modify the registers.
// TODO(benvanik): use access flags to see if we need to do reads/writes.
// Though LLVM may do a better job than we can, except across calls.
IRBuilder<>& b = *builder_;
if (locals_.xer) {
@ -619,29 +667,16 @@ void FunctionGenerator::SpillRegisters() {
}
}
void FunctionGenerator::setup_xer() {
IRBuilder<>& b = *builder_;
if (locals_.xer) {
return;
}
locals_.xer = SetupLocal(b.getInt64Ty(), "xer");
}
Value* FunctionGenerator::xer_value() {
XEASSERTNOTNULL(locals_.xer);
IRBuilder<>& b = *builder_;
setup_xer();
return b.CreateLoad(locals_.xer);
}
void FunctionGenerator::update_xer_value(Value* value) {
XEASSERTNOTNULL(locals_.xer);
IRBuilder<>& b = *builder_;
setup_xer();
// Extend to 64bits if needed.
if (!value->getType()->isIntegerTy(64)) {
value = b.CreateZExt(value, b.getInt64Ty());
@ -650,10 +685,9 @@ void FunctionGenerator::update_xer_value(Value* value) {
}
void FunctionGenerator::update_xer_with_overflow(Value* value) {
XEASSERTNOTNULL(locals_.xer);
IRBuilder<>& b = *builder_;
setup_xer();
// Expects a i1 indicating overflow.
// Trust the caller that if it's larger than that it's already truncated.
if (!value->getType()->isIntegerTy(64)) {
@ -668,10 +702,9 @@ void FunctionGenerator::update_xer_with_overflow(Value* value) {
}
void FunctionGenerator::update_xer_with_carry(Value* value) {
XEASSERTNOTNULL(locals_.xer);
IRBuilder<>& b = *builder_;
setup_xer();
// Expects a i1 indicating carry.
// Trust the caller that if it's larger than that it's already truncated.
if (!value->getType()->isIntegerTy(64)) {
@ -685,10 +718,9 @@ void FunctionGenerator::update_xer_with_carry(Value* value) {
}
void FunctionGenerator::update_xer_with_overflow_and_carry(Value* value) {
XEASSERTNOTNULL(locals_.xer);
IRBuilder<>& b = *builder_;
setup_xer();
// Expects a i1 indicating overflow.
// Trust the caller that if it's larger than that it's already truncated.
if (!value->getType()->isIntegerTy(64)) {
@ -705,29 +737,16 @@ void FunctionGenerator::update_xer_with_overflow_and_carry(Value* value) {
b.CreateStore(xer, locals_.xer);
}
void FunctionGenerator::setup_lr() {
IRBuilder<>& b = *builder_;
if (locals_.lr) {
return;
}
locals_.lr = SetupLocal(b.getInt64Ty(), "lr");
}
Value* FunctionGenerator::lr_value() {
XEASSERTNOTNULL(locals_.lr);
IRBuilder<>& b = *builder_;
setup_lr();
return b.CreateLoad(locals_.lr);
}
void FunctionGenerator::update_lr_value(Value* value) {
XEASSERTNOTNULL(locals_.lr);
IRBuilder<>& b = *builder_;
setup_lr();
// Extend to 64bits if needed.
if (!value->getType()->isIntegerTy(64)) {
value = b.CreateZExt(value, b.getInt64Ty());
@ -735,29 +754,17 @@ void FunctionGenerator::update_lr_value(Value* value) {
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() {
XEASSERTNOTNULL(locals_.ctr);
IRBuilder<>& b = *builder_;
setup_ctr();
return b.CreateLoad(locals_.ctr);
}
void FunctionGenerator::update_ctr_value(Value* value) {
XEASSERTNOTNULL(locals_.ctr);
IRBuilder<>& b = *builder_;
setup_ctr();
// Extend to 64bits if needed.
if (!value->getType()->isIntegerTy(64)) {
value = b.CreateZExt(value, b.getInt64Ty());
@ -765,34 +772,21 @@ void FunctionGenerator::update_ctr_value(Value* value) {
b.CreateStore(value, locals_.ctr);
}
void FunctionGenerator::setup_cr(uint32_t n) {
IRBuilder<>& b = *builder_;
XEASSERT(n >= 0 && n < 8);
if (locals_.cr[n]) {
return;
}
char name[32];
xesnprintfa(name, XECOUNT(name), "cr_f%d", n);
locals_.cr[n] = SetupLocal(b.getInt8Ty(), name);
}
Value* FunctionGenerator::cr_value(uint32_t n) {
XEASSERT(n >= 0 && n < 8);
XEASSERTNOTNULL(locals_.cr[n]);
IRBuilder<>& b = *builder_;
setup_cr(n);
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) {
XEASSERT(n >= 0 && n < 8);
XEASSERTNOTNULL(locals_.cr[n]);
IRBuilder<>& b = *builder_;
setup_cr(n);
// Truncate to 8 bits if needed.
// TODO(benvanik): also widen?
if (!value->getType()->isIntegerTy(8)) {
@ -834,22 +828,10 @@ void FunctionGenerator::update_cr_with_cond(
update_cr_value(n, c);
}
void FunctionGenerator::setup_gpr(uint32_t n) {
IRBuilder<>& b = *builder_;
if (locals_.gpr[n]) {
return;
}
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) {
IRBuilder<>& b = *builder_;
XEASSERT(n >= 0 && n < 32);
XEASSERTNOTNULL(locals_.gpr[n]);
IRBuilder<>& b = *builder_;
// Actually r0 is writable, even though nobody should ever do that.
// Perhaps we can check usage and enable this if safe?
@ -858,15 +840,13 @@ Value* FunctionGenerator::gpr_value(uint32_t n) {
// return b.getInt64(0);
// }
setup_gpr(n);
return b.CreateLoad(locals_.gpr[n]);
}
void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) {
IRBuilder<>& b = *builder_;
XEASSERT(n >= 0 && n < 32);
XEASSERTNOTNULL(locals_.gpr[n]);
IRBuilder<>& b = *builder_;
// See above - r0 can be written.
// if (n == 0) {
@ -874,8 +854,6 @@ void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) {
// return;
// }
setup_gpr(n);
// Extend to 64bits if needed.
if (!value->getType()->isIntegerTy(64)) {
value = b.CreateZExt(value, b.getInt64Ty());