diff --git a/src/alloy/frontend/ppc/ppc_emit-private.h b/src/alloy/frontend/ppc/ppc_emit-private.h index a0f7dcee5..3b095dc13 100644 --- a/src/alloy/frontend/ppc/ppc_emit-private.h +++ b/src/alloy/frontend/ppc/ppc_emit-private.h @@ -22,8 +22,8 @@ namespace ppc { #define XEREGISTERINSTR(name, opcode) \ RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name); -#define XEINSTRNOTIMPLEMENTED() -//#define XEINSTRNOTIMPLEMENTED assert_trueALWAYS +//#define XEINSTRNOTIMPLEMENTED() +#define XEINSTRNOTIMPLEMENTED() assert_always("Instruction not implemented"); //#define XEINSTRNOTIMPLEMENTED() __debugbreak() } // namespace ppc diff --git a/src/alloy/frontend/ppc/ppc_emit_control.cc b/src/alloy/frontend/ppc/ppc_emit_control.cc index 8e00b3d24..25a63f618 100644 --- a/src/alloy/frontend/ppc/ppc_emit_control.cc +++ b/src/alloy/frontend/ppc/ppc_emit_control.cc @@ -529,9 +529,42 @@ XEEMITTER(twi, 0x0C000000, D)(PPCHIRBuilder& f, InstrData& i) { // Processor control (A-26) -XEEMITTER(mfcr, 0x7C000026, X)(PPCHIRBuilder& f, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +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 + + // TODO(benvanik): optimize mfcr sequences. + // Often look something like this: + // mfocrf r11, cr6 + // not r10, r11 + // extrwi r3, r10, 1, 26 + // Could recognize this and only load the appropriate CR bit. + + assert_true(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; + } + } + Value* v; + if (count == 1) { + v = f.LoadCR(cri); + } else { + v = f.LoadZero(INT64_TYPE); + } + f.StoreGPR(i.XFX.RT, v); + return 0; } XEEMITTER(mfspr, 0x7C0002A6, 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 a1abfb415..d586c2fa5 100644 --- a/src/alloy/frontend/ppc/ppc_hir_builder.cc +++ b/src/alloy/frontend/ppc/ppc_hir_builder.cc @@ -253,8 +253,26 @@ void PPCHIRBuilder::StoreCTR(Value* value) { } Value* PPCHIRBuilder::LoadCR(uint32_t n) { - assert_always(); - return 0; + // Construct the entire word of just the bits we care about. + // This makes it easier for the optimizer to exclude things, though + // we could be even more clever and watch sequences. + Value* v = Shl(ZeroExtend(LoadContext(offsetof(PPCContext, cr0) + (4 * n) + 0, + INT8_TYPE), + INT64_TYPE), + 4 * (7 - n) + 3); + v = Or(v, Shl(ZeroExtend(LoadContext(offsetof(PPCContext, cr0) + (4 * n) + 1, + INT8_TYPE), + INT64_TYPE), + 4 * (7 - n) + 2)); + v = Or(v, Shl(ZeroExtend(LoadContext(offsetof(PPCContext, cr0) + (4 * n) + 2, + INT8_TYPE), + INT64_TYPE), + 4 * (7 - n) + 1)); + v = Or(v, Shl(ZeroExtend(LoadContext(offsetof(PPCContext, cr0) + (4 * n) + 3, + INT8_TYPE), + INT64_TYPE), + 4 * (7 - n) + 0)); + return v; } Value* PPCHIRBuilder::LoadCRField(uint32_t n, uint32_t bit) { diff --git a/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.bin b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.bin new file mode 100644 index 000000000..daedb5fa5 Binary files /dev/null and b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.bin differ diff --git a/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.dis b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.dis new file mode 100644 index 000000000..cd34b261f --- /dev/null +++ b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.dis @@ -0,0 +1,20 @@ + +/vagrant/src/alloy/frontend/ppc/test/bin//instr_vcmpxxfp.o: file format elf64-powerpc + + +Disassembly of section .text: + +0000000000100000 : + 100000: 10 64 2c c6 .long 0x10642cc6 + 100004: 7c 70 20 26 mfocrf r3,2 + 100008: 4e 80 00 20 blr + +000000000010000c : + 10000c: 10 64 2c c6 .long 0x10642cc6 + 100010: 7c 70 20 26 mfocrf r3,2 + 100014: 4e 80 00 20 blr + +0000000000100018 : + 100018: 10 64 2c c6 .long 0x10642cc6 + 10001c: 7c 70 20 26 mfocrf r3,2 + 100020: 4e 80 00 20 blr diff --git a/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.map b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.map new file mode 100644 index 000000000..2db9b1bf7 --- /dev/null +++ b/src/alloy/frontend/ppc/test/bin/instr_vcmpxxfp.map @@ -0,0 +1,3 @@ +0000000000000000 t test_vcmpxxfp_1 +000000000000000c t test_vcmpxxfp_2 +0000000000000018 t test_vcmpxxfp_3 diff --git a/src/alloy/frontend/ppc/test/instr_vcmpxxfp.s b/src/alloy/frontend/ppc/test/instr_vcmpxxfp.s new file mode 100644 index 000000000..b73bbc406 --- /dev/null +++ b/src/alloy/frontend/ppc/test/instr_vcmpxxfp.s @@ -0,0 +1,32 @@ +test_vcmpxxfp_1: + #_ REGISTER_IN v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_IN v5 [3f800000, 3f800000, 3f800000, 3f800000] + vcmpeqfp. v3, v4, v5 + mfocrf r3, 2 # cr6 + blr + #_ REGISTER_OUT v3 [ffffffff, ffffffff, ffffffff, ffffffff] + #_ REGISTER_OUT v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT v5 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT r3 0x00000080 + +test_vcmpxxfp_2: + #_ REGISTER_IN v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_IN v5 [3f800001, 3f800000, 3f800000, 3f800000] + vcmpeqfp. v3, v4, v5 + mfocrf r3, 2 # cr6 + blr + #_ REGISTER_OUT v3 [00000000, ffffffff, ffffffff, ffffffff] + #_ REGISTER_OUT v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT v5 [3f800001, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT r3 0x00000000 + +test_vcmpxxfp_3: + #_ REGISTER_IN v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_IN v5 [3f800001, 3f800001, 3f800001, 3f800001] + vcmpeqfp. v3, v4, v5 + mfocrf r3, 2 # cr6 + blr + #_ REGISTER_OUT v3 [00000000, 00000000, 00000000, 00000000] + #_ REGISTER_OUT v4 [3f800000, 3f800000, 3f800000, 3f800000] + #_ REGISTER_OUT v5 [3f800001, 3f800001, 3f800001, 3f800001] + #_ REGISTER_OUT r3 0x00000020