REGISTERS

    /* Registers are allocated top down; the order here is odd in order to make
     * sure that non-volatile registers get allocated from r31 (or f31) down.
     *
     * Attributes ending in an exclamation mark must match exactly when copying
     * a register into another register (e.g. for eviction).
     */

    r12                                           bytes4! int! volatile; 
    r11                                           bytes4! int! volatile; 
    r10                                           bytes4! int! volatile; 
    r9                                            bytes4! int! volatile;
    r8                                            bytes4! int! volatile;
    r7                                            bytes4! int! volatile;
    r6                                            bytes4! int! volatile;
    r5                                            bytes4! int! volatile;
    r4                                            bytes4! int! volatile;
    r3                                            bytes4! int! volatile ret;

    r31                                           bytes4! int!; 
    r30                                           bytes4! int!; 
    r29                                           bytes4! int!; 
    r28                                           bytes4! int!; 
    r27                                           bytes4! int!; 
    r26                                           bytes4! int!; 
    r25                                           bytes4! int!; 
    r24                                           bytes4! int!; 
    r23                                           bytes4! int!; 
    r22                                           bytes4! int!; 
    r21                                           bytes4! int!; 
    r20                                           bytes4! int!; 
    r19                                           bytes4! int!; 
    r18                                           bytes4! int!; 
    r17                                           bytes4! int!; 
    r16                                           bytes4! int!;
    r15                                           bytes4! int!;
    r14                                           bytes4! int!;
    r13                                           bytes4! int!;

    r11r12  named("r11", "r12") aliases(r11, r12) bytes8! pair! volatile;
    r9r10   named("r9",  "r10") aliases(r9,  r10) bytes8! pair! volatile;
    r7r8    named("r7",  "r8")  aliases(r7,  r8)  bytes8! pair! volatile;
    r5r6    named("r5",  "r6")  aliases(r6,  r6)  bytes8! pair! volatile;
    r3r4    named("r3",  "r4")  aliases(r3,  r4)  bytes8! pair! volatile pret;

    r29r30  named("r29", "r30") aliases(r29, r30) bytes8! pair!;
    r27r28  named("r27", "r28") aliases(r27, r28) bytes8! pair!;
    r25r26  named("r25", "r26") aliases(r25, r26) bytes8! pair!;
    r23r24  named("r23", "r24") aliases(r23, r24) bytes8! pair!;
    r21r22  named("r21", "r22") aliases(r21, r22) bytes8! pair!;
    r19r20  named("r19", "r20") aliases(r19, r20) bytes8! pair!;
    r17r18  named("r17", "r18") aliases(r17, r18) bytes8! pair!;
    r15r16  named("r15", "r16") aliases(r15, r16) bytes8! pair!;
    r13r14  named("r13", "r14") aliases(r13, r14) bytes8! pair!;

    f14                                           bytes4! float! volatile;
    f13                                           bytes4! float! volatile;
    f12                                           bytes4! float! volatile;
    f11                                           bytes4! float! volatile;
    f10                                           bytes4! float! volatile;
    f9                                            bytes4! float! volatile;
    f8                                            bytes4! float! volatile;
    f7                                            bytes4! float! volatile;
    f6                                            bytes4! float! volatile;
    f5                                            bytes4! float! volatile;
    f4                                            bytes4! float! volatile;
    f3                                            bytes4! float! volatile fret;
    f2                                            bytes4! float! volatile;
    f1                                            bytes4! float! volatile;
    f0                                            bytes4! float! volatile;

    f31                                           bytes4! float!;
    f30                                           bytes4! float!;
    f29                                           bytes4! float!;
    f28                                           bytes4! float!;
    f27                                           bytes4! float!;
    f26                                           bytes4! float!;
    f25                                           bytes4! float!;
    f24                                           bytes4! float!;
    f23                                           bytes4! float!;
    f22                                           bytes4! float!;
    f21                                           bytes4! float!;
    f20                                           bytes4! float!;
    f19                                           bytes4! float!;
    f18                                           bytes4! float!;
    f17                                           bytes4! float!;
    f16                                           bytes4! float!;
    f15                                           bytes4! float!;

    d14     named("f14")       aliases(f14)       bytes8! double! volatile;
    d13     named("f13")       aliases(f13)       bytes8! double! volatile;
    d12     named("f12")       aliases(f12)       bytes8! double! volatile;
    d11     named("f11")       aliases(f11)       bytes8! double! volatile;
    d10     named("f10")       aliases(f10)       bytes8! double! volatile;
    d9      named("f9")        aliases(f9)        bytes8! double! volatile;
    d8      named("f8")        aliases(f8)        bytes8! double! volatile;
    d7      named("f7")        aliases(f7)        bytes8! double! volatile;
    d6      named("f6")        aliases(f6)        bytes8! double! volatile;
    d5      named("f5")        aliases(f5)        bytes8! double! volatile;
    d4      named("f4")        aliases(f4)        bytes8! double! volatile;
    d3      named("f3")        aliases(f3)        bytes8! double! volatile dret;
    d2      named("f2")        aliases(f2)        bytes8! double! volatile;
    d1      named("f1")        aliases(f1)        bytes8! double! volatile;
    d0      named("f0")        aliases(f0)        bytes8! double! volatile;

    d31     named("f31")       aliases(f31)       bytes8! double!;
    d30     named("f30")       aliases(f30)       bytes8! double!;
    d29     named("f29")       aliases(f29)       bytes8! double!;
    d28     named("f28")       aliases(f28)       bytes8! double!;
    d27     named("f27")       aliases(f27)       bytes8! double!;
    d26     named("f26")       aliases(f26)       bytes8! double!;
    d25     named("f25")       aliases(f25)       bytes8! double!;
    d24     named("f24")       aliases(f24)       bytes8! double!;
    d23     named("f23")       aliases(f23)       bytes8! double!;
    d22     named("f22")       aliases(f22)       bytes8! double!;
    d21     named("f21")       aliases(f21)       bytes8! double!;
    d20     named("f20")       aliases(f20)       bytes8! double!;
    d19     named("f19")       aliases(f19)       bytes8! double!;
    d18     named("f18")       aliases(f18)       bytes8! double!;
    d17     named("f17")       aliases(f17)       bytes8! double!;
    d16     named("f16")       aliases(f16)       bytes8! double!;
    d15     named("f15")       aliases(f15)       bytes8! double!;

	cr0                                           cr!;



DECLARATIONS

	cr;
    ubyteX;   /* bottom 8 bits valid, the rest undefined */
    ubyte0;  /* bottom 8 bits valid, the rest 0 */
    ushortX;  /* bottom 16 bits valid, the rest undefined */
    ushort0; /* bottom 16 bits valid, the rest 0 */

	address fragment;



PATTERNS

/* Special */

	PAIR(BLOCK4, BLOCK4);



/* Miscellaneous special things */

	PUSH4(in:(int)reg)
		emit "stwu %in, -4(sp)"
		cost 4;

    PUSH8(in:(pair)reg)
        emit "stwu %in.0, -4(sp)"
        emit "stwu %in.1, -4(sp)"
        cost 8;

	out:(int)reg = POP4
		emit "lwz %out, 0(sp)"
        emit "addi sp, sp, 4"
		cost 8;

    out:(pair)reg = POP8
        emit "lwz %out.0, 4(sp)"
        emit "lwz %out.1, 0(sp)"
        emit "addi sp, sp, 8"
        cost 12;

	out:(float)reg = POPF4
		emit "lfs %out, 0(sp)"
		emit "addi sp, sp, 4"
		cost 8;
		
	SETRET4(in:(ret)reg)
		emit "! setret4"
		cost 1;

    SETRET8(in:(pret)reg)
        emit "! setret8"
        cost 1;

    (ret)reg = GETRET4
        emit "! getret4"
        cost 1;

    (pret)reg = GETRET8
        emit "! getret8"
        cost 1;

	STACKADJUST4(delta:CONST4)
        when signed_constant(%delta, 16)
		emit "addi sp, sp, $delta"
		cost 4;

    out:(int)reg = GETFP4
        emit "mr %out, fp"
        cost 4;

    out:(int)reg = FPTOARGS4(GETFP4)
        emit "addi %out, fp, 8"
        cost 4;

    out:(int)reg = FPTOARGS4(in:(int)reg)
        emit "addi %out, %in, 8"
        cost 4;



/* Memory operations */

    /* Stores */

	STORE8(addr:address, value:(pair)reg)
		emit "stw %value.0, 4+%addr"
		emit "stw %value.1, 0+%addr"
		cost 4;

	STORE4(addr:address, value:(int)reg)
		emit "stw %value, %addr"
		cost 4;

	STORE2(addr:address, value:(int)ushortX)
		emit "sth %value, %addr"
		cost 4;

    STORE2(ADD4(left:(int)reg, right:(int)reg), value:(int)ushortX)
        emit "sthx %value, %left, %right"
        cost 4;

    STORE1(addr:address, value:(int)ubyteX)
		emit "stb %value, %addr"
		cost 4;

    STORE1(ADD4(left:(int)reg, right:(int)reg), value:(int)ubyteX)
        emit "stbx %value, %left, %right"
        cost 4;

    /* Loads */

	out:(int)reg = LOAD4(addr:address)
		emit "lwz %out, %addr"
		cost 4;

    out:(pair)reg = LOAD8(addr:address)
        emit "lwz %out.0, 4+%addr"
        emit "lwz %out.1, 0+%addr"
        cost 8;

	out:(int)ushort0 = LOAD2(addr:address)
		emit "lhz %out, %addr"
		cost 4;

	out:(int)ubyte0 = LOAD1(addr:address)
		emit "lbz %out, %addr"
		cost 4;

    /* ubyte intrinsics */

    out:(int)ubyteX = in:(int)ubyte0
        with %out == %in
        emit "! ubyte0 -> ubyteX"
        cost 1;

    out:(int)ubyte0 = in:(int)ubyteX
        emit "andi %out, %in, 0xff ! ubyteX -> ubyte0"
        cost 4;

    out:(int)reg = in:(int)ubyte0
        with %out == %in
        emit "! ubyte0 -> reg"
        cost 4;

    out:(int)ubyteX = in:(int)reg
        with %out == %in
        emit "! reg -> ubyteX"
        cost 1;

    /* ushort intrinsics */

    out:(int)ushortX = in:(int)ushort0
        with %out == %in
        emit "! ushort0 -> ushortX"
        cost 1;

    out:(int)ushort0 = in:(int)ushortX
        emit "andi %out, %in, 0xff ! ushortX -> ushort0"
        cost 4;

    out:(int)reg = in:(int)ushort0
        with %out == %in
        emit "! ushort0 -> reg"
        cost 4;

    out:(int)ushortX = in:(int)reg
        with %out == %in
        emit "! reg -> ushortX"
        cost 1;

	/* byte conversions */

    out:(int)ubyte0 = CIU14(in:(int)ubyte0)
        with %out == %in
        emit "! CIU14(ubyte0) -> ubyte0"
        cost 1;
        
    out:(int)ubyte0 = CIU41(in:(int)ubyte0)
        with %out == %in
        emit "! CIU41(ubyte0) -> ubyte0"
        cost 1;
        
    out:(int)ubyteX = CIU41(in:(int)ubyteX)
        with %out == %in
        emit "! CIU41(ubyteX) -> ubyteX"
        cost 1;
        
    out:(int)reg = CII14(in:(int)ubyteX)
        emit "extsb %out, %in ! CII14(ubyteX) -> reg"
        cost 4;

    /* short conversions */

    out:(int)ushort0 = CIU24(in:(int)ushort0)
        with %out == %in
        emit "! CIU24(ushort0) -> ushort0"
        cost 1;
        
    out:(int)ushort0 = CIU42(in:(int)ushort0)
        with %out == %in
        emit "! CIU42(ushort0) -> ushort0"
        cost 1;
        
    out:(int)ushortX = CIU42(in:(int)ushortX)
        with %out == %in
        emit "! CIU42(ushortX) -> ushortX"
        cost 1;
        
    out:(int)reg = CII24(in:(int)ushort0)
        with %out == %in
        emit "! CII24(ushort0) -> reg"
        cost 4;
        
    out:(int)reg = CII24(in:(int)ushortX)
        emit "extsh %out, %in"
        cost 4;


/* Locals */

	out:(int)reg = in:LOCAL4
		emit "addi %out, fp, $in"
		cost 4;

	address = in:LOCAL4
		emit "$in(fp)";



/* Memory addressing modes */

	address = ADD4(addr:(int)reg, offset:CONST4)
        when signed_constant(%offset, 16)
		emit "$offset(%addr)";

	address = addr:(int)reg
		emit "0(%addr)";



/* Branches */

	JUMP(addr:BLOCK4)
		emit "b $addr"
		cost 4;

	CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4))
        emit "bc 12, 2, $true" /* IFTRUE EQ */
		emit "b $false"
		cost 8;

	CJUMPLE(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4))
        emit "bc 4, 1, $true" /* IFFALSE GT */
        emit "b $false"
		cost 8;

	CJUMPLT(value:(cr)cr, PAIR(true:BLOCK4, false:BLOCK4))
        emit "bc 12, 0, $true" /* IFTRUE LT */
        emit "b $false"
		cost 8;

	CALL(dest:LABEL4)
        with corrupted(volatile)
		emit "bl $dest"
		cost 4;

    CALL(dest:(int)reg)
        with corrupted(volatile)
        emit "mtspr ctr, %dest"
        emit "bcctrl 20, 0, 0"
        cost 8;

    JUMP(dest:LABEL4)
        emit "b $dest"
        cost 4;



/* Comparisons */

	cr:(cr)cr = COMPARES44(left:(int)reg, right:(int)reg)
        emit "cmp %cr, 0, %left, %right"
		cost 4;

	cr:(cr)cr = COMPARES44(left:(int)reg, right:CONST4)
        when signed_constant(%right, 16)
        emit "cmpi %cr, 0, %left, $right"
		cost 4;

	cr:(cr)cr = COMPAREU44(left:(int)reg, right:(int)reg)
        emit "cmpl %cr, 0, %left, %right"
		cost 4;

	cr:(cr)cr = COMPAREU44(left:(int)reg, right:CONST4)
        when signed_constant(%right, 16)
        emit "cmpli %cr, 0, %left, $right"
		cost 4;

    out:(cr)cr = COMPARES44(in:(cr)cr, result:CONST4)
        when specific_constant(%result, 0)
        with %out == %in
        emit "! COMPARES(cr, 0)"
        cost 4;



/* Booleans */

    out:(int)reg = IFEQ4(in:(cr)cr)
        emit "mfcr %out" /* get cr0 */
        emit "rlwinmi %out, %out, 32-2, 2, 31" /* extract just EQ */
        cost 8;

    out:(int)reg = IFEQ4(in:(int)reg)
        emit "cntlzw %out, %in" /* returns 0..32 */
        emit "rlwinmi %out, %out, 32-5, 5, 31" /* if 32, return 1, otherwise 0 */
        cost 8;



/* Conversions */

    out:(int)reg = CIU44(in:(int)reg)
        with %out == %in
        emit "! ciu44"
        cost 4;

    out:(int)reg = CUI44(in:(int)reg)
        with %out == %in
        emit "! cui44"
        cost 4;


/* ALU operations */

	out:(int)reg = ADD4(left:(int)reg, right:(int)reg)
		emit "add %out, %left, %right"
		cost 4;

	out:(int)reg = ADD4(left:(int)reg, right:CONST4)
        when signed_constant(%right, 16)
		emit "addi %out, %left, $right"
		cost 4;

	out:(int)reg = ADD4(left:CONST4, right:(int)reg)
        when signed_constant(%left, 16)
		emit "addi %out, %right, $left"
		cost 4;

	out:(int)reg = SUB4(left:(int)reg, right:(int)reg)
		emit "subf %out, %left, %right"
		cost 4;

	out:(int)reg = SUB4(left:(int)reg, right:CONST4)
		emit "addi %out, %left, -[$right]"
		cost 4;

	out:(int)reg = MUL4(left:(int)reg, right:(int)reg)
		emit "mullw %out, %right, %left"
		cost 4;

	out:(int)reg = MOD4(left:(int)reg, right:(int)reg)
		emit "divw %out, %left, %right"
        emit "mullw %out, %out, %right"
        emit "subf %out, %out, %left"
		cost 12;

	out:(int)reg = MUL4(left:(int)reg, right:(int)reg)
		emit "mullw %out, %left, %right"
		cost 4;

	out:(int)reg = DIV4(left:(int)reg, right:(int)reg)
		emit "divw %out, %left, %right"
		cost 4;

    out:(int)reg = ASL4(left:(int)reg, right:(int)reg)
        emit "slw %out, %left, %right"
        cost 4;

    out:(int)reg = NEG4(left:(int)reg)
        emit "neg %out, %left"
        cost 4;

	out:(int)reg = AND4(left:CONST4, right:(int)reg)
		emit "andi. %out, %right, $left"
		cost 4;

	out:(int)reg = AND4(left:(int)reg, right:CONST4)
		emit "andi. %out, %left, $right"
		cost 4;

	out:(int)reg = AND4(left:(int)reg, right:(int)reg)
		emit "and %out, %left, %right"
		cost 4;

	out:(int)reg = OR4(left:(int)reg, right:(int)reg)
		emit "or %out, %right, %left"
		cost 4;

	out:(int)reg = EOR4(left:(int)reg, right:(int)reg)
		emit "xor %out, %right, %left"
		cost 4;

	out:(int)reg = value:LABEL4
		emit "la %out, $value"
		cost 4;

	out:(int)reg = value:BLOCK4
		emit "la %out, $value"
		cost 4;

	out:(int)reg = value:CONST4
		emit "li %out, $value"
		cost 8;


/* FPU operations */

    out:(float)reg = LOADF4(addr:address)
        emit "lfs %out, %addr"
        cost 4;
        
    out:(double)reg = LOADF8(addr:address)
        emit "lfd %out, %addr"
        cost 4;
        
	out:(float)reg = value:CONSTF4
		emit "lfs %out, address-containing-$value"
		cost 8;

	out:(float)reg = ADDF4(left:(float)reg, right:(float)reg)
		emit "fadds %out, %left, %right"
		cost 4;

	out:(double)reg = ADDF8(left:(double)reg, right:(double)reg)
		emit "fadd %out, %left, %right"
		cost 4;

	out:(float)reg = SUBF4(left:(float)reg, right:(float)reg)
		emit "fsubs %out, %left, %right"
		cost 4;

	out:(double)reg = SUBF8(left:(double)reg, right:(double)reg)
		emit "fsub %out, %left, %right"
		cost 4;

    out:(float)reg = MULF4(left:(float)reg, right:(float)reg)
        emit "fmuls %out, %left, %right"
        cost 4;

    out:(double)reg = MULF8(left:(double)reg, right:(double)reg)
        emit "fmul %out, %left, %right"
        cost 4;

    out:(float)reg = NEGF4(left:(float)reg)
        emit "fneg %out, %left"
        cost 4;

    out:(double)reg = NEGF8(left:(double)reg)
        emit "fneg %out, %left"
        cost 4;

	cr:(cr)cr = COMPAREF44(left:(float)reg, right:(float)reg)
        emit "fcmpu %cr, %left, %right"
		cost 4;

	cr:(cr)cr = COMPAREF84(left:(double)reg, right:(double)reg)
        emit "fcmpu %cr, %left, %right"
		cost 4;

    out:(ret)reg = CFI44(val:(fret)reg)
        with corrupted(volatile)
        emit "bl .cfi44"
        cost 4;

    out:(fret)reg = CIF44(val:(ret)reg)
        with corrupted(volatile)
        emit "bl .cif44"
        cost 4;

    out:(ret)reg = CFI84(val:(dret)reg)
        with corrupted(volatile)
        emit "bl .cfi84"
        cost 4;

    out:(dret)reg = CIF48(val:(ret)reg)
        with corrupted(volatile)
        emit "bl .cif48"
        cost 4;

    out:(float)reg = CFF84(val:(double)reg)
        emit "frsp %out, %val"
        cost 4;

    out:(double)reg = CFF48(val:(float)reg)
        emit "fmr %out, %val"
        cost 1;

/* vim: set sw=4 ts=4 expandtab : */