diff --git a/basis/cpu/ppc/allot/allot.factor b/basis/cpu/ppc/allot/allot.factor
deleted file mode 100644
index 3190973f26..0000000000
--- a/basis/cpu/ppc/allot/allot.factor
+++ /dev/null
@@ -1,112 +0,0 @@
-! Copyright (C) 2006, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel cpu.ppc.architecture cpu.ppc.assembler
-kernel.private namespaces math sequences generic arrays
-compiler.generator compiler.generator.registers
-compiler.generator.fixup system layouts
-cpu.architecture alien ;
-IN: cpu.ppc.allot
-
-: load-zone-ptr ( reg -- )
-    >r "nursery" f r> %load-dlsym ;
-
-: %allot ( header size -- )
-    #! Store a pointer to 'size' bytes allocated from the
-    #! nursery in r11.
-    8 align ! align the size
-    12 load-zone-ptr ! nusery -> r12
-    11 12 cell LWZ ! nursery.here -> r11
-    11 11 pick ADDI ! increment r11
-    11 12 cell STW ! r11 -> nursery.here
-    11 11 rot SUBI ! old value
-    type-number tag-fixnum 12 LI ! compute header
-    12 11 0 STW ! store header
-    ;
-
-: %store-tagged ( reg tag -- )
-    >r dup fresh-object v>operand 11 r> tag-number ORI ;
-
-M: ppc %gc
-    "end" define-label
-    12 load-zone-ptr
-    11 12 cell LWZ ! nursery.here -> r11
-    12 12 3 cells LWZ ! nursery.end -> r12
-    11 11 1024 ADDI ! add ALLOT_BUFFER_ZONE to here
-    11 0 12 CMP ! is here >= end?
-    "end" get BLE
-    0 frame-required
-    %prepare-alien-invoke
-    "minor_gc" f %alien-invoke
-    "end" resolve-label ;
-
-: %allot-float ( reg -- )
-    #! exits with tagged ptr to object in r12, untagged in r11
-    float 16 %allot
-    11 8 STFD
-    12 11 float tag-number ORI
-    f fresh-object ;
-
-M: ppc %box-float ( dst src -- )
-    [ v>operand ] bi@ %allot-float 12 MR ;
-
-: %allot-bignum ( #digits -- )
-    #! 1 cell header, 1 cell length, 1 cell sign, + digits
-    #! length is the # of digits + sign
-    bignum over 3 + cells %allot
-    1+ v>operand 12 LI ! compute the length
-    12 11 cell STW ! store the length
-    ;
-
-: %allot-bignum-signed-1 ( reg -- )
-    #! on entry, reg is a 30-bit quantity sign-extended to
-    #! 32-bits.
-    #! exits with tagged ptr to bignum in reg
-    [
-        { "end" "non-zero" "pos" "store" } [ define-label ] each
-        ! is it zero?
-        0 over v>operand 0 CMPI
-        "non-zero" get BNE
-        dup 0 >bignum %load-literal
-        "end" get B
-        ! it is non-zero
-        "non-zero" resolve-label
-        1 %allot-bignum
-        ! is the fixnum negative?
-        0 over v>operand 0 CMPI
-        "pos" get BGE
-        1 12 LI
-        ! store negative sign
-        12 11 2 cells STW
-        ! negate fixnum
-        dup v>operand dup -1 MULI
-        "store" get B
-        "pos" resolve-label
-        0 12 LI
-        ! store positive sign
-        12 11 2 cells STW
-        "store" resolve-label
-        ! store the number
-        dup v>operand 11 3 cells STW
-        ! tag the bignum, store it in reg
-        bignum %store-tagged
-        "end" resolve-label
-    ] with-scope ;
-
-M: ppc %box-alien ( dst src -- )
-    { "end" "f" } [ define-label ] each
-    0 over v>operand 0 CMPI
-    "f" get BEQ
-    alien 4 cells %allot
-    ! Store offset
-    v>operand 11 3 cells STW
-    f v>operand 12 LI
-    ! Store expired slot
-    12 11 1 cells STW
-    ! Store underlying-alien slot
-    12 11 2 cells STW
-    ! Store tagged ptr in reg
-    dup object %store-tagged
-    "end" get B
-    "f" resolve-label
-    f v>operand swap v>operand LI
-    "end" resolve-label ;
diff --git a/basis/cpu/ppc/allot/authors.txt b/basis/cpu/ppc/allot/authors.txt
deleted file mode 100644
index 1901f27a24..0000000000
--- a/basis/cpu/ppc/allot/authors.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slava Pestov
diff --git a/basis/cpu/ppc/allot/summary.txt b/basis/cpu/ppc/allot/summary.txt
deleted file mode 100644
index 3c4941ea1d..0000000000
--- a/basis/cpu/ppc/allot/summary.txt
+++ /dev/null
@@ -1 +0,0 @@
-PowerPC inline memory allocation
diff --git a/basis/cpu/ppc/allot/tags.txt b/basis/cpu/ppc/allot/tags.txt
deleted file mode 100644
index 6bf68304bb..0000000000
--- a/basis/cpu/ppc/allot/tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-unportable
diff --git a/basis/cpu/ppc/architecture/architecture.factor b/basis/cpu/ppc/architecture/architecture.factor
deleted file mode 100644
index f19b71f3e4..0000000000
--- a/basis/cpu/ppc/architecture/architecture.factor
+++ /dev/null
@@ -1,331 +0,0 @@
-! Copyright (C) 2005, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien.c-types cpu.ppc.assembler
-cpu.architecture generic kernel kernel.private math memory
-namespaces sequences words assocs compiler.generator
-compiler.generator.registers compiler.generator.fixup system
-layouts classes words.private alien combinators
-compiler.constants math.order make ;
-IN: cpu.ppc.architecture
-
-! PowerPC register assignments
-! r3-r10, r16-r31: integer vregs
-! f0-f13: float vregs
-! r11, r12: scratch
-! r14: data stack
-! r15: retain stack
-
-: ds-reg 14 ; inline
-: rs-reg 15 ; inline
-
-: reserved-area-size ( -- n )
-    os {
-        { linux [ 2 ] }
-        { macosx [ 6 ] }
-    } case cells ; foldable
-
-: lr-save ( -- n )
-    os {
-        { linux [ 1 ] }
-        { macosx [ 2 ] }
-    } case cells ; foldable
-
-: param@ ( n -- x ) reserved-area-size + ; inline
-
-: param-save-size ( -- n ) 8 cells ; foldable
-
-: local@ ( n -- x )
-    reserved-area-size param-save-size + + ; inline
-
-: factor-area-size ( -- n ) 2 cells ; foldable
-
-: next-save ( n -- i ) cell - ;
-
-: xt-save ( n -- i ) 2 cells - ;
-
-M: ppc stack-frame-size ( n -- i )
-    local@ factor-area-size + 4 cells align ;
-
-M: temp-reg v>operand drop 11 ;
-
-M: int-regs return-reg drop 3 ;
-M: int-regs param-regs drop { 3 4 5 6 7 8 9 10 } ;
-M: int-regs vregs
-    drop {
-        3 4 5 6 7 8 9 10
-        16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
-    } ;
-
-M: float-regs return-reg drop 1 ;
-M: float-regs param-regs 
-    drop os H{
-        { macosx { 1 2 3 4 5 6 7 8 9 10 11 12 13 } }
-        { linux { 1 2 3 4 5 6 7 8 } }
-    } at ;
-M: float-regs vregs drop { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 } ;
-
-GENERIC: loc>operand ( loc -- reg n )
-
-M: ds-loc loc>operand n>> cells neg ds-reg swap ;
-M: rs-loc loc>operand n>> cells neg rs-reg swap ;
-
-M: immediate load-literal
-    [ v>operand ] bi@ LOAD ;
-
-M: ppc load-indirect ( obj reg -- )
-    [ 0 swap LOAD32 rc-absolute-ppc-2/2 rel-literal ] keep
-    dup 0 LWZ ;
-
-M: ppc %save-word-xt ( -- )
-    0 11 LOAD32 rc-absolute-ppc-2/2 rel-this ;
-
-M: ppc %prologue ( n -- )
-    0 MFLR
-    1 1 pick neg ADDI
-    11 1 pick xt-save STW
-    dup 11 LI
-    11 1 pick next-save STW
-    0 1 rot lr-save + STW ;
-
-M: ppc %epilogue ( n -- )
-    #! At the end of each word that calls a subroutine, we store
-    #! the previous link register value in r0 by popping it off
-    #! the stack, set the link register to the contents of r0,
-    #! and jump to the link register.
-    0 1 pick lr-save + LWZ
-    1 1 rot ADDI
-    0 MTLR ;
-
-: (%call) ( reg -- ) MTLR BLRL ;
-
-: (%jump) ( reg -- ) MTCTR BCTR ;
-
-: %load-dlsym ( symbol dll register -- )
-    0 swap LOAD32 rc-absolute-ppc-2/2 rel-dlsym ;
-
-M: ppc %call ( label -- ) BL ;
-
-M: ppc %jump-label ( label -- ) B ;
-
-M: ppc %jump-f ( label -- )
-    0 "flag" operand f v>operand CMPI BEQ ;
-
-M: ppc %dispatch ( -- )
-    [
-        %epilogue-later
-        0 11 LOAD32 rc-absolute-ppc-2/2 rel-here
-        "offset" operand "n" operand 1 SRAWI
-        11 11 "offset" operand ADD
-        11 dup 6 cells LWZ
-        11 (%jump)
-    ] H{
-        { +input+ { { f "n" } } }
-        { +scratch+ { { f "offset" } } }
-    } with-template ;
-
-M: ppc %dispatch-label ( word -- )
-    0 , rc-absolute-cell rel-word ;
-
-M: ppc %return ( -- ) %epilogue-later BLR ;
-
-M: ppc %peek ( vreg loc -- )
-    >r v>operand r> loc>operand LWZ ;
-
-M: ppc %replace
-    >r v>operand r> loc>operand STW ;
-
-M: ppc %unbox-float ( dst src -- )
-    [ v>operand ] bi@ float-offset LFD ;
-
-M: ppc %inc-d ( n -- ) ds-reg dup rot cells ADDI ;
-
-M: ppc %inc-r ( n -- ) rs-reg dup rot cells ADDI ;
-
-M: int-regs %save-param-reg drop 1 rot local@ STW ;
-
-M: int-regs %load-param-reg drop 1 rot local@ LWZ ;
-
-GENERIC: STF ( src dst off reg-class -- )
-
-M: single-float-regs STF drop STFS ;
-
-M: double-float-regs STF drop STFD ;
-
-M: float-regs %save-param-reg >r 1 rot local@ r> STF ;
-
-GENERIC: LF ( dst src off reg-class -- )
-
-M: single-float-regs LF drop LFS ;
-
-M: double-float-regs LF drop LFD ;
-
-M: float-regs %load-param-reg >r 1 rot local@ r> LF ;
-
-M: stack-params %load-param-reg ( stack reg reg-class -- )
-    drop >r 0 1 rot local@ LWZ 0 1 r> param@ STW ;
-
-: next-param@ ( n -- x ) param@ stack-frame get total-size>> + ;
-
-M: stack-params %save-param-reg ( stack reg reg-class -- )
-    #! Funky. Read the parameter from the caller's stack frame.
-    #! This word is used in callbacks
-    drop
-    0 1 rot next-param@ LWZ
-    0 1 rot local@ STW ;
-
-M: ppc %prepare-unbox ( -- )
-    ! First parameter is top of stack
-    3 ds-reg 0 LWZ
-    ds-reg dup cell SUBI ;
-
-M: ppc %unbox ( n reg-class func -- )
-    ! Value must be in r3
-    ! Call the unboxer
-    f %alien-invoke
-    ! Store the return value on the C stack
-    over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
-
-M: ppc %unbox-long-long ( n func -- )
-    ! Value must be in r3:r4
-    ! Call the unboxer
-    f %alien-invoke
-    ! Store the return value on the C stack
-    [
-        3 1 pick local@ STW
-        4 1 rot cell + local@ STW
-    ] when* ;
-
-M: ppc %unbox-large-struct ( n c-type -- )
-    ! Value must be in r3
-    ! Compute destination address and load struct size
-    [ 4 1 rot local@ ADDI ] [ heap-size 5 LI ] bi*
-    ! Call the function
-    "to_value_struct" f %alien-invoke ;
-
-M: ppc %box ( n reg-class func -- )
-    ! If the source is a stack location, load it into freg #0.
-    ! If the source is f, then we assume the value is already in
-    ! freg #0.
-    >r
-    over [ 0 over param-reg swap %load-param-reg ] [ 2drop ] if
-    r> f %alien-invoke ;
-
-M: ppc %box-long-long ( n func -- )
-    >r [
-        3 1 pick local@ LWZ
-        4 1 rot cell + local@ LWZ
-    ] when* r> f %alien-invoke ;
-
-: struct-return@ ( n -- n )
-    [ stack-frame get params>> ] unless* local@ ;
-
-M: ppc %prepare-box-struct ( -- )
-    #! Compute target address for value struct return
-    3 1 f struct-return@ ADDI
-    3 1 0 local@ STW ;
-
-M: ppc %box-large-struct ( n c-type -- )
-    ! If n = f, then we're boxing a returned struct
-    ! Compute destination address and load struct size
-    [ 3 1 rot struct-return@ ADDI ] [ heap-size 4 LI ] bi*
-    ! Call the function
-    "box_value_struct" f %alien-invoke ;
-
-M: ppc %prepare-alien-invoke
-    #! Save Factor stack pointers in case the C code calls a
-    #! callback which does a GC, which must reliably trace
-    #! all roots.
-    "stack_chain" f 11 %load-dlsym
-    11 11 0 LWZ
-    1 11 0 STW
-    ds-reg 11 8 STW
-    rs-reg 11 12 STW ;
-
-M: ppc %alien-invoke ( symbol dll -- )
-    11 %load-dlsym 11 (%call) ;
-
-M: ppc %alien-callback ( quot -- )
-    3 load-indirect "c_to_factor" f %alien-invoke ;
-
-M: ppc %prepare-alien-indirect ( -- )
-    "unbox_alien" f %alien-invoke
-    13 3 MR ;
-
-M: ppc %alien-indirect ( -- )
-    13 (%call) ;
-
-M: ppc %callback-value ( ctype -- )
-     ! Save top of data stack
-     3 ds-reg 0 LWZ
-     3 1 0 local@ STW
-     ! Restore data/call/retain stacks
-     "unnest_stacks" f %alien-invoke
-     ! Restore top of data stack
-     3 1 0 local@ LWZ
-     ! Unbox former top of data stack to return registers
-     unbox-return ;
-
-: %untag ( src dest -- ) 0 0 31 tag-bits get - RLWINM ;
-
-: %tag-fixnum ( src dest -- ) tag-bits get SLWI ;
-
-: %untag-fixnum ( dest src -- ) tag-bits get SRAWI ;
-
-M: ppc value-structs?
-    #! On Linux/PPC, value structs are passed in the same way
-    #! as reference structs, we just have to make a copy first.
-    os linux? not ;
-
-M: ppc fp-shadows-int? ( -- ? ) os macosx? ;
-
-M: ppc small-enough? ( n -- ? ) -32768 32767 between? ;
-
-M: ppc struct-small-enough? ( size -- ? ) drop f ;
-
-M: ppc %box-small-struct
-    drop "No small structs" throw ;
-
-M: ppc %unbox-small-struct
-    drop "No small structs" throw ;
-
-! Alien intrinsics
-M: ppc %unbox-byte-array ( dst src -- )
-    [ v>operand ] bi@ byte-array-offset ADDI ;
-
-M: ppc %unbox-alien ( dst src -- )
-    [ v>operand ] bi@ alien-offset LWZ ;
-
-M: ppc %unbox-f ( dst src -- )
-    drop 0 swap v>operand LI ;
-
-M: ppc %unbox-any-c-ptr ( dst src -- )
-    { "is-byte-array" "end" "start" } [ define-label ] each
-    ! Address is computed in R12
-    0 12 LI
-    ! Load object into R11
-    11 swap v>operand MR
-    ! We come back here with displaced aliens
-    "start" resolve-label
-    ! Is the object f?
-    0 11 f v>operand CMPI
-    ! If so, done
-    "end" get BEQ
-    ! Is the object an alien?
-    0 11 header-offset LWZ
-    0 0 alien type-number tag-fixnum CMPI
-    "is-byte-array" get BNE
-    ! If so, load the offset
-    0 11 alien-offset LWZ
-    ! Add it to address being computed
-    12 12 0 ADD
-    ! Now recurse on the underlying alien
-    11 11 underlying-alien-offset LWZ
-    "start" get B
-    "is-byte-array" resolve-label
-    ! Add byte array address to address being computed
-    12 12 11 ADD
-    ! Add an offset to start of byte array's data area
-    12 12 byte-array-offset ADDI
-    "end" resolve-label
-    ! Done, store address in destination register
-    v>operand 12 MR ;
diff --git a/basis/cpu/ppc/architecture/authors.txt b/basis/cpu/ppc/architecture/authors.txt
deleted file mode 100644
index 1901f27a24..0000000000
--- a/basis/cpu/ppc/architecture/authors.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slava Pestov
diff --git a/basis/cpu/ppc/architecture/summary.txt b/basis/cpu/ppc/architecture/summary.txt
deleted file mode 100644
index 76fe694abe..0000000000
--- a/basis/cpu/ppc/architecture/summary.txt
+++ /dev/null
@@ -1 +0,0 @@
-PowerPC architecture description
diff --git a/basis/cpu/ppc/architecture/tags.txt b/basis/cpu/ppc/architecture/tags.txt
deleted file mode 100644
index 6bf68304bb..0000000000
--- a/basis/cpu/ppc/architecture/tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-unportable
diff --git a/basis/cpu/ppc/intrinsics/authors.txt b/basis/cpu/ppc/intrinsics/authors.txt
deleted file mode 100755
index 1901f27a24..0000000000
--- a/basis/cpu/ppc/intrinsics/authors.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slava Pestov
diff --git a/basis/cpu/ppc/intrinsics/intrinsics.factor b/basis/cpu/ppc/intrinsics/intrinsics.factor
deleted file mode 100644
index 634040b0d0..0000000000
--- a/basis/cpu/ppc/intrinsics/intrinsics.factor
+++ /dev/null
@@ -1,640 +0,0 @@
-! Copyright (C) 2005, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien alien.accessors alien.c-types arrays
-cpu.ppc.assembler cpu.ppc.architecture cpu.ppc.allot
-cpu.architecture kernel kernel.private math math.private
-namespaces sequences words generic quotations byte-arrays
-hashtables hashtables.private
-sequences.private sbufs vectors system layouts
-math.floats.private classes slots.private
-combinators
-compiler.constants
-compiler.intrinsics
-compiler.generator
-compiler.generator.fixup
-compiler.generator.registers ;
-IN: cpu.ppc.intrinsics
-
-: %slot-literal-known-tag ( -- out value offset )
-    "val" operand
-    "obj" operand
-    "n" get cells
-    "obj" get operand-tag - ;
-
-: %slot-literal-any-tag ( -- out value offset )
-    "obj" operand "scratch1" operand %untag
-    "val" operand "scratch1" operand "n" get cells ;
-
-: %slot-any ( -- out value offset )
-    "obj" operand "scratch1" operand %untag
-    "offset" operand "n" operand 1 SRAWI
-    "scratch1" operand "val" operand "offset" operand ;
-
-\ slot {
-    ! Slot number is literal and the tag is known
-    {
-        [ %slot-literal-known-tag LWZ ] H{
-            { +input+ { { f "obj" known-tag } { [ small-slot? ] "n" } } }
-            { +scratch+ { { f "val" } } }
-            { +output+ { "val" } }
-        }
-    }
-    ! Slot number is literal
-    {
-        [ %slot-literal-any-tag LWZ ] H{
-            { +input+ { { f "obj" } { [ small-slot? ] "n" } } }
-            { +scratch+ { { f "scratch1" } { f "val" } } }
-            { +output+ { "val" } }
-        }
-    }
-    ! Slot number in a register
-    {
-        [ %slot-any LWZX ] H{
-            { +input+ { { f "obj" } { f "n" } } }
-            { +scratch+ { { f "val" } { f "scratch1" } { f "offset" } } }
-            { +output+ { "val" } }
-        }
-    }
-} define-intrinsics
-
-: load-cards-offset ( dest -- )
-    "cards_offset" f pick %load-dlsym  dup 0 LWZ ;
-
-: load-decks-offset ( dest -- )
-    "decks_offset" f pick %load-dlsym  dup 0 LWZ ;
-
-: %write-barrier ( -- )
-    "val" get operand-immediate? "obj" get fresh-object? or [
-        card-mark "scratch1" operand LI
-
-        ! Mark the card
-        "val" operand load-cards-offset
-        "obj" operand "scratch2" operand card-bits SRWI
-        "scratch2" operand "scratch1" operand "val" operand STBX
-
-        ! Mark the card deck
-        "val" operand load-decks-offset
-        "obj" operand "scratch2" operand deck-bits SRWI
-        "scratch2" operand "scratch1" operand "val" operand STBX
-    ] unless ;
-
-\ set-slot {
-    ! Slot number is literal and tag is known
-    {
-        [ %slot-literal-known-tag STW %write-barrier ] H{
-            { +input+ { { f "val" } { f "obj" known-tag } { [ small-slot? ] "n" } } }
-            { +scratch+ { { f "scratch1" } { f "scratch2" } } }
-            { +clobber+ { "val" } }
-        }
-    }
-    ! Slot number is literal
-    {
-        [ %slot-literal-any-tag STW %write-barrier ] H{
-            { +input+ { { f "val" } { f "obj" } { [ small-slot? ] "n" } } }
-            { +scratch+ { { f "scratch1" } { f "scratch2" } } }
-            { +clobber+ { "val" } }
-        }
-    }
-    ! Slot number is in a register
-    {
-        [ %slot-any STWX %write-barrier ] H{
-            { +input+ { { f "val" } { f "obj" } { f "n" } } }
-            { +scratch+ { { f "scratch1" } { f "scratch2" } { f "offset" } } }
-            { +clobber+ { "val" } }
-        }
-    }
-} define-intrinsics
-
-: fixnum-register-op ( op -- pair )
-    [ "out" operand "y" operand "x" operand ] swap suffix H{
-        { +input+ { { f "x" } { f "y" } } }
-        { +scratch+ { { f "out" } } }
-        { +output+ { "out" } }
-    } 2array ;
-
-: fixnum-value-op ( op -- pair )
-    [ "out" operand "x" operand "y" operand ] swap suffix H{
-        { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
-        { +scratch+ { { f "out" } } }
-        { +output+ { "out" } }
-    } 2array ;
-
-: define-fixnum-op ( word imm-op reg-op -- )
-    >r fixnum-value-op r> fixnum-register-op 2array
-    define-intrinsics ;
-
-{
-    { fixnum+fast ADDI ADD }
-    { fixnum-fast SUBI SUBF }
-    { fixnum-bitand ANDI AND }
-    { fixnum-bitor ORI OR }
-    { fixnum-bitxor XORI XOR }
-} [
-    first3 define-fixnum-op
-] each
-
-\ fixnum*fast {
-    {
-        [
-            "out" operand "x" operand "y" get MULLI
-        ] H{
-            { +input+ { { f "x" } { [ small-tagged? ] "y" } } }
-            { +scratch+ { { f "out" } } }
-            { +output+ { "out" } }
-        }
-    } {
-        [
-            "out" operand "x" operand %untag-fixnum
-            "out" operand "y" operand "out" operand MULLW
-        ] H{
-            { +input+ { { f "x" } { f "y" } } }
-            { +scratch+ { { f "out" } } }
-            { +output+ { "out" } }
-        }
-    }
-} define-intrinsics
-
-: %untag-fixnums ( seq -- )
-    [ dup %untag-fixnum ] unique-operands ;
-
-\ fixnum-shift-fast {
-    {
-        [
-            "out" operand "x" operand "y" get
-            dup 0 < [ neg SRAWI ] [ swapd SLWI ] if
-            ! Mask off low bits
-            "out" operand dup %untag
-        ] H{
-            { +input+ { { f "x" } { [ ] "y" } } }
-            { +scratch+ { { f "out" } } }
-            { +output+ { "out" } }
-        }
-    }
-    {
-        [
-            { "positive" "end" } [ define-label ] each
-            "out" operand "y" operand %untag-fixnum
-            0 "y" operand 0 CMPI
-            "positive" get BGE
-            "out" operand dup NEG
-            "out" operand "x" operand "out" operand SRAW
-            "end" get B
-            "positive" resolve-label
-            "out" operand "x" operand "out" operand SLW
-            "end" resolve-label
-            ! Mask off low bits
-            "out" operand dup %untag
-        ] H{
-            { +input+ { { f "x" } { f "y" } } }
-            { +scratch+ { { f "out" } } }
-            { +output+ { "out" } }
-        }
-    }
-} define-intrinsics
-
-: generate-fixnum-mod ( -- )
-    #! PowerPC doesn't have a MOD instruction; so we compute
-    #! x-(x/y)*y. Puts the result in "s" operand.
-    "s" operand "r" operand "y" operand MULLW
-    "s" operand "s" operand "x" operand SUBF ;
-
-\ fixnum-mod [
-    ! divide x by y, store result in x
-    "r" operand "x" operand "y" operand DIVW
-    generate-fixnum-mod
-] H{
-    { +input+ { { f "x" } { f "y" } } }
-    { +scratch+ { { f "r" } { f "s" } } }
-    { +output+ { "s" } }
-} define-intrinsic
-
-\ fixnum-bitnot [
-    "x" operand dup NOT
-    "x" operand dup %untag
-] H{
-    { +input+ { { f "x" } } }
-    { +output+ { "x" } }
-} define-intrinsic
-
-: fixnum-register-jump ( op -- pair )
-    [ "x" operand 0 "y" operand CMP ] swap suffix
-    { { f "x" } { f "y" } } 2array ;
-
-: fixnum-value-jump ( op -- pair )
-    [ 0 "x" operand "y" operand CMPI ] swap suffix
-    { { f "x" } { [ small-tagged? ] "y" } } 2array ;
-
-: define-fixnum-jump ( word op -- )
-    [ fixnum-value-jump ] keep fixnum-register-jump
-    2array define-if-intrinsics ;
-
-{
-    { fixnum< BGE }
-    { fixnum<= BGT }
-    { fixnum> BLE }
-    { fixnum>= BLT }
-    { eq? BNE }
-} [
-    first2 define-fixnum-jump
-] each
-
-: overflow-check ( insn1 insn2 -- )
-    [
-        >r 0 0 LI
-        0 MTXER
-        "r" operand "y" operand "x" operand r> execute
-        >r
-        "end" define-label
-        "end" get BNO
-        { "x" "y" } %untag-fixnums
-        "r" operand "y" operand "x" operand r> execute
-        "r" get %allot-bignum-signed-1
-        "end" resolve-label
-    ] with-scope ; inline
-
-: overflow-template ( word insn1 insn2 -- )
-    [ overflow-check ] 2curry H{
-        { +input+ { { f "x" } { f "y" } } }
-        { +scratch+ { { f "r" } } }
-        { +output+ { "r" } }
-        { +clobber+ { "x" "y" } }
-    } define-intrinsic ;
-
-\ fixnum+ \ ADD \ ADDO. overflow-template
-\ fixnum- \ SUBF \ SUBFO. overflow-template
-
-: generate-fixnum/i ( -- )
-    #! This VOP is funny. If there is an overflow, it falls
-    #! through to the end, and the result is in "x" operand.
-    #! Otherwise it jumps to the "no-overflow" label and the
-    #! result is in "r" operand.
-    "end" define-label
-    "no-overflow" define-label
-    "r" operand "x" operand "y" operand DIVW
-    ! if the result is greater than the most positive fixnum,
-    ! which can only ever happen if we do
-    ! most-negative-fixnum -1 /i, then the result is a bignum.
-    most-positive-fixnum "s" operand LOAD
-    "r" operand 0 "s" operand CMP
-    "no-overflow" get BLE
-    most-negative-fixnum neg "x" operand LOAD
-    "x" get %allot-bignum-signed-1 ;
-
-\ fixnum/i [
-    generate-fixnum/i
-    "end" get B
-    "no-overflow" resolve-label
-    "r" operand "x" operand %tag-fixnum
-    "end" resolve-label
-] H{
-    { +input+ { { f "x" } { f "y" } } }
-    { +scratch+ { { f "r" } { f "s" } } }
-    { +output+ { "x" } }
-    { +clobber+ { "y" } }
-} define-intrinsic
-
-\ fixnum/mod [
-    generate-fixnum/i
-    0 "s" operand LI
-    "end" get B
-    "no-overflow" resolve-label
-    generate-fixnum-mod
-    "r" operand "x" operand %tag-fixnum
-    "end" resolve-label
-] H{
-    { +input+ { { f "x" } { f "y" } } }
-    { +scratch+ { { f "r" } { f "s" } } }
-    { +output+ { "x" "s" } }
-    { +clobber+ { "y" } }
-} define-intrinsic
-
-\ fixnum>bignum [
-    "x" operand dup %untag-fixnum
-    "x" get %allot-bignum-signed-1
-] H{
-    { +input+ { { f "x" } } }
-    { +output+ { "x" } }
-} define-intrinsic
-
-\ bignum>fixnum [
-    "nonzero" define-label
-    "positive" define-label
-    "end" define-label
-    "x" operand dup %untag
-    "y" operand "x" operand cell LWZ
-     ! if the length is 1, its just the sign and nothing else,
-     ! so output 0
-    0 "y" operand 1 v>operand CMPI
-    "nonzero" get BNE
-    0 "y" operand LI
-    "end" get B
-    "nonzero" resolve-label
-    ! load the value
-    "y" operand "x" operand 3 cells LWZ
-    ! load the sign
-    "x" operand "x" operand 2 cells LWZ
-    ! is the sign negative?
-    0 "x" operand 0 CMPI
-    "positive" get BEQ
-    "y" operand dup -1 MULI
-    "positive" resolve-label
-    "y" operand dup %tag-fixnum
-    "end" resolve-label
-] H{
-    { +input+ { { f "x" } } }
-    { +scratch+ { { f "y" } } }
-    { +clobber+ { "x" } }
-    { +output+ { "y" } }
-} define-intrinsic
-
-: define-float-op ( word op -- )
-    [ "z" operand "x" operand "y" operand ] swap suffix H{
-        { +input+ { { float "x" } { float "y" } } }
-        { +scratch+ { { float "z" } } }
-        { +output+ { "z" } }
-    } define-intrinsic ;
-
-{
-    { float+ FADD }
-    { float- FSUB }
-    { float* FMUL }
-    { float/f FDIV }
-} [
-    first2 define-float-op
-] each
-
-: define-float-jump ( word op -- )
-    [ "x" operand 0 "y" operand FCMPU ] swap suffix
-    { { float "x" } { float "y" } } define-if-intrinsic ;
-
-{
-    { float< BGE }
-    { float<= BGT }
-    { float> BLE }
-    { float>= BLT }
-    { float= BNE }
-} [
-    first2 define-float-jump
-] each
-
-\ float>fixnum [
-    "scratch" operand "in" operand FCTIWZ
-    "scratch" operand 1 0 param@ STFD
-    "out" operand 1 cell param@ LWZ
-    "out" operand dup %tag-fixnum
-] H{
-    { +input+ { { float "in" } } }
-    { +scratch+ { { float "scratch" } { f "out" } } }
-    { +output+ { "out" } }
-} define-intrinsic
-
-\ fixnum>float [
-    HEX: 4330 "scratch" operand LIS
-    "scratch" operand 1 0 param@ STW
-    "scratch" operand "in" operand %untag-fixnum
-    "scratch" operand dup HEX: 8000 XORIS
-    "scratch" operand 1 cell param@ STW
-    "f1" operand 1 0 param@ LFD
-    4503601774854144.0 "scratch" operand load-indirect
-    "f2" operand "scratch" operand float-offset LFD
-    "f1" operand "f1" operand "f2" operand FSUB
-] H{
-    { +input+ { { f "in" } } }
-    { +scratch+ { { f "scratch" } { float "f1" } { float "f2" } } }
-    { +output+ { "f1" } }
-} define-intrinsic
-
-
-\ tag [
-    "out" operand "in" operand tag-mask get ANDI
-    "out" operand dup %tag-fixnum
-] H{
-    { +input+ { { f "in" } } }
-    { +scratch+ { { f "out" } } }
-    { +output+ { "out" } }
-} define-intrinsic
-
-: userenv ( reg -- )
-    #! Load the userenv pointer in a register.
-    "userenv" f rot %load-dlsym ;
-
-\ getenv [
-    "n" operand dup 1 SRAWI
-    "x" operand userenv
-    "x" operand "n" operand "x" operand ADD
-    "x" operand dup 0 LWZ
-] H{
-    { +input+ { { f "n" } } }
-    { +scratch+ { { f "x" } } }
-    { +output+ { "x" } }
-    { +clobber+ { "n" } }
-} define-intrinsic
-
-\ setenv [
-    "n" operand dup 1 SRAWI
-    "x" operand userenv
-    "x" operand "n" operand "x" operand ADD
-    "val" operand "x" operand 0 STW
-] H{
-    { +input+ { { f "val" } { f "n" } } }
-    { +scratch+ { { f "x" } } }
-    { +clobber+ { "n" } }
-} define-intrinsic
-
-\ (tuple) [
-    tuple "layout" get size>> 2 + cells %allot
-    ! Store layout
-    "layout" get 12 load-indirect
-    12 11 cell STW
-    ! Store tagged ptr in reg
-    "tuple" get tuple %store-tagged
-] H{
-    { +input+ { { [ ] "layout" } } }
-    { +scratch+ { { f "tuple" } } }
-    { +output+ { "tuple" } }
-} define-intrinsic
-
-\ (array) [
-    array "n" get 2 + cells %allot
-    ! Store length
-    "n" operand 12 LI
-    12 11 cell STW
-    ! Store tagged ptr in reg
-    "array" get object %store-tagged
-] H{
-    { +input+ { { [ ] "n" } } }
-    { +scratch+ { { f "array" } } }
-    { +output+ { "array" } }
-} define-intrinsic
-
-\ (byte-array) [
-    byte-array "n" get 2 cells + %allot
-    ! Store length
-    "n" operand 12 LI
-    12 11 cell STW
-    ! Store tagged ptr in reg
-    "array" get object %store-tagged
-] H{
-    { +input+ { { [ ] "n" } } }
-    { +scratch+ { { f "array" } } }
-    { +output+ { "array" } }
-} define-intrinsic
-
-\ <ratio> [
-    ratio 3 cells %allot
-    "numerator" operand 11 1 cells STW
-    "denominator" operand 11 2 cells STW
-    ! Store tagged ptr in reg
-    "ratio" get ratio %store-tagged
-] H{
-    { +input+ { { f "numerator" } { f "denominator" } } }
-    { +scratch+ { { f "ratio" } } }
-    { +output+ { "ratio" } }
-} define-intrinsic
-
-\ <complex> [
-    complex 3 cells %allot
-    "real" operand 11 1 cells STW
-    "imaginary" operand 11 2 cells STW
-    ! Store tagged ptr in reg
-    "complex" get complex %store-tagged
-] H{
-    { +input+ { { f "real" } { f "imaginary" } } }
-    { +scratch+ { { f "complex" } } }
-    { +output+ { "complex" } }
-} define-intrinsic
-
-\ <wrapper> [
-    wrapper 2 cells %allot
-    "obj" operand 11 1 cells STW
-    ! Store tagged ptr in reg
-    "wrapper" get object %store-tagged
-] H{
-    { +input+ { { f "obj" } } }
-    { +scratch+ { { f "wrapper" } } }
-    { +output+ { "wrapper" } }
-} define-intrinsic
-
-! Alien intrinsics
-: %alien-accessor ( quot -- )
-    "offset" operand dup %untag-fixnum
-    "scratch" operand "offset" operand "alien" operand ADD
-    "value" operand "scratch" operand 0 roll call ; inline
-
-: alien-integer-get-template
-    H{
-        { +input+ {
-            { unboxed-c-ptr "alien" c-ptr }
-            { f "offset" fixnum }
-        } }
-        { +scratch+ { { f "value" } { f "scratch" } } }
-        { +output+ { "value" } }
-        { +clobber+ { "offset" } }
-    } ;
-
-: %alien-integer-get ( quot -- )
-    %alien-accessor
-    "value" operand dup %tag-fixnum ; inline
-
-: alien-integer-set-template
-    H{
-        { +input+ {
-            { f "value" fixnum }
-            { unboxed-c-ptr "alien" c-ptr }
-            { f "offset" fixnum }
-        } }
-        { +scratch+ { { f "scratch" } } }
-        { +clobber+ { "value" "offset" } }
-    } ;
-
-: %alien-integer-set ( quot -- )
-    "offset" get "value" get = [
-        "value" operand dup %untag-fixnum
-    ] unless
-    %alien-accessor ; inline
-
-: define-alien-integer-intrinsics ( word get-quot word set-quot -- )
-    [ %alien-integer-set ] curry
-    alien-integer-set-template
-    define-intrinsic
-    [ %alien-integer-get ] curry
-    alien-integer-get-template
-    define-intrinsic ;
-
-\ alien-unsigned-1 [ LBZ ]
-\ set-alien-unsigned-1 [ STB ]
-define-alien-integer-intrinsics
-
-\ alien-signed-1 [ pick >r LBZ r> dup EXTSB ]
-\ set-alien-signed-1 [ STB ]
-define-alien-integer-intrinsics
-
-\ alien-unsigned-2 [ LHZ ]
-\ set-alien-unsigned-2 [ STH ]
-define-alien-integer-intrinsics
-
-\ alien-signed-2 [ LHA ]
-\ set-alien-signed-2 [ STH ]
-define-alien-integer-intrinsics
-
-\ alien-cell [
-    [ LWZ ] %alien-accessor
-] H{
-    { +input+ {
-        { unboxed-c-ptr "alien" c-ptr }
-        { f "offset" fixnum }
-    } }
-    { +scratch+ { { unboxed-alien "value" } { f "scratch" } } }
-    { +output+ { "value" } }
-    { +clobber+ { "offset" } }
-} define-intrinsic
-
-\ set-alien-cell [
-    [ STW ] %alien-accessor
-] H{
-    { +input+ {
-        { unboxed-c-ptr "value" pinned-c-ptr }
-        { unboxed-c-ptr "alien" c-ptr }
-        { f "offset" fixnum }
-    } }
-    { +scratch+ { { f "scratch" } } }
-    { +clobber+ { "offset" } }
-} define-intrinsic
-
-: alien-float-get-template
-    H{
-        { +input+ {
-            { unboxed-c-ptr "alien" c-ptr }
-            { f "offset" fixnum }
-        } }
-        { +scratch+ { { float "value" } { f "scratch" } } }
-        { +output+ { "value" } }
-        { +clobber+ { "offset" } }
-    } ;
-
-: alien-float-set-template
-    H{
-        { +input+ {
-            { float "value" float }
-            { unboxed-c-ptr "alien" c-ptr }
-            { f "offset" fixnum }
-        } }
-        { +scratch+ { { f "scratch" } } }
-        { +clobber+ { "offset" } }
-    } ;
-
-: define-alien-float-intrinsics ( word get-quot word set-quot -- )
-    [ %alien-accessor ] curry
-    alien-float-set-template
-    define-intrinsic
-    [ %alien-accessor ] curry
-    alien-float-get-template
-    define-intrinsic ;
-
-\ alien-double [ LFD ]
-\ set-alien-double [ STFD ]
-define-alien-float-intrinsics
-
-\ alien-float [ LFS ]
-\ set-alien-float [ STFS ]
-define-alien-float-intrinsics
diff --git a/basis/cpu/ppc/intrinsics/tags.txt b/basis/cpu/ppc/intrinsics/tags.txt
deleted file mode 100644
index 6bf68304bb..0000000000
--- a/basis/cpu/ppc/intrinsics/tags.txt
+++ /dev/null
@@ -1 +0,0 @@
-unportable
diff --git a/basis/cpu/ppc/ppc.factor b/basis/cpu/ppc/ppc.factor
index 1577945118..8e7d8fed7d 100644
--- a/basis/cpu/ppc/ppc.factor
+++ b/basis/cpu/ppc/ppc.factor
@@ -1,8 +1,15 @@
-USING: accessors cpu.ppc.architecture cpu.ppc.intrinsics
-cpu.architecture namespaces alien.c-types kernel system
-combinators ;
+! Copyright (C) 2005, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: cpu.ppc.architecture
 
-{
+! PowerPC register assignments
+! r3-r11, r16-r31: integer vregs
+! f0-f13: float vregs
+! r12: scratch
+! r14: data stack
+! r15: retain stack
+
+<< {
     { [ os macosx? ] [
         4 "longlong" c-type (>>align)
         4 "ulonglong" c-type (>>align)
@@ -12,4 +19,545 @@ combinators ;
         t "longlong" c-type (>>stack-align?)
         t "ulonglong" c-type (>>stack-align?)
     ] }
-} cond
+} cond >>
+
+M: ppc machine-registers
+    {
+        { int-regs { 3 4 5 6 7 8 9 10 11 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 } }
+        { double-float-regs { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 } }
+    } ;
+
+: scratch-reg 12 ; inline
+
+M: ppc two-operand? t ;
+
+M: ppc %load-immediate ( reg n -- ) swap LOAD ;
+
+M:: ppc %load-indirect ( reg obj -- )
+    0 reg LOAD32
+    obj rc-absolute-ppc-2/2 rel-literal
+    reg reg 0 LWZ ;
+
+: ds-reg 14 ; inline
+: rs-reg 15 ; inline
+
+GENERIC: loc-reg ( loc -- reg )
+
+M: ds-loc log-reg drop ds-reg ;
+M: rs-loc log-reg drop rs-reg ;
+
+: loc>operand ( loc -- reg n )
+    [ loc-reg ] [ n>> cells neg ] bi ; inline
+
+M: ppc %peek loc>operand LWZ ;
+M: ppc %replace loc>operand STW ;
+
+: (%inc) ( n reg -- ) dup rot cells ADDI ; inline
+
+M: ppc %inc-d ( n -- ) ds-reg (%inc) ;
+M: ppc %inc-r ( n -- ) rs-reg (%inc) ;
+
+: reserved-area-size ( -- n )
+    os {
+        { linux [ 2 ] }
+        { macosx [ 6 ] }
+    } case cells ; foldable
+
+: lr-save ( -- n )
+    os {
+        { linux [ 1 ] }
+        { macosx [ 2 ] }
+    } case cells ; foldable
+
+: param@ ( n -- x ) reserved-area-size + ; inline
+
+: param-save-size ( -- n ) 8 cells ; foldable
+
+: local@ ( n -- x )
+    reserved-area-size param-save-size + + ; inline
+
+: factor-area-size ( -- n ) 2 cells ; foldable
+
+: next-save ( n -- i ) cell - ;
+
+: xt-save ( n -- i ) 2 cells - ;
+
+M: ppc stack-frame-size ( stack-frame -- i )
+    local@ factor-area-size + 4 cells align ;
+
+! M: x86 stack-frame-size ( stack-frame -- i )
+!     [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ]
+!     [ params>> ]
+!     [ return>> ]
+!     tri + +
+!     3 cells +
+!     align-stack ;
+
+M: ppc %call ( label -- ) BL ;
+M: ppc %jump-label ( label -- ) B ;
+M: ppc %return ( -- ) BLR ;
+
+M:: ppc %dispatch ( src temp -- )
+    0 temp LOAD32 rc-absolute-ppc-2/2 rel-here
+    temp temp src ADD
+    temp temp 5 cells LWZ
+    temp MTCTR
+    BCTR ;
+
+M: ppc %dispatch-label ( word -- )
+    0 , rc-absolute-cell rel-word ;
+
+:: (%slot) ( obj slot tag temp -- reg offset )
+    temp slot obj ADD
+    temp tag neg ; inline
+
+: (%slot-imm) ( obj slot tag -- reg offset )
+    [ cells ] dip - ; inline
+
+M: ppc %slot ( dst obj slot tag temp -- ) (%slot) LWZ ;
+M: ppc %slot-imm ( dst obj slot tag -- ) (%slot-imm) LWZ ;
+M: ppc %set-slot ( src obj slot tag temp -- ) (%slot) STW ;
+M: ppc %set-slot-imm ( src obj slot tag -- ) (%slot-imm) STW ;
+
+M: ppc %add     ADD ;
+M: ppc %add-imm ADDI ;
+M: ppc %sub     swapd SUBF ;
+M: ppc %sub-imm SUBI ;
+M: ppc %mul     MULLW ;
+M: ppc %mul-imm MULLI ;
+M: ppc %and     AND ;
+M: ppc %and-imm ANDI ;
+M: ppc %or      OR ;
+M: ppc %or-imm  ORI ;
+M: ppc %xor     XOR ;
+M: ppc %xor-imm XORI ;
+M: ppc %shl-imm swapd SLWI ;
+M: ppc %shr-imm swapd SRWI ;
+M: ppc %sar-imm SRAWI ;
+M: ppc %not     NOT ;
+
+M: ppc %integer>bignum ( dst src temp -- )
+    [
+        { "end" "non-zero" "pos" "store" } [ define-label ] each
+        ! is it zero?
+        0 over v>operand 0 CMPI
+        "non-zero" get BNE
+        dup 0 >bignum %load-literal
+        "end" get B
+        ! it is non-zero
+        "non-zero" resolve-label
+        1 bignum over 3 + cells %allot
+        1+ v>operand 12 LI ! compute the length
+        12 11 cell STW ! store the length
+        ! is the fixnum negative?
+        0 over v>operand 0 CMPI
+        "pos" get BGE
+        1 12 LI
+        ! store negative sign
+        12 11 2 cells STW
+        ! negate fixnum
+        dup v>operand dup -1 MULI
+        "store" get B
+        "pos" resolve-label
+        0 12 LI
+        ! store positive sign
+        12 11 2 cells STW
+        "store" resolve-label
+        ! store the number
+        dup v>operand 11 3 cells STW
+        ! tag the bignum, store it in reg
+        bignum %store-tagged
+        "end" resolve-label
+    ] with-scope ;
+
+: bignum@ ( n -- offset ) cells bignum tag-number - ; inline
+
+M:: %bignum>integer ( dst src -- )
+    [
+        "end" define-label
+        scratch-reg src 1 bignum@ LWZ
+        ! if the length is 1, its just the sign and nothing else,
+        ! so output 0
+        0 dst LI
+        0 scratch-reg 1 v>operand CMPI
+        "end" get BEQ
+        ! load the value
+        dst src 3 bignum@ LWZ
+        ! load the sign
+        scratch-reg src 2 bignum@ LWZ
+        ! branchless arithmetic: we want to turn 0 into 1,
+        ! and 1 into -1
+        scratch-reg scratch-reg 1 SLWI
+        scratch-reg scratch-reg NEG
+        scratch-reg scratch-reg 1 ADDI
+        ! multiply value by sign
+        dst dst scratch-reg MULLW
+        "end" resolve-label
+    ] with-scope ;
+
+M: ppc %add-float FADD ;
+M: ppc %sub-float FSUB ;
+M: ppc %mul-float FMUL ;
+M: ppc %div-float FDIV ;
+
+M: ppc %integer>float
+    HEX: 4330 "scratch" operand LIS
+    "scratch" operand 1 0 param@ STW
+    "in" operand dup HEX: 8000 XORIS
+    "in" operand 1 cell param@ STW
+    "f1" operand 1 0 param@ LFD
+    4503601774854144.0 "in" operand load-indirect
+    "f2" operand "in" operand float-offset LFD
+    "f1" operand "f1" operand "f2" operand FSUB ;
+
+M: ppc %float>integer
+    "scratch" operand "in" operand FCTIWZ
+    "scratch" operand 1 0 param@ STFD
+    "out" operand 1 cell param@ LWZ ;
+
+M: ppc %copy ( dst src -- ) MR ;
+
+M: ppc %copy-float ( dst src -- ) MFR ;
+
+M: ppc %unbox-float ( dst src -- ) float-offset LFD ;
+
+M:: ppc %unbox-any-c-ptr ( dst src temp -- )
+    [
+        { "is-byte-array" "end" "start" } [ define-label ] each
+        ! Address is computed in dst
+        0 dst LI
+        ! Load object into scratch-reg
+        scratch-reg src MR
+        ! We come back here with displaced aliens
+        "start" resolve-label
+        ! Is the object f?
+        0 scratch-reg \ f tag-number CMPI
+        ! If so, done
+        "end" get BEQ
+        ! Is the object an alien?
+        0 scratch-reg header-offset LWZ
+        0 0 alien type-number tag-fixnum CMPI
+        "is-byte-array" get BNE
+        ! If so, load the offset
+        0 scratch-reg alien-offset LWZ
+        ! Add it to address being computed
+        dst dst 0 ADD
+        ! Now recurse on the underlying alien
+        scratch-reg scratch-reg underlying-alien-offset LWZ
+        "start" get B
+        "is-byte-array" resolve-label
+        ! Add byte array address to address being computed
+        dst dst scratch-reg ADD
+        ! Add an offset to start of byte array's data area
+        dst dst byte-array-offset ADDI
+        "end" resolve-label
+    ] with-scope ;
+
+: alien@ ( n -- n' ) cells object tag-number - ;
+
+M:: ppc %box-alien ( dst src temp -- )
+    [
+        "f" define-label
+        dst \ f tag-number %load-immediate
+        0 src 0 CMPI
+        "f" get BEQ
+        dst 4 cells alien temp %allot
+        ! Store offset
+        dst src 3 alien@ STW
+        temp \ f tag-number %load-immediate
+        ! Store expired slot
+        temp dst 1 alien@ STW
+        ! Store underlying-alien slot
+        temp dst 2 alien@ STW
+        "f" resolve-label
+    ] with-scope ;
+
+M: ppc %alien-unsigned-1 0 LBZ ;
+M: ppc %alien-unsigned-2 0 LHZ ;
+
+M: ppc %alien-signed-1 dupd 0 LBZ EXTSB ;
+M: ppc %alien-signed-2 0 LHA ;
+
+M: ppc %alien-cell 0 LWZ ;
+
+M: ppc %alien-float 0 LFS ;
+M: ppc %alien-double 0 LFD ;
+
+M: ppc %set-alien-integer-1 0 STB ;
+M: ppc %set-alien-integer-2 0 STH ;
+
+M: ppc %set-alien-cell 0 STW ;
+
+M: ppc %set-alien-float 0 STFS ;
+M: ppc %set-alien-double 0 STFD ;
+
+: load-zone-ptr ( reg -- )
+    [ "nursery" f ] dip %load-dlsym ;
+
+: load-allot-ptr ( nursery-ptr allot-ptr -- )
+    [ drop load-zone-ptr ] [ swap cell LWZ ] 2bi ;
+
+:: inc-allot-ptr ( nursery-ptr n -- )
+    scratch-reg inc-allot-ptr 4 LWZ
+    scratch-reg scratch-reg n 8 align ADD
+    scratch-reg inc-allot-ptr 4 STW ;
+
+:: store-header ( temp class -- )
+    class type-number tag-fixnum scratch-reg LI
+    temp scratch-reg 0 STW ;
+
+: store-tagged ( dst tag -- )
+    dupd tag-number ORI ;
+
+M:: ppc %allot ( dst size class nursery-ptr -- )
+    nursery-ptr dst load-allot-ptr
+    dst class store-header
+    dst class store-tagged
+    nursery-ptr size inc-allot-ptr ;
+
+: %alien-global ( dest name -- )
+    [ f swap %load-dlsym ] [ drop dup 0 LWZ ] 2bi ;
+
+: load-cards-offset ( dest -- )
+    "cards_offset" %alien-global ;
+
+: load-decks-offset ( dest -- )
+    "decks_offset" %alien-global ;
+
+M:: ppc %write-barrier ( src card# table -- )
+    card-mark scratch-reg LI
+
+    ! Mark the card
+    table load-cards-offset
+    src card# card-bits SRWI
+    table scratch-reg card# STBX
+
+    ! Mark the card deck
+    table load-decks-offset
+    src card# deck-bits SRWI
+    table scratch-reg card# STBX ;
+
+M: ppc %gc
+    "end" define-label
+    12 load-zone-ptr
+    11 12 cell LWZ ! nursery.here -> r11
+    12 12 3 cells LWZ ! nursery.end -> r12
+    11 11 1024 ADDI ! add ALLOT_BUFFER_ZONE to here
+    11 0 12 CMP ! is here >= end?
+    "end" get BLE
+    0 frame-required
+    %prepare-alien-invoke
+    "minor_gc" f %alien-invoke
+    "end" resolve-label ;
+
+M: ppc %prologue ( n -- )
+    0 scrach-reg LOAD32 rc-absolute-ppc-2/2 rel-this
+    0 MFLR
+    1 1 pick neg ADDI
+    scrach-reg 1 pick xt-save STW
+    dup scrach-reg LI
+    scrach-reg 1 pick next-save STW
+    0 1 rot lr-save + STW ;
+
+M: ppc %epilogue ( n -- )
+    #! At the end of each word that calls a subroutine, we store
+    #! the previous link register value in r0 by popping it off
+    #! the stack, set the link register to the contents of r0,
+    #! and jump to the link register.
+    0 1 pick lr-save + LWZ
+    1 1 rot ADDI
+    0 MTLR ;
+
+:: (%boolean) ( dst word -- )
+    "end" define-label
+    \ f tag-number %load-immediate
+    "end" get word execute
+    dst \ t %load-indirect
+    "end" get resolve-label ; inline
+
+: %boolean ( dst cc -- )
+    negate-cc {
+        { cc< [ \ BLT %boolean ] }
+        { cc<= [ \ BLE %boolean ] }
+        { cc> [ \ BGT %boolean ] }
+        { cc>= [ \ BGE %boolean ] }
+        { cc= [ \ BEQ %boolean ] }
+        { cc/= [ \ BNE %boolean ] }
+    } case ;
+
+: (%compare) ( src1 src2 -- ) [ 0 ] dip CMP ; inline
+: (%compare-imm) ( src1 src2 -- ) [ 0 ] 2dip CMPI ; inline
+: (%compare-float) ( src1 src2 -- ) [ 0 ] dip FCMPU ; inline
+
+M: ppc %compare (%compare) %boolean ;
+M: ppc %compare-imm (%compare-imm) %boolean ;
+M: ppc %compare-float (%compare-float) %boolean ;
+
+: %branch ( label cc -- )
+    {
+        { cc< [ BLT ] }
+        { cc<= [ BLE ] }
+        { cc> [ BGT ] }
+        { cc>= [ BGE ] }
+        { cc= [ BEQ ] }
+        { cc/= [ BNE ] }
+    } case ;
+
+M: ppc %compare-branch (%compare) %branch ;
+M: ppc %compare-imm-branch (%compare-imm) %branch ;
+M: ppc %compare-float-branch (%compare-float) %branch ;
+
+! M: ppc %spill-integer ( src n -- ) spill-integer@ swap MOV ;
+! M: ppc %reload-integer ( dst n -- ) spill-integer@ MOV ;
+! 
+! M: ppc %spill-float ( src n -- ) spill-float@ swap MOVSD ;
+! M: ppc %reload-float ( dst n -- ) spill-float@ MOVSD ;
+
+M: ppc %loop-entry ;
+
+M: int-regs return-reg drop 3 ;
+M: int-regs param-regs drop { 3 4 5 6 7 8 9 10 } ;
+M: float-regs return-reg drop 1 ;
+M: float-regs param-regs 
+    drop os H{
+        { macosx { 1 2 3 4 5 6 7 8 9 10 11 12 13 } }
+        { linux { 1 2 3 4 5 6 7 8 } }
+    } at ;
+
+M: int-regs %save-param-reg drop 1 rot local@ STW ;
+M: int-regs %load-param-reg drop 1 rot local@ LWZ ;
+
+GENERIC: STF ( src dst off reg-class -- )
+
+M: single-float-regs STF drop STFS ;
+M: double-float-regs STF drop STFD ;
+
+M: float-regs %save-param-reg >r 1 rot local@ r> STF ;
+
+GENERIC: LF ( dst src off reg-class -- )
+
+M: single-float-regs LF drop LFS ;
+M: double-float-regs LF drop LFD ;
+
+M: float-regs %load-param-reg >r 1 rot local@ r> LF ;
+
+M: stack-params %load-param-reg ( stack reg reg-class -- )
+    drop >r 0 1 rot local@ LWZ 0 1 r> param@ STW ;
+
+: next-param@ ( n -- x ) param@ stack-frame get total-size>> + ;
+
+M: stack-params %save-param-reg ( stack reg reg-class -- )
+    #! Funky. Read the parameter from the caller's stack frame.
+    #! This word is used in callbacks
+    drop
+    0 1 rot next-param@ LWZ
+    0 1 rot local@ STW ;
+
+M: ppc %prepare-unbox ( -- )
+    ! First parameter is top of stack
+    3 ds-reg 0 LWZ
+    ds-reg dup cell SUBI ;
+
+M: ppc %unbox ( n reg-class func -- )
+    ! Value must be in r3
+    ! Call the unboxer
+    f %alien-invoke
+    ! Store the return value on the C stack
+    over [ [ return-reg ] keep %save-param-reg ] [ 2drop ] if ;
+
+M: ppc %unbox-long-long ( n func -- )
+    ! Value must be in r3:r4
+    ! Call the unboxer
+    f %alien-invoke
+    ! Store the return value on the C stack
+    [
+        3 1 pick local@ STW
+        4 1 rot cell + local@ STW
+    ] when* ;
+
+M: ppc %unbox-large-struct ( n c-type -- )
+    ! Value must be in r3
+    ! Compute destination address and load struct size
+    [ 4 1 rot local@ ADDI ] [ heap-size 5 LI ] bi*
+    ! Call the function
+    "to_value_struct" f %alien-invoke ;
+
+M: ppc %box ( n reg-class func -- )
+    ! If the source is a stack location, load it into freg #0.
+    ! If the source is f, then we assume the value is already in
+    ! freg #0.
+    >r
+    over [ 0 over param-reg swap %load-param-reg ] [ 2drop ] if
+    r> f %alien-invoke ;
+
+M: ppc %box-long-long ( n func -- )
+    >r [
+        3 1 pick local@ LWZ
+        4 1 rot cell + local@ LWZ
+    ] when* r> f %alien-invoke ;
+
+: struct-return@ ( n -- n )
+    [ stack-frame get params>> ] unless* local@ ;
+
+M: ppc %prepare-box-struct ( -- )
+    #! Compute target address for value struct return
+    3 1 f struct-return@ ADDI
+    3 1 0 local@ STW ;
+
+M: ppc %box-large-struct ( n c-type -- )
+    ! If n = f, then we're boxing a returned struct
+    ! Compute destination address and load struct size
+    [ 3 1 rot struct-return@ ADDI ] [ heap-size 4 LI ] bi*
+    ! Call the function
+    "box_value_struct" f %alien-invoke ;
+
+M: ppc %prepare-alien-invoke
+    #! Save Factor stack pointers in case the C code calls a
+    #! callback which does a GC, which must reliably trace
+    #! all roots.
+    "stack_chain" f 11 %load-dlsym
+    11 11 0 LWZ
+    1 11 0 STW
+    ds-reg 11 8 STW
+    rs-reg 11 12 STW ;
+
+M: ppc %alien-invoke ( symbol dll -- )
+    11 %load-dlsym 11 MTLR BLRL ;
+
+M: ppc %alien-callback ( quot -- )
+    3 load-indirect "c_to_factor" f %alien-invoke ;
+
+M: ppc %prepare-alien-indirect ( -- )
+    "unbox_alien" f %alien-invoke
+    13 3 MR ;
+
+M: ppc %alien-indirect ( -- )
+    13 MTLR BLRL ;
+
+M: ppc %callback-value ( ctype -- )
+    ! Save top of data stack
+    3 ds-reg 0 LWZ
+    3 1 0 local@ STW
+    ! Restore data/call/retain stacks
+    "unnest_stacks" f %alien-invoke
+    ! Restore top of data stack
+    3 1 0 local@ LWZ
+    ! Unbox former top of data stack to return registers
+    unbox-return ;
+
+M: ppc value-structs?
+    #! On Linux/PPC, value structs are passed in the same way
+    #! as reference structs, we just have to make a copy first.
+    os linux? not ;
+
+M: ppc fp-shadows-int? ( -- ? ) os macosx? ;
+
+M: ppc small-enough? ( n -- ? ) -32768 32767 between? ;
+
+M: ppc struct-small-enough? ( size -- ? ) drop f ;
+
+M: ppc %box-small-struct
+    drop "No small structs" throw ;
+
+M: ppc %unbox-small-struct
+    drop "No small structs" throw ;