-#if defined(__ppc__) || defined(__ppc64__)
-
-// Test to see if either the displacement or destination is within
-// the +/- 2^25 range needed for a PPC branch immediate instruction.
-// Shifting the high bit of the displacement (or destination)
-// left 6 bits and then 6 bits arithmetically to the right does a
-// sign extend of the 26th bit. If that result is equivalent to the
-// original value, then the displacement (or destination) will fit
-// into a simple branch. Otherwise a larger branch sequence is required.
-// ppc64: max displacement is still +/- 2^25, but intptr_t is bigger
-
-// tiny: bc*
-// small: b, ba (unconditional only)
-// 32: bctr with lis+ori only
-static BOOL ppc_tiny_displacement(intptr_t displacement)
-{
- size_t shift = sizeof(intptr_t) - 16; // ilp32=16, lp64=48
- return (((displacement << shift) >> shift) == displacement);
-}
-
-static BOOL ppc_small_displacement(intptr_t displacement)
-{
- size_t shift = sizeof(intptr_t) - 26; // ilp32=6, lp64=38
- return (((displacement << shift) >> shift) == displacement);
-}
-
-#if defined(__ppc64__)
-// Same as ppc_small_displacement, but decides whether 32 bits is big enough.
-static BOOL ppc_32bit_displacement(intptr_t displacement)
-{
- size_t shift = sizeof(intptr_t) - 32;
- return (((displacement << shift) >> shift) == displacement);
-}
-#endif
-
-/**********************************************************************
-* objc_branch_size
-* Returns the number of instructions needed
-* for a branch from entry to target.
-**********************************************************************/
-__private_extern__ size_t objc_branch_size(void *entry, void *target)
-{
- return objc_cond_branch_size(entry, target, COND_ALWAYS);
-}
-
-__private_extern__ size_t
-objc_cond_branch_size(void *entry, void *target, unsigned cond)
-{
- intptr_t destination = (intptr_t)target;
- intptr_t displacement = (intptr_t)destination - (intptr_t)entry;
-
- if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
- // fits in unconditional relative branch immediate
- return 1;
- }
- if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
- // fits in unconditional absolute branch immediate
- return 1;
- }
- if (ppc_tiny_displacement(displacement)) {
- // fits in conditional relative branch immediate
- return 1;
- }
- if (ppc_tiny_displacement(destination)) {
- // fits in conditional absolute branch immediate
- return 1;
- }
-#if defined(__ppc64__)
- if (!ppc_32bit_displacement(destination)) {
- // fits in 64-bit absolute branch through CTR
- return 7;
- }
-#endif
-
- // fits in 32-bit absolute branch through CTR
- return 4;
-}
-
-/**********************************************************************
-* objc_write_branch
-* Writes at entry a PPC branch instruction sequence that branches to target.
-* The sequence written will be objc_branch_size(entry, target) instructions.
-* Returns the number of instructions written.
-**********************************************************************/
-__private_extern__ size_t objc_write_branch(void *entry, void *target)
-{
- return objc_write_cond_branch(entry, target, COND_ALWAYS);
-}
-
-__private_extern__ size_t
-objc_write_cond_branch(void *entry, void *target, unsigned cond)
-{
- unsigned *address = (unsigned *)entry; // location to store the 32 bit PPC instructions
- intptr_t destination = (intptr_t)target; // destination as an absolute address
- intptr_t displacement = (intptr_t)destination - (intptr_t)address; // destination as a branch relative offset
-
- if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
- // use unconditional relative branch with the displacement
- address[0] = 0x48000000 | (unsigned)(displacement & 0x03fffffc); // b *+displacement
- // issued 1 instruction
- return 1;
- }
- if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
- // use unconditional absolute branch with the destination
- address[0] = 0x48000000 | (unsigned)(destination & 0x03fffffc) | 2; // ba destination (2 is the absolute flag)
- // issued 1 instruction
- return 1;
- }
-
- if (ppc_tiny_displacement(displacement)) {
- // use conditional relative branch with the displacement
- address[0] = 0x40000000 | cond | (unsigned)(displacement & 0x0000fffc); // b *+displacement
- // issued 1 instruction
- return 1;
- }
- if (ppc_tiny_displacement(destination)) {
- // use conditional absolute branch with the destination
- address[0] = 0x40000000 | cond | (unsigned)(destination & 0x0000fffc) | 2; // ba destination (2 is the absolute flag)
- // issued 1 instruction
- return 1;
- }
-
-
- // destination is large and far away.
- // Use an absolute branch via CTR.
-
-#if defined(__ppc64__)
- if (!ppc_32bit_displacement(destination)) {
- uint16_t lo = destination & 0xffff;
- uint16_t hi = (destination >> 16) & 0xffff;
- uint16_t hi2 = (destination >> 32) & 0xffff;
- uint16_t hi3 = (destination >> 48) & 0xffff;
-
- address[0] = 0x3d800000 | hi3; // lis r12, hi3
- address[1] = 0x618c0000 | hi2; // ori r12, r12, hi2
- address[2] = 0x798c07c6; // sldi r12, r12, 32
- address[3] = 0x658c0000 | hi; // oris r12, r12, hi
- address[4] = 0x618c0000 | lo; // ori r12, r12, lo
- address[5] = 0x7d8903a6; // mtctr r12
- address[6] = 0x4c000420 | cond; // bctr
- // issued 7 instructions
- return 7;
- }
-#endif
-
- {
- uint16_t lo = destination & 0xffff;
- uint16_t hi = (destination >> 16) & 0xffff;
-
- address[0] = 0x3d800000 | hi; // lis r12,hi
- address[1] = 0x618c0000 | lo; // ori r12,r12,lo
- address[2] = 0x7d8903a6; // mtctr r12
- address[3] = 0x4c000420 | cond; // bctr
- // issued 4 instructions
- return 4;
- }
-}
-
-// defined(__ppc__) || defined(__ppc64__)
-#endif
-