Tests pass if one edits the top build.lua to uncomment "qemuppc" from both vars.plats and vars.plats_with_tests, and one leaves mcg in plat/qemuppc/descr. Add or correct some EM instructions in treebuilder.c: - "lof", "stf": handle negative offsets in load() and store(). - "cuu": add using IR_FROMUI. - "lim", "sim": keep an entire word in ".ignmask", to be compatible with mach/powerpc/libem/trp.s and ncg. We also keep a word in ".ignmask" in ncg for both i386 and m68020. - "trp": pass trap number in register. See comment in helper_function_with_arg(). - "sig": push the old value of .trppc on the stack. - "and ?", "ior ?", "xor ?", "com ?", "cms ?", "set ?", "inn ?": connect to helper functions in libem. - "blm", "bls": drop call to memmove() and use new helper ".bls4", because tests/plat/structcopy_e.c can't call memmove(). - "xor s", "cms s": if s is large, fall back on helper function. - "rol", "ror": add by decomposing each rotate into 4 IR ops. - "rck s", "bls s": make fatal unless s is word size. - "loi": push multiple loads in the correct order. - "dup s", "exg s": if s is large, fall back on helper. - "dus": add using new helper ".dus4". - "lxl", "lxa": follow the static chain, not the dynamic chain. - "lor 1": materialise the stack before pushing the stack pointer. - "lor 2", "str 2": make fatal. - "los", "sts": drop calls to memcpy() and use helpers ".los4" and and ".sts4", so lang/m2/libm2/LtoUset.e starts working. - "gto": correctly read descriptor. Change mach/powerpc/mcg/table: - ANY.L: add for "asp -8". - LOAD.L: work around register corruption. - COMPAREUL.I: add for "cms 8".
		
			
				
	
	
		
			814 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			814 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| 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 may have at most one of: int, float, long, double. These
 | |
|      * indicate that the register is used to store a value of that type. If
 | |
|      * your register can store more than one type, create an alias. Registers
 | |
|      * with none of these cannot be copied by the code generator (and so cannot
 | |
|      * be moved from register to register or spilt).
 | |
|      */
 | |
| 
 | |
|     r12                                           int volatile; 
 | |
|     r11                                           int volatile; 
 | |
|     r10                                           int volatile; 
 | |
|     r9                                            int volatile;
 | |
|     r8                                            int volatile;
 | |
|     r7                                            int volatile;
 | |
|     r6                                            int volatile;
 | |
|     r5                                            int volatile;
 | |
|     r4                                            int volatile;
 | |
|     r3                                            int volatile iret;
 | |
| 
 | |
|     r31                                           int; 
 | |
|     r30                                           int; 
 | |
|     r29                                           int; 
 | |
|     r28                                           int; 
 | |
|     r27                                           int; 
 | |
|     r26                                           int; 
 | |
|     r25                                           int; 
 | |
|     r24                                           int; 
 | |
|     r23                                           int; 
 | |
|     r22                                           int; 
 | |
|     r21                                           int; 
 | |
|     r20                                           int; 
 | |
|     r19                                           int; 
 | |
|     r18                                           int; 
 | |
|     r17                                           int; 
 | |
|     r16                                           int;
 | |
|     r15                                           int;
 | |
|     r14                                           int;
 | |
|     r13                                           int;
 | |
| 
 | |
|     r11r12  named("r11", "r12") aliases(r11, r12) long volatile;
 | |
|     r9r10   named("r9",  "r10") aliases(r9,  r10) long volatile;
 | |
|     r7r8    named("r7",  "r8")  aliases(r7,  r8)  long volatile;
 | |
|     r5r6    named("r5",  "r6")  aliases(r6,  r6)  long volatile;
 | |
|     r3r4    named("r3",  "r4")  aliases(r3,  r4)  long volatile lret;
 | |
| 
 | |
|     r29r30  named("r29", "r30") aliases(r29, r30) long;
 | |
|     r27r28  named("r27", "r28") aliases(r27, r28) long;
 | |
|     r25r26  named("r25", "r26") aliases(r25, r26) long;
 | |
|     r23r24  named("r23", "r24") aliases(r23, r24) long;
 | |
|     r21r22  named("r21", "r22") aliases(r21, r22) long;
 | |
|     r19r20  named("r19", "r20") aliases(r19, r20) long;
 | |
|     r17r18  named("r17", "r18") aliases(r17, r18) long;
 | |
|     r15r16  named("r15", "r16") aliases(r15, r16) long;
 | |
|     r13r14  named("r13", "r14") aliases(r13, r14) long;
 | |
| 
 | |
|     f14                                           float volatile;
 | |
|     f13                                           float volatile;
 | |
|     f12                                           float volatile;
 | |
|     f11                                           float volatile;
 | |
|     f10                                           float volatile;
 | |
|     f9                                            float volatile;
 | |
|     f8                                            float volatile;
 | |
|     f7                                            float volatile;
 | |
|     f6                                            float volatile;
 | |
|     f5                                            float volatile;
 | |
|     f4                                            float volatile;
 | |
|     f3                                            float volatile fret;
 | |
|     f2                                            float volatile;
 | |
|     f1                                            float volatile;
 | |
|     f0                                            float volatile;
 | |
| 
 | |
|     f31                                           float;
 | |
|     f30                                           float;
 | |
|     f29                                           float;
 | |
|     f28                                           float;
 | |
|     f27                                           float;
 | |
|     f26                                           float;
 | |
|     f25                                           float;
 | |
|     f24                                           float;
 | |
|     f23                                           float;
 | |
|     f22                                           float;
 | |
|     f21                                           float;
 | |
|     f20                                           float;
 | |
|     f19                                           float;
 | |
|     f18                                           float;
 | |
|     f17                                           float;
 | |
|     f16                                           float;
 | |
|     f15                                           float;
 | |
| 
 | |
|     d14     named("f14")       aliases(f14)       double volatile;
 | |
|     d13     named("f13")       aliases(f13)       double volatile;
 | |
|     d12     named("f12")       aliases(f12)       double volatile;
 | |
|     d11     named("f11")       aliases(f11)       double volatile;
 | |
|     d10     named("f10")       aliases(f10)       double volatile;
 | |
|     d9      named("f9")        aliases(f9)        double volatile;
 | |
|     d8      named("f8")        aliases(f8)        double volatile;
 | |
|     d7      named("f7")        aliases(f7)        double volatile;
 | |
|     d6      named("f6")        aliases(f6)        double volatile;
 | |
|     d5      named("f5")        aliases(f5)        double volatile;
 | |
|     d4      named("f4")        aliases(f4)        double volatile;
 | |
|     d3      named("f3")        aliases(f3)        double volatile dret;
 | |
|     d2      named("f2")        aliases(f2)        double volatile;
 | |
|     d1      named("f1")        aliases(f1)        double volatile;
 | |
|     d0      named("f0")        aliases(f0)        double volatile;
 | |
| 
 | |
|     d31     named("f31")       aliases(f31)       double;
 | |
|     d30     named("f30")       aliases(f30)       double;
 | |
|     d29     named("f29")       aliases(f29)       double;
 | |
|     d28     named("f28")       aliases(f28)       double;
 | |
|     d27     named("f27")       aliases(f27)       double;
 | |
|     d26     named("f26")       aliases(f26)       double;
 | |
|     d25     named("f25")       aliases(f25)       double;
 | |
|     d24     named("f24")       aliases(f24)       double;
 | |
|     d23     named("f23")       aliases(f23)       double;
 | |
|     d22     named("f22")       aliases(f22)       double;
 | |
|     d21     named("f21")       aliases(f21)       double;
 | |
|     d20     named("f20")       aliases(f20)       double;
 | |
|     d19     named("f19")       aliases(f19)       double;
 | |
|     d18     named("f18")       aliases(f18)       double;
 | |
|     d17     named("f17")       aliases(f17)       double;
 | |
|     d16     named("f16")       aliases(f16)       double;
 | |
|     d15     named("f15")       aliases(f15)       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(BLOCK.I, BLOCK.I);
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Miscellaneous special things */
 | |
| 
 | |
| 	PUSH.I(in:(int)reg)
 | |
| 		emit "stwu %in, -4(sp)"
 | |
| 		cost 4;
 | |
| 
 | |
|     PUSH.L(in:(long)reg)
 | |
|         emit "stwu %in.0, -4(sp)"
 | |
|         emit "stwu %in.1, -4(sp)"
 | |
|         cost 8;
 | |
| 
 | |
|     PUSH.D(in:(double)reg)
 | |
|         emit "stfdu %in, -8(sp)"
 | |
|         cost 4;
 | |
| 
 | |
| 	out:(int)reg = POP.I
 | |
| 		emit "lwz %out, 0(sp)"
 | |
|         emit "addi sp, sp, 4"
 | |
| 		cost 8;
 | |
| 
 | |
|     out:(long)reg = POP.L
 | |
|         emit "lwz %out.0, 4(sp)"
 | |
|         emit "lwz %out.1, 0(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 12;
 | |
| 
 | |
| 	out:(float)reg = POP.F
 | |
| 		emit "lfs %out, 0(sp)"
 | |
| 		emit "addi sp, sp, 4"
 | |
| 		cost 8;
 | |
| 		
 | |
| 	out:(double)reg = POP.D
 | |
| 		emit "lfd %out, 0(sp)"
 | |
| 		emit "addi sp, sp, 8"
 | |
| 		cost 8;
 | |
| 		
 | |
| 	SETRET.I(in:(iret)reg)
 | |
| 		emit "! setret4"
 | |
| 		cost 1;
 | |
| 
 | |
|     SETRET.L(in:(lret)reg)
 | |
|         emit "! setret8"
 | |
|         cost 1;
 | |
| 
 | |
| 	STACKADJUST.I(delta:CONST.I)
 | |
|         when signed_constant(%delta, 16)
 | |
| 		emit "addi sp, sp, $delta"
 | |
| 		cost 4;
 | |
| 
 | |
| 	STACKADJUST.I(in:(int)reg)
 | |
| 		emit "add sp, sp, %in"
 | |
| 		cost 4;
 | |
| 
 | |
| 	STACKADJUST.I(NEG.I(in:(int)reg))
 | |
| 		emit "subf sp, %in, sp"
 | |
| 		cost 4;
 | |
| 
 | |
|     out:(int)reg = GETFP.I
 | |
|         emit "mr %out, fp"
 | |
|         cost 4;
 | |
| 
 | |
|     SETFP.I(in:(int)reg)
 | |
|         emit "mr fp, %in"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = CHAINFP.I(in:(int)reg)
 | |
|         emit "lwz %out, 0(%in)"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FPTOAB.I(GETFP.I)
 | |
|         emit "addi %out, fp, 8"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FPTOAB.I(in:(int)reg)
 | |
|         emit "addi %out, %in, 8"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FPTOLB.I(in:(int)reg)
 | |
|         with %out == %in
 | |
|         cost 1;
 | |
| 
 | |
|     out:(int)reg = GETSP.I
 | |
|         emit "mr %out, sp"
 | |
|         cost 4;
 | |
| 
 | |
|     SETSP.I(in:(int)reg)
 | |
|         emit "mr sp, %in"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = ANY.I
 | |
|         cost 1;
 | |
| 
 | |
|     out:(long)reg = ANY.L
 | |
|         cost 1;
 | |
| 
 | |
|     out:(int)reg = COPYF.I(in:(float)reg)
 | |
|         emit "stfsu %in, -4(sp)"
 | |
|         emit "lwz %out, 0(sp)"
 | |
|         emit "addi sp, sp, 4"
 | |
|         cost 12;
 | |
| 
 | |
|     out:(double)reg = COPYL.D(in:(long)reg)
 | |
|         emit "stwu %in.0, -4(sp)"
 | |
|         emit "stwu %in.1, -4(sp)"
 | |
|         emit "lfd %out, 0(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 16;
 | |
| 
 | |
|     out:(long)reg = COPYD.L(in:(double)reg)
 | |
|         emit "stfdu %in, -8(sp)"
 | |
|         emit "lwz %out.0, 4(sp)"
 | |
|         emit "lwz %out.1, 0(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 16;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Memory operations */
 | |
| 
 | |
|     /* Stores */
 | |
| 
 | |
| 	STORE.D(addr:address, value:(double)reg)
 | |
|         emit "stfd %value, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
| 	STORE.L(addr:address, value:(long)reg)
 | |
| 		emit "stw %value.0, 4+%addr"
 | |
| 		emit "stw %value.1, 0+%addr"
 | |
| 		cost 8;
 | |
| 
 | |
| 	STORE.I(addr:address, value:(int)reg)
 | |
| 		emit "stw %value, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
| 	STOREH.I(addr:address, value:(int)ushortX)
 | |
| 		emit "sth %value, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
|     STOREH.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ushortX)
 | |
|         emit "sthx %value, %left, %right"
 | |
|         cost 4;
 | |
| 
 | |
| 	STOREB.I(addr:address, value:(int)ushortX)
 | |
| 		emit "sth %value, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
|     STOREB.I(addr:address, value:(int)ubyteX)
 | |
| 		emit "stb %value, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
|     STOREB.I(ADD.I(left:(int)reg, right:(int)reg), value:(int)ubyteX)
 | |
|         emit "stbx %value, %left, %right"
 | |
|         cost 4;
 | |
| 
 | |
|     /* Loads */
 | |
| 
 | |
| 	out:(int)reg = LOAD.I(addr:address)
 | |
| 		emit "lwz %out, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
| #if 0
 | |
|     /* FIXME: Doesn't work because %out.0 and %addr might share a
 | |
|      * register, so it corrupts %addr before it loads %out.1. */
 | |
|     out:(long)reg = LOAD.L(addr:address)
 | |
|         emit "lwz %out.0, 4+%addr"
 | |
|         emit "lwz %out.1, 0+%addr"
 | |
|         cost 8;
 | |
| #else
 | |
|     /* Works, but costs an extra instruction. */
 | |
|     out:(long)reg = LOAD.L(addr:address)
 | |
|         emit "la %out.1, %addr"
 | |
|         emit "lwz %out.0, 4(%out.1)"
 | |
|         emit "lwz %out.1, 0(%out.1)"
 | |
|         cost 12;
 | |
| #endif
 | |
| 
 | |
| 	out:(int)ushort0 = LOADH.I(addr:address)
 | |
| 		emit "lhz %out, %addr"
 | |
| 		cost 4;
 | |
| 
 | |
| 	out:(int)ubyte0 = LOADB.I(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;
 | |
| 
 | |
| 
 | |
| /* Extensions and conversions */
 | |
| 
 | |
|     out:(int)reg = EXTENDB.I(in:(int)reg)
 | |
|         emit "extsb %out, %in"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = EXTENDH.I(in:(int)reg)
 | |
|         emit "extsh %out, %in"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FROMSI.I(in:(int)reg)
 | |
|         with %out == %in
 | |
|         emit "! FROMSI.I(int) -> int"
 | |
|         cost 1;
 | |
| 
 | |
|     out:(int)reg = FROMUI.I(in:(int)reg)
 | |
|         with %out == %in
 | |
|         emit "! FROMUI.I(int) -> int"
 | |
|         cost 1;
 | |
| 
 | |
|     out:(long)reg = FROMSI.L(in:(int)reg)
 | |
|         emit "mr %out.0, %in"
 | |
|         emit "srawi %out.1, %out.0, 31"
 | |
|         cost 8;
 | |
| 
 | |
|     out:(long)reg = FROMUI.L(in:(int)reg)
 | |
|         emit "mr %out.0, %in"
 | |
|         emit "li32 %out.1, 0"
 | |
|         cost 8;
 | |
| 
 | |
|     out:(iret)reg = FROMSF.I(in:(dret)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "bl .fromf2i"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FROMSD.I(in:(double)reg)
 | |
|         with preserved(%in)
 | |
|         emit "fctiwz %in, %in"
 | |
|         emit "stfdu %in, -8(sp)"
 | |
|         emit "lwz %out, 4(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 16;
 | |
| 
 | |
|     out:(int)reg = FROMUD.I(in:(double)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "stfdu %in, -8(sp)"
 | |
|         emit "bl .cfu8"
 | |
|         emit "lwz %out, 0(sp)"
 | |
|         emit "addi sp, sp, 4"
 | |
|         cost 16;
 | |
| 
 | |
|     out:(lret)reg = FROMSF.L(in:(fret)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "bl .fromf2l"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(lret)reg = FROMUF.I(in:(fret)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "bl .fromf2l"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(double)reg = FROMSI.D(in:(int)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "stwu %in, -4(sp)"
 | |
|         emit "bl .cif8"
 | |
|         emit "lfd %out, 0(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(fret)reg = FROMUI.F(in:(iret)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "bl .fromui2f"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(double)reg = FROMUI.D(in:(int)reg)
 | |
|         with corrupted(volatile)
 | |
|         emit "stwu %in, -4(sp)"
 | |
|         emit "bl .cuf8"
 | |
|         emit "lfd %out, 0(sp)"
 | |
|         emit "addi sp, sp, 8"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg)
 | |
|         emit "mr %out.0, %in1"
 | |
|         emit "mr %out.1, %in2"
 | |
|         cost 8;
 | |
|     
 | |
|     out:(int)reg = FROML0.I(in:(long)reg)
 | |
|         emit "mr %out, %in.0"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = FROML1.I(in:(long)reg)
 | |
|         emit "mr %out, %in.1"
 | |
|         cost 4;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Locals */
 | |
| 
 | |
| 	out:(int)reg = in:LOCAL.I
 | |
| 		emit "addi %out, fp, $in"
 | |
| 		cost 4;
 | |
| 
 | |
| 	address = in:LOCAL.I
 | |
| 		emit "$in(fp)";
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Memory addressing modes */
 | |
| 
 | |
| 	address = ADD.I(addr:(int)reg, offset:CONST.I)
 | |
|         when signed_constant(%offset, 16)
 | |
| 		emit "$offset(%addr)";
 | |
| 
 | |
| 	address = addr:(int)reg
 | |
| 		emit "0(%addr)";
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Branches */
 | |
| 
 | |
| 	JUMP(addr:BLOCK.I)
 | |
| 		emit "b $addr"
 | |
| 		cost 4;
 | |
| 
 | |
| 	FARJUMP(addr:LABEL.I)
 | |
|         with corrupted(volatile)
 | |
| 		emit "b $addr"
 | |
| 		cost 4;
 | |
| 
 | |
|     JUMP(dest:(int)reg)
 | |
|         emit "mtspr ctr, %dest"
 | |
|         emit "bcctrl 20, 0, 0"
 | |
|         cost 8;
 | |
| 
 | |
| 	CJUMPEQ(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I))
 | |
|         emit "bc 12, 2, $true" /* IFTRUE EQ */
 | |
| 		emit "b $false"
 | |
| 		cost 8;
 | |
| 
 | |
| 	CJUMPLE(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I))
 | |
|         emit "bc 4, 1, $true" /* IFFALSE GT */
 | |
|         emit "b $false"
 | |
| 		cost 8;
 | |
| 
 | |
| 	CJUMPLT(value:(cr)cr, PAIR(true:BLOCK.I, false:BLOCK.I))
 | |
|         emit "bc 12, 0, $true" /* IFTRUE LT */
 | |
|         emit "b $false"
 | |
| 		cost 8;
 | |
| 
 | |
|     #define CALLLABEL(insn) \
 | |
|         insn (dest:LABEL.I) \
 | |
|             with corrupted(volatile) \
 | |
|             emit "bl $dest" \
 | |
|             cost 4;
 | |
| 
 | |
|     CALLLABEL(CALL)
 | |
|     out:(iret)reg = CALLLABEL(CALL.I)
 | |
|     out:(lret)reg = CALLLABEL(CALL.L)
 | |
| 
 | |
|     #define CALLINDIRECT(insn) \
 | |
|         insn (dest:(int)reg) \
 | |
|             with corrupted(volatile) \
 | |
|             emit "mtspr ctr, %dest" \
 | |
|             emit "bcctrl 20, 0, 0" \
 | |
|             cost 8;
 | |
| 
 | |
|     CALLINDIRECT(CALL)
 | |
|     out:(iret)reg = CALLINDIRECT(CALL.I)
 | |
|     out:(lret)reg = CALLINDIRECT(CALL.L)
 | |
| 
 | |
|     JUMP(dest:LABEL.I)
 | |
|         emit "b $dest"
 | |
|         cost 4;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Comparisons */
 | |
| 
 | |
| 	cr:(cr)cr = COMPARESI.I(left:(int)reg, right:(int)reg)
 | |
|         emit "cmp %cr, 0, %left, %right"
 | |
| 		cost 4;
 | |
| 
 | |
| 	cr:(cr)cr = COMPARESI.I(left:(int)reg, right:CONST.I)
 | |
|         when signed_constant(%right, 16)
 | |
|         emit "cmpi %cr, 0, %left, $right"
 | |
| 		cost 4;
 | |
| 
 | |
| 	cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:(int)reg)
 | |
|         emit "cmpl %cr, 0, %left, %right"
 | |
| 		cost 4;
 | |
| 
 | |
| 	cr:(cr)cr = COMPAREUI.I(left:(int)reg, right:CONST.I)
 | |
|         when signed_constant(%right, 16)
 | |
|         emit "cmpli %cr, 0, %left, $right"
 | |
| 		cost 4;
 | |
| 
 | |
|     out:(cr)cr = COMPARESI.I(in:(cr)cr, result:CONST.I)
 | |
|         when specific_constant(%result, 0)
 | |
|         with %out == %in
 | |
|         emit "! COMPARESI.I(cr, 0)"
 | |
|         cost 4;
 | |
| 
 | |
|     cr:(cr)cr = COMPAREUL.I(left:(long)reg, right:(long)reg)
 | |
|         emit "cmpl %cr, 0, %left.1, %right.1"
 | |
|         emit "bne 1f"
 | |
|         emit "cmpl %cr, 0, %left.0, %right.0"
 | |
|         emit "1:"
 | |
|         cost 12;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Booleans */
 | |
| 
 | |
|     out:(int)reg = IFEQ.I(in:(cr)cr)
 | |
|         emit "mfcr %out" /* get cr0 */
 | |
|         emit "rlwinm %out, %out, 3, 31, 31"      /* extract just EQ */
 | |
|         cost 8;
 | |
| 
 | |
| #if 0
 | |
|     out:(int)reg = IFEQ.I(in:(int)reg)
 | |
|         emit "cntlzw %out, %in" /* returns 0..32 */
 | |
|         emit "rlwinm %out, %out, [32-5], 31, 31" /* if 32, return 1, otherwise 0 */
 | |
|         cost 8;
 | |
| #endif
 | |
| 
 | |
|     out:(int)reg = IFLT.I(in:(cr)cr)
 | |
|         emit "mfcr %out" /* get cr0 */
 | |
|         emit "rlwinm %out, %out, 1, 31, 31"     /* leave just LT */
 | |
|         cost 8;
 | |
| 
 | |
|     out:(int)reg = IFLE.I(in:(cr)cr)
 | |
|         emit "mfcr %out"                        /* get cr0 */
 | |
|         emit "rlwinm %out, %out, 2, 31, 31"     /* leave just GT */
 | |
|         emit "xori %out, %out, 1"               /* negate */
 | |
|         cost 12;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Conversions */
 | |
| 
 | |
| #if 0
 | |
|     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;
 | |
| #endif
 | |
| 
 | |
| /* ALU operations */
 | |
| 
 | |
|     #define ALUR(name, instr) \
 | |
|         out:(int)reg = name(left:(int)reg, right:(int)reg) \
 | |
|             emit instr " %out, %left, %right"              \
 | |
|             cost 4;                                        \
 | |
| 
 | |
|     #define ALUC(name, instr) \
 | |
|         out:(int)reg = name(left:(int)reg, right:CONST.I)  \
 | |
|             when signed_constant(%right, 16)               \
 | |
|             emit instr " %out, %left, $right"              \
 | |
|             cost 4;                                        \
 | |
| 
 | |
|     #define ALUC_reversed(name, instr) \
 | |
|         out:(int)reg = name(left:CONST.I, right:(int)reg)  \
 | |
|             when signed_constant(%left, 16)                \
 | |
|             emit instr " %out, %right, $left"              \
 | |
|             cost 4;                                        \
 | |
| 
 | |
|     #define ALUCC(name, instr) \
 | |
|         ALUC(name, instr) \
 | |
|         ALUC_reversed(name, instr)
 | |
| 
 | |
|     ALUR(ADD.I, "add")
 | |
|     ALUCC(ADD.I, "addi")
 | |
| 
 | |
| 	out:(int)reg = SUB.I(left:(int)reg, right:(int)reg)
 | |
| 		emit "subf %out, %right, %left"
 | |
| 		cost 4;
 | |
| 
 | |
| 	out:(int)reg = SUB.I(left:(int)reg, right:CONST.I)
 | |
| 		emit "addi %out, %left, -[$right]"
 | |
| 		cost 4;
 | |
| 
 | |
| 	out:(int)reg = MOD.I(left:(int)reg, right:(int)reg)
 | |
|         with preserved(%left), preserved(%right)
 | |
| 		emit "divw %out, %left, %right"
 | |
|         emit "mullw %out, %out, %right"
 | |
|         emit "subf %out, %out, %left"
 | |
| 		cost 12;
 | |
| 
 | |
| 	out:(int)reg = MODU.I(left:(int)reg, right:(int)reg)
 | |
|         with preserved(%left), preserved(%right)
 | |
| 		emit "divwu %out, %left, %right"
 | |
|         emit "mullw %out, %out, %right"
 | |
|         emit "subf %out, %out, %left"
 | |
| 		cost 12;
 | |
| 
 | |
|     ALUR(MUL.I, "mullw")
 | |
|     ALUCC(MUL.I, "mulli")
 | |
| 
 | |
|     ALUR(DIV.I, "divw")
 | |
|     ALUR(DIVU.I, "divwu")
 | |
| 
 | |
|     ALUR(ASL.I, "slw")
 | |
|     ALUR(ASR.I, "sraw")
 | |
| 
 | |
|     ALUR(LSL.I, "slw")
 | |
|     ALUR(LSR.I, "srw")
 | |
| 
 | |
|     out:(int)reg = NEG.I(left:(int)reg)
 | |
|         emit "neg %out, %left"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(int)reg = NOT.I(in:(int)reg)
 | |
|         emit "nor %out, %in, %in"
 | |
|         cost 4;
 | |
| 
 | |
|     ALUR(AND.I, "and")
 | |
|     ALUCC(AND.I, "andi.")
 | |
| 
 | |
|     ALUR(OR.I, "or")
 | |
|     ALUCC(OR.I, "ori")
 | |
| 
 | |
|     ALUR(EOR.I, "xor")
 | |
|     ALUCC(EOR.I, "xori")
 | |
| 
 | |
| 	out:(int)reg = value:LABEL.I
 | |
| 		emit "li32 %out, $value"
 | |
| 		cost 4;
 | |
| 
 | |
| 	out:(int)reg = value:BLOCK.I
 | |
| 		emit "li32 %out, $value"
 | |
| 		cost 4;
 | |
| 
 | |
| 	out:(int)reg = value:CONST.I
 | |
| 		emit "li32 %out, $value"
 | |
| 		cost 8;
 | |
| 
 | |
| 
 | |
| /* FPU operations */
 | |
| 
 | |
|     #define FPU4R(name, instr) \
 | |
|         out:(float)reg = name(left:(float)reg, right:(float)reg) \
 | |
|             emit instr " %out, %left, %right"                    \
 | |
|             cost 4;                                              \
 | |
| 
 | |
|     #define FPU8R(name, instr) \
 | |
|         out:(double)reg = name(left:(double)reg, right:(double)reg) \
 | |
|             emit instr " %out, %left, %right"                       \
 | |
|             cost 4;                                                 \
 | |
| 
 | |
|     out:(float)reg = LOAD.F(addr:address)
 | |
|         emit "lfs %out, %addr"
 | |
|         cost 4;
 | |
|         
 | |
|     out:(double)reg = LOAD.D(addr:address)
 | |
|         emit "lfd %out, %addr"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(float)reg = in:CONST.F
 | |
|         when specific_constant(%in, 0)
 | |
|         emit "li32 r0, .fd_00000000"
 | |
|         emit "lfs %out, 0(r0)"
 | |
|         cost 12;
 | |
| 
 | |
|     FPU4R(ADDF.F, "fadds")
 | |
|     FPU8R(ADDF.D, "fadd")
 | |
| 
 | |
|     FPU4R(SUBF.F, "fsubs")
 | |
|     FPU8R(SUBF.D, "fsub")
 | |
| 
 | |
|     FPU4R(MULF.F, "fmuls")
 | |
|     FPU8R(MULF.D, "fmul")
 | |
| 
 | |
|     FPU4R(DIVF.F, "fdivs")
 | |
|     FPU8R(DIVF.D, "fdiv")
 | |
| 
 | |
|     #define FMALEFT(type, insn, add, mul) \
 | |
|         out:(type)reg = add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg) \
 | |
|         emit insn " %out, %m1, %m2, %m3"                                   \
 | |
|         cost 4;                                                            \
 | |
|                                                                                  
 | |
|     #define FMARIGHT(type, insn, add, mul) \
 | |
|         out:(type)reg = add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg)) \
 | |
|         emit insn " %out, %m1, %m2, %m3"                                   \
 | |
|         cost 4;                                                            \
 | |
| 
 | |
|     FMALEFT( double, "fmadd",   ADDF.D, MULF.D)
 | |
|     FMARIGHT(double, "fmadd",   ADDF.D, MULF.D)
 | |
|     FMALEFT( float,  "fmadds",  ADDF.F, MULF.F)
 | |
|     FMARIGHT(float,  "fmadds",  ADDF.F, MULF.F)
 | |
| 
 | |
|     FMALEFT( double, "fmsub",   SUBF.D, MULF.D)
 | |
|     FMALEFT( float,  "fmsubs",  SUBF.F, MULF.F)
 | |
| 
 | |
|     FMARIGHT(double, "fnmadd",  SUBF.D, MULF.D)
 | |
|     FMARIGHT(float,  "fnmadds", SUBF.F, MULF.F)
 | |
| 
 | |
|     #define FMANEGLEFT(type, insn, neg, add, mul) \
 | |
|         out:(type)reg = neg(add(mul(m1:(type)reg, m2:(type)reg), m3:(type)reg)) \
 | |
|         emit insn " %out, %m1, %m2, %m3"                                        \
 | |
|         cost 4;                                                                 \
 | |
|                                                                                  
 | |
|     #define FMANEGRIGHT(type, insn, neg, add, mul) \
 | |
|         out:(type)reg = neg(add(m3:(type)reg, mul(m1:(type)reg, m2:(type)reg))) \
 | |
|         emit insn " %out, %m1, %m2, %m3"                                        \
 | |
|         cost 4;                                                                 \
 | |
| 
 | |
|     FMANEGLEFT( double, "fnmsub", NEGF.D, ADDF.D, MULF.D)
 | |
|     FMANEGRIGHT(double, "fnmsub", NEGF.D, ADDF.D, MULF.D)
 | |
|     FMANEGLEFT( float,  "fnmsub", NEGF.F, ADDF.F, MULF.F)
 | |
|     FMANEGRIGHT(float,  "fnmsub", NEGF.F, ADDF.F, MULF.F)
 | |
| 
 | |
|     out:(float)reg = NEGF.F(left:(float)reg)
 | |
|         emit "fneg %out, %left"
 | |
|         cost 4;
 | |
| 
 | |
|     out:(double)reg = NEGF.D(left:(double)reg)
 | |
|         emit "fneg %out, %left"
 | |
|         cost 4;
 | |
| 
 | |
| 	cr:(cr)cr = COMPAREF.I(left:(float)reg, right:(float)reg)
 | |
|         emit "fcmpu %cr, %left, %right"
 | |
| 		cost 4;
 | |
| 
 | |
| 	cr:(cr)cr = COMPARED.I(left:(double)reg, right:(double)reg)
 | |
|         emit "fcmpu %cr, %left, %right"
 | |
| 		cost 4;
 | |
| 
 | |
| /* vim: set sw=4 ts=4 expandtab : */
 | |
| 
 |