diff --git a/include/xenia/cpu/codegen/function_generator.h b/include/xenia/cpu/codegen/function_generator.h index 635f713e4..08eaeabdf 100644 --- a/include/xenia/cpu/codegen/function_generator.h +++ b/include/xenia/cpu/codegen/function_generator.h @@ -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_; diff --git a/src/cpu/codegen/emit_alu.cc b/src/cpu/codegen/emit_alu.cc index e8acedc79..deb43e4d6 100644 --- a/src/cpu/codegen/emit_alu.cc +++ b/src/cpu/codegen/emit_alu.cc @@ -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) { diff --git a/src/cpu/codegen/emit_control.cc b/src/cpu/codegen/emit_control.cc index 339045b4d..e8ba9e847 100644 --- a/src/cpu/codegen/emit_control.cc +++ b/src/cpu/codegen/emit_control.cc @@ -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); diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index 852e6f829..b550a94d7 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -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::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());