diff --git a/src/alloy/frontend/ppc/ppc_emit_control.cc b/src/alloy/frontend/ppc/ppc_emit_control.cc index 40e8a8ce3..7e3c0ebff 100644 --- a/src/alloy/frontend/ppc/ppc_emit_control.cc +++ b/src/alloy/frontend/ppc/ppc_emit_control.cc @@ -533,12 +533,12 @@ XEEMITTER(mfcr, 0x7C000026, XFX)(PPCHIRBuilder& f, InstrData& i) { // mfocrf RT,FXM // RT <- undefined // count <- 0 - // do i = 0 to 7 - // if FXMi = 1 then - // n <- i - // count <- count + 1 - // if count = 1 then - // RT4un + 32:4un + 35 <- CR4un + 32 : 4un + 35 + // do i = 0 to 7 + // if FXMi = 1 then + // n <- i + // count <- count + 1 + // if count = 1 then + // RT4un + 32:4un + 35 <- CR4un + 32 : 4un + 35 // TODO(benvanik): optimize mfcr sequences. // Often look something like this: @@ -621,8 +621,36 @@ XEEMITTER(mftb, 0x7C0002E6, XFX)(PPCHIRBuilder& f, InstrData& i) { } XEEMITTER(mtcrf, 0x7C000120, XFX)(PPCHIRBuilder& f, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // mtocrf FXM,RS + // count <- 0 + // do i = 0 to 7 + // if FXMi = 1 then + // n <- i + // count <- count + 1 + // if count = 1 then + // CR4un + 32 : 4un + 35 <- RS4un + 32:4un + 35 + + Value* v = f.LoadGPR(i.XFX.RT); + if (i.XFX.spr & (1 << 9)) { + uint32_t bits = (i.XFX.spr & 0x1FF) >> 1; + int count = 0; + int cri = 0; + for (int b = 0; b <= 7; ++b) { + if (bits & (1 << b)) { + cri = 7 - b; + ++count; + } + } + if (count == 1) { + f.StoreCR(cri, v); + } else { + // Invalid; store zero to CR. + f.StoreCR(f.LoadZero(INT64_TYPE)); + } + } else { + f.StoreCR(v); + } + return 0; } XEEMITTER(mtspr, 0x7C0003A6, XFX)(PPCHIRBuilder& f, InstrData& i) { diff --git a/src/alloy/frontend/ppc/ppc_hir_builder.cc b/src/alloy/frontend/ppc/ppc_hir_builder.cc index 5a8d0cc56..ff9fefaeb 100644 --- a/src/alloy/frontend/ppc/ppc_hir_builder.cc +++ b/src/alloy/frontend/ppc/ppc_hir_builder.cc @@ -289,9 +289,25 @@ Value* PPCHIRBuilder::LoadCRField(uint32_t n, uint32_t bit) { return LoadContext(offsetof(PPCContext, cr0) + (4 * n) + bit, INT8_TYPE); } +void PPCHIRBuilder::StoreCR(Value* value) { + // All bits. This is expensive, but seems to be less used than the + // field-specific StoreCR. + for (int i = 0; i <= 7; ++i) { + StoreCR(i, value); + } +} + void PPCHIRBuilder::StoreCR(uint32_t n, Value* value) { - // TODO(benvanik): split bits out and store in values. - assert_always(); + // Pull out the bits we are interested in. + // Optimization passes will kill any unneeded stores (mostly). + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 0, + Truncate(Shr(value, 4 * (7 - n) + 3), INT8_TYPE)); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 1, + Truncate(Shr(value, 4 * (7 - n) + 2), INT8_TYPE)); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 2, + Truncate(Shr(value, 4 * (7 - n) + 1), INT8_TYPE)); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 3, + Truncate(Shr(value, 4 * (7 - n) + 0), INT8_TYPE)); } void PPCHIRBuilder::StoreCRField(uint32_t n, uint32_t bit, Value* value) { diff --git a/src/alloy/frontend/ppc/ppc_hir_builder.h b/src/alloy/frontend/ppc/ppc_hir_builder.h index 5d09f1c78..59c694ef9 100644 --- a/src/alloy/frontend/ppc/ppc_hir_builder.h +++ b/src/alloy/frontend/ppc/ppc_hir_builder.h @@ -53,6 +53,7 @@ class PPCHIRBuilder : public hir::HIRBuilder { Value* LoadCR(); Value* LoadCR(uint32_t n); Value* LoadCRField(uint32_t n, uint32_t bit); + void StoreCR(Value* value); void StoreCR(uint32_t n, Value* value); void StoreCRField(uint32_t n, uint32_t bit, Value* value); void UpdateCR(uint32_t n, Value* lhs, bool is_signed = true);