Setting up locals in codegen based on disassembly results.
This commit is contained in:
parent
d3054839b7
commit
9c86c29140
|
@ -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_;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue