/* Superoptimizer. Finds the shortest instruction sequences for an arbitrary function f(x,y) where x and y are integers. The algorithm is based on exhaustive search with backtracking and iterative deepening. Copyright (C) 1991, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "superopt.h" #include "run_program.def" #include "version.h" int goal_function_arity; enum goal_func goal_function; word (*eval_goal_function) (const word *); int flag_output_assembler = 0; int flag_use_carry = 1; /* Counts the number of solutions found. Flags to top loop that it should not go deeper. */ int success; #ifdef TIMING #ifndef USG #include #include unsigned long cputime () { struct rusage rus; getrusage (0, &rus); return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; } #else #include unsigned long cputime () { return clock () / 1000; } #endif int timings[100]; #endif #ifdef STATISTICS unsigned int heuristic_reject_count = 0; unsigned int heuristic_accept_count = 0; #endif char *insn_name[] = { #undef DEF_INSN #define DEF_INSN(SYM,CLASS,NAME) NAME, #include "insn.def" }; char insn_class[] = { #undef DEF_INSN #define DEF_INSN(SYM,CLASS,NAME) CLASS, #include "insn.def" }; /* Initialize the "immediate" values in the top registers. */ void init_immediates(word *values) { int i; for (i = -1; i < BITS_PER_WORD; i++) values[0x20 + i] = i; values[0x20 - 2] = VALUE_MIN_SIGNED; values[0x20 - 3] = VALUE_MAX_SIGNED; } inline word random_word(void) { #ifdef __hpux return mrand48(); #else /* random returns 31 bits. We need 32. */ return random() ^ (random() << 1); #endif } char * xrealloc (ptr, size) char *ptr; unsigned size; { char *result = (char *) realloc (ptr, size); if (!result) abort (); return result; } char * xmalloc (size) unsigned size; { register char *val = (char *) malloc (size); if (val == 0) abort (); return val; } #define RECURSE(opcode, s1, s2, prune_hint) \ recurse(opcode, n_values, s1, s2, v, 1, sequence, n_insns, values, \ n_values + 1, goal_value, allowed_cost, co, prune_hint) #define CRECURSE_2OP(opcode, d, s1, s2, cost, prune_hint) \ recurse(opcode, d, s1, s2, v, cost, sequence, n_insns, values, \ n_values, goal_value, allowed_cost, co, prune_hint) #define CRECURSE_NEW(opcode, d, s1, s2, cost, prune_hint) \ recurse(opcode, d, s1, s2, v, cost, sequence, n_insns, values, \ n_values + 1, goal_value, allowed_cost, co, prune_hint) /* Save the last generated instruction and recursively call `synth', if we are not at a leaf node. Otherwise test the computed value and back-track. This function is extremely critical for the performance! OPCODE is the opcode of the insn that was just generated. D is the destination register. S1 is the left source register or immediate reference. It is an immediate reference if IMMEDIATE_P(S1) is true. S2 is the right source register or immediate reference. It is an immediate reference if IMMEDIATE_P(S2) is true. V is the computed result from "rD = rS1 OPCODE rS2". COST is the cost of OPCODE with the the actual operands. SEQUENCE is the insn sequence so far, excluding the just generated insn. N_INSNS is the number of insns in SEQUENCE. VALUES contains the values in register 0..N_VALUES. N_VALUES is the number of registers that have been assigned values by the insns so far. GOAL_VALUE is the value we aim at, when the sequence is ready. ALLOWED_COST is the maximum allowed cost of the remaining sequence. CY is the carry flag. It is negative if it has an undefined value (this for pruning the search tree), and otherwise takes the values 0 or 1 according to the conventions of the current target. PRUNE_HINT contains flags to assist pruning of the search tree. */ static inline void recurse(opcode_t opcode, int d, int s1, int s2, word v, int cost, insn_t *sequence, int n_insns, word *values, int n_values, const word goal_value, int allowed_cost, int cy, int prune_flags) { insn_t insn; /* Update the remaining allowed cost with the cost of the last instruction. */ allowed_cost -= cost; if (allowed_cost > 0) { /* ALLOWED_COST is still positive, meaning we can generate more instructions. */ word old_d; old_d = values[d]; /* Remember old value of dest. reg. */ values[d] = v; #if __GNUC__ sequence[n_insns] = (insn_t) {opcode, s1, s2, d}; #else insn.opcode = opcode; insn.s1 = s1; insn.s2 = s2; insn.d = d; sequence[n_insns] = insn; #endif synth(sequence, n_insns + 1, values, n_values, goal_value, allowed_cost, cy, prune_flags); values[d] = old_d; /* Restore value of dest. reg. */ } else if (goal_value == v) { /* We are at a leaf node and got the right answer for the random value operands. However, we probably have an incorrect sequence. Call test_sequence to find out. */ #if __GNUC__ sequence[n_insns] = (insn_t) {opcode, s1, s2, d}; #else insn.opcode = opcode; insn.s1 = s1; insn.s2 = s2; insn.d = d; sequence[n_insns] = insn; #endif test_sequence(sequence, n_insns + 1); #ifdef STATISTICS heuristic_accept_count++; #endif } #ifdef STATISTICS else heuristic_reject_count++; #endif } #define NAME(op) operand_names[op] static char *operand_names[256]= { #if SPARC "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i6", "%i7", #elif RS6000 "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", #elif M88000 "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", #elif AM29K "lr2", "lr3", "lr4", "lr5", "lr6", "lr7", "lr8", "lr9", #elif M68000 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", #elif I386 "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%noooo!", "%crash!!!", #elif PYR "pr0", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", #elif ALPHA "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", #else #error no register names for this CPU #endif 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, #if SPARC "???%hi(0x7fffffff)","%hi(0x80000000)","-1","%g0","1","2","3","4","5","6", "7","8","9","10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29","30","31", #elif RS6000 "0x7fff","0x8000","-1","0","1","2","3","4","5","6", "7","8","9","10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29","30","31", #elif M88000 "hi16(0x7fffffff)","hi16(0x80000000)","-1","r0","1","2","3","4","5","6", "7","8","9","10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29","30","31", #elif AM29K "0x7fff","0x8000","-1","0","1","2","3","4","5","6", "7","8","9","10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29","30","31", #elif M68000 "#0x7fffffff","#0x80000000","#-1","#0","#1","#2","#3","#4","#5","#6", "#7","#8","#9","#10","#11","#12","#13","#14","#15","#16","#17","#18","#19", "#20","#21","#22","#23","#24","#25","#26","#27","#28","#29","#30","#31", #elif I386 "$0x7fffffff","$0x80000000","$-1","$0","$1","$2","$3","$4","$5","$6", "$7","$8","$9","$10","$11","$12","$13","$14","$15","$16","$17","$18","$19", "$20","$21","$22","$23","$24","$25","$26","$27","$28","$29","$30","$31", #elif PYR "$0x7fffffff","$0x80000000","$-1","$0","$1","$2","$3","$4","$5","$6", "$7","$8","$9","$10","$11","$12","$13","$14","$15","$16","$17","$18","$19", "$20","$21","$22","$23","$24","$25","$26","$27","$28","$29","$30","$31", #elif ALPHA "0x7fff","0x8000","-1","$31","1","2","3","4","5","6", "7","8","9","10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29","30","31", "32","33","34","35","36","37","38","39","40","41","42","43", "44","45","46","47","48","49","50","51","52","53","54","55", "56","57","58","59","60","61","62","63", #else #error no constant syntax for this CPU #endif }; /* Output INSN in assembler mnemonic format on stdout. */ void output_assembler(insn_t insn) { int d, s1, s2; d = insn.d; s1 = insn.s1; s2 = insn.s2; printf("\t"); switch (insn.opcode) { #if SPARC case COPY: if (IMMEDIATE_P(s1) && (IMMEDIATE_VAL(s1) & 0x1fff) == 0) printf("sethi %s,%s",NAME(s1),NAME(d)); else printf("mov %s,%s",NAME(s1),NAME(d)); break; case ADD: printf("add %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ADD_CI:printf("addx %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ADD_CO:printf("addcc %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ADD_CIO:printf("addxcc %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SUB: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("xnor %%g0,%s,%s",NAME(s2),NAME(d)); else printf("sub %s,%s,%s",NAME(s1),NAME(s2),NAME(d)); break; case SUB_CI:printf("subx %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SUB_CO:printf("subcc %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SUB_CIO:printf("subxcc %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case AND: printf("and %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case IOR: printf("or %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case XOR: printf("xor %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ANDC: printf("andn %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case IORC: printf("orn %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case EQV: printf("xnor %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case LSHIFTR:printf("srl %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ASHIFTR:printf("sra %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SHIFTL:printf("sll %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; #elif RS6000 case COPY: if (IMMEDIATE_P(s1)) { if (IMMEDIATE_VAL(s1) >= 0 && IMMEDIATE_VAL(s1) < 0x8000) printf("lil %s,0x%x",NAME(d),IMMEDIATE_VAL(s1)); else printf("liu %s,%s",NAME(d),NAME(s1)); } else printf("oril %s,%s,0",NAME(d),NAME(s1)); break; case ADD: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) + 0x4000 < 0x8000) printf("cal %s,%d(%s)",NAME(d),IMMEDIATE_VAL(s2),NAME(s1)); else if ((IMMEDIATE_VAL(s2) & 0xffff) == 0) printf("cau %s,%s,0x%x",NAME(d),NAME(s1),IMMEDIATE_VAL(s2) >> 16); else abort (); } else printf("cax %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ADD_CO: if (IMMEDIATE_P(s2)) printf("ai %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); else printf("a %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ADD_CIO: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == -1) printf("ame %s,%s",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 0) printf("aze %s,%s",NAME(d),NAME(s1)); } else printf("ae %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case SUB: if (IMMEDIATE_P(s1)) { if (IMMEDIATE_VAL(s1) == 0) printf("neg %s,%s",NAME(d),NAME(s2)); else if (IMMEDIATE_VAL(s1) == -1) printf("nand %s,%s,%s",NAME(d),NAME(s2),NAME(s2)); } else abort(); break; case ADC_CO: if (IMMEDIATE_P(s1)) printf("sfi %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); else printf("sf %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); break; case ADC_CIO: if (IMMEDIATE_P(s1)) { if (IMMEDIATE_VAL(s1) == -1) printf("sfme %s,%s",NAME(d),NAME(s2)); else if (IMMEDIATE_VAL(s1) == 0) printf("sfze %s,%s",NAME(d),NAME(s2)); else abort(); } else printf("sfe %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); break; case AND: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == 0x80000000) printf("rlinm %s,%s,0,0,0",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 0x7fffffff) printf("rlinm %s,%s,0,1,31",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 1) printf("rlinm %s,%s,0,31,31",NAME(d),NAME(s1)); else abort(); } else printf("and %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case IOR: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == 0x80000000) printf("oriu %s,%s,0x8000",NAME(d),NAME(s1)); else abort(); } else printf("or %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case XOR: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == 1) printf("xoril\t%s,%s,1",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 0x80000000) printf("xoriu\t%s,%s,0x8000",NAME(d),NAME(s1)); else abort(); } else printf("xor %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ANDC: printf("andc %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case IORC: printf("orc %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case EQV: printf("eqv %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case NAND: printf("nand %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case NOR: printf("nor %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case LSHIFTR: if (IMMEDIATE_P(s2)) printf("sri %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); else printf("sre %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ASHIFTR_CON: if (IMMEDIATE_P(s2)) printf("srai %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); else printf("srea %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case SHIFTL: if (IMMEDIATE_P(s2)) printf("sli %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); else printf("sle %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ROTATEL: if (IMMEDIATE_P(s2)) printf("rlinm %s,%s,%s,0,31",NAME(d),NAME(s1),NAME(s2)); else printf("rlnm %s,%s,%s,0,31",NAME(d),NAME(s1),NAME(s2)); break; case ABSVAL:printf("abs %s,%s",NAME(d),NAME(s1));break; case NABSVAL:printf("nabs %s,%s",NAME(d),NAME(s1));break; case DOZ: if (IMMEDIATE_P(s1)) printf("dozi %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); else printf("doz %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); break; case MUL: if (IMMEDIATE_P(s1)) printf("muli %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); else printf("muls %s,%s,%s",NAME(d),NAME(s2),NAME(s1)); break; case CLZ: printf("cntlz %s,%s",NAME(d),NAME(s1));break; #elif M88000 case COPY: if (IMMEDIATE_P(s1)) { if ((IMMEDIATE_VAL(s1) & 0xffff) == 0) printf("or.u %s,r0,0x%x",NAME(d),IMMEDIATE_VAL(s1)); else if ((IMMEDIATE_VAL(s1) & 0xffff0000) == 0) printf("or %s,r0,0x%x",NAME(d),IMMEDIATE_VAL(s1)); else if ((IMMEDIATE_VAL(s1) & 0xffff0000) == 0xffff0000) printf("subu %s,r0,0x%x",NAME(d),-IMMEDIATE_VAL(s1)); else { word x = IMMEDIATE_VAL(s1); int i, j; for (i = 31; i > 0; i--) if ((x & (1 << i)) != 0) break; for (j = i; j >= 0; j--) if ((x & (1 << j)) == 0) break; printf("set %s,r0,%d<%d>",NAME(d), i - j, j + 1); } } else printf("or %s,%s",NAME(d),NAME(s1)); break; case ADD: printf("addu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADD_CI:printf("addu.ci %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADD_CO:printf("addu.co %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADD_CIO: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == -1) { printf("subu.cio %s,%s,r0",NAME(d),NAME(s1)); break; } if (IMMEDIATE_VAL(s2) != 0) abort(); } printf("addu.cio %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case SUB: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("xor.c %s,%s,r0",NAME(d),NAME(s2)); else printf("subu %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ADC_CI:printf("subu.ci %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADC_CO:printf("subu.co %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADC_CIO:printf("subu.cio %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case AND: if (IMMEDIATE_P(s2)) { if (IMMEDIATE_VAL(s2) == 0x80000000) printf("mask.u %s,%s,0x8000",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 0x7fffffff) printf("and.u %s,%s,0x7fff",NAME(d),NAME(s1)); else if (IMMEDIATE_VAL(s2) == 1) printf("mask %s,%s,1",NAME(d),NAME(s1)); else abort(); } else printf("and %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case IOR: if (IMMEDIATE_P(s2)) { if ((IMMEDIATE_VAL(s2) & 0xffff) == 0) printf("or.u %s,%s,0x%x",NAME(d),NAME(s1), IMMEDIATE_VAL(s2)>>16); else if (IMMEDIATE_VAL(s2) < 0x10000) printf("or %s,%s,0x%x",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); else abort(); } else printf("or %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case XOR: if (IMMEDIATE_P(s2)) { if ((IMMEDIATE_VAL(s2) & 0xffff) == 0) printf("xor.u %s,%s,0x%x",NAME(d),NAME(s1), IMMEDIATE_VAL(s2)>>16); else if (IMMEDIATE_VAL(s2) < 0x10000) printf("xor %s,%s,0x%x",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); else abort(); } else printf("xor %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ANDC: printf("and.c %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case IORC: printf("or.c %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case EQV: printf("xor.c %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case LSHIFTR:printf("extu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ASHIFTR:printf("ext %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case SHIFTL:printf("mak %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ROTATEL: printf("rot %s,%s,%d",NAME(d),NAME(s1),32-IMMEDIATE_VAL(s2)); break; case FF1: printf("ff1 %s,%s",NAME(d),NAME(s1)); break; case FF0: printf("ff0 %s,%s",NAME(d),NAME(s1)); break; case CMPPAR: if (IMMEDIATE_P(s2)) printf("cmp %s,%s,0x%x",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); else if (IMMEDIATE_P(s1)) printf("cmp %s,r0,%s",NAME(d),NAME(s2)); else printf("cmp %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case EXTS1: printf("ext %s,%s,1<%d>",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); break; case EXTS2: printf("ext %s,%s,2<%d>",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); break; case EXTU1: printf("extu %s,%s,1<%d>",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); break; case EXTU2: printf("extu %s,%s,2<%d>",NAME(d),NAME(s1),IMMEDIATE_VAL(s2)); break; case MUL: printf("mul %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; #elif AM29K case COPY: if (IMMEDIATE_P(s1)) { if (IMMEDIATE_VAL(s1) < 0x10000) printf("const %s,0x%x",NAME(d),IMMEDIATE_VAL(s1)); else if (-IMMEDIATE_VAL(s1) < 0x10000) printf("constn %s,-0x%x",NAME(d),-IMMEDIATE_VAL(s1)); else if (IMMEDIATE_VAL(s1) == 0x80000000) printf("cpeq %s,gr1,gr1",NAME(d)); else abort(); } else printf("or %s,%s,0",NAME(d),NAME(s1)); break; case ADD_CO: if (IMMEDIATE_P(s2) && (signed_word) IMMEDIATE_VAL(s2) < 0) printf("sub %s,%s,0x%x",NAME(d),NAME(s1),-IMMEDIATE_VAL(s2)); else printf("add %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case ADD_CIO: if (IMMEDIATE_P(s2) && (signed_word) IMMEDIATE_VAL(s2) < 0) printf("subc %s,%s,0x%x",NAME(d),NAME(s1),-IMMEDIATE_VAL(s2)); else printf("addc %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case SUB: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("nor %s,%s,0",NAME(d),NAME(s2)); else abort(); break; case ADC_CO:printf("sub %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ADC_CIO:printf("subc %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case AND: printf("and %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case IOR: printf("or %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case XOR: printf("xor %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ANDC: printf("andn %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case EQV: printf("xnor %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case NAND: printf("nand %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case NOR: printf("nor %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case LSHIFTR:printf("srl %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case ASHIFTR:printf("sra %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case SHIFTL:printf("sll %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPEQ: printf("cpeq %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPGE: printf("cpge %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPGEU: printf("cpgeu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPGT: printf("cpgt %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPGTU: printf("cpgtu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPLE: printf("cple %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPLEU: printf("cpleu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPLT: printf("cplt %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPLTU: printf("cpltu %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case CPNEQ: printf("cpneq %s,%s,%s",NAME(d),NAME(s1),NAME(s2));break; case MUL: printf("multiply %s,%s,%s",NAME(d),NAME(s1),NAME(s2)); break; case CLZ: printf("clz %s,%s",NAME(d),NAME(s1));break; #elif M68000 case COPY: if (IMMEDIATE_P(s1)) { if ((signed_word) IMMEDIATE_VAL(s1) >= -128 && (signed_word) IMMEDIATE_VAL(s1) < 128) { printf("moveq #%ld,%s", IMMEDIATE_VAL(s1),NAME(d)); break; } } printf("movel %s,%s",NAME(s1),NAME(d)); break; case EXCHANGE: printf("exgl %s,%s",NAME(s2),NAME(d));break; case ADD_CO: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) >= 1 && IMMEDIATE_VAL(s2) <= 8) printf("addql %s,%s",NAME(s2),NAME(d)); else printf("addl %s,%s",NAME(s2),NAME(d)); break; case ADD_CIO: printf("addxl %s,%s",NAME(s2),NAME(d));break; case SUB: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("notl %s",NAME(d)); else abort(); break; case SUB_CO: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == 0) printf("negl %s",NAME(d)); else if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) >= 1 && IMMEDIATE_VAL(s2) <= 8) printf("subql %s,%s",NAME(s2),NAME(d)); else printf("subl %s,%s",NAME(s2),NAME(d)); break; case SUB_CIO: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == 0) printf("negxl %s",NAME(d)); else printf("subxl %s,%s",NAME(s2),NAME(d)); break; case AND: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x8000 < 0x10000) printf("andw %s,%s",NAME(s2),NAME(d)); else printf("andl %s,%s",NAME(s2),NAME(d)); break; case IOR: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x8000 < 0x10000) printf("orw %s,%s",NAME(s2),NAME(d)); else printf("orl %s,%s",NAME(s2),NAME(d)); break; case XOR: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x8000 < 0x10000) printf("eorw %s,%s",NAME(s2),NAME(d)); else printf("eorl %s,%s",NAME(s2),NAME(d)); break; case LSHIFTR_CO: printf("lsrl %s,%s",NAME(s2),NAME(d));break; case ASHIFTR_CO: printf("asrl %s,%s",NAME(s2),NAME(d));break; case SHIFTL_CO: printf("lsll %s,%s",NAME(s2),NAME(d));break; case ROTATEL_CO: printf("roll %s,%s",NAME(s2),NAME(d));break; case ROTATEXL_CIO: printf("roxll %s,%s",NAME(s2),NAME(d));break; case MUL: printf("mulsl %s,%s",NAME(s2),NAME(d));break; #elif I386 case COPY: printf("movl %s,%s",NAME(s1),NAME(d));break; case EXCHANGE: printf("xchgl %s,%s",NAME(s2),NAME(d));break; case ADD: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) == 1) printf("incl %s",NAME(d)); else abort(); break; case ADD_CO: printf("addl %s,%s",NAME(s2),NAME(d));break; case ADD_CIO: printf("adcl %s,%s",NAME(s2),NAME(d));break; case SUB: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) == 1) printf("decl %s",NAME(d)); else if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("notl %s",NAME(d)); else abort(); break; case SUB_CO: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == 0) printf("negl %s",NAME(d)); else printf("subl %s,%s",NAME(s2),NAME(d)); break; case SUB_CIO: printf("sbbl %s,%s",NAME(s2),NAME(d));break; case CMP: printf("cmpl %s,%s",NAME(s2),NAME(s1));break; case AND_RC: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x80 < 0x100) printf("andb $%d,%s",IMMEDIATE_VAL(s2),NAME(d)); else printf("andl %s,%s",NAME(s2),NAME(d)); break; case IOR_RC: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x80 < 0x100) printf("orb $%d,%s",IMMEDIATE_VAL(s2),NAME(d)); else printf("orl %s,%s",NAME(s2),NAME(d)); break; case XOR_RC: if (IMMEDIATE_P(s2) && IMMEDIATE_VAL(s2) + 0x80 < 0x100) printf("xorb $%d,%s",IMMEDIATE_VAL(s2),NAME(d)); else printf("xorl %s,%s",NAME(s2),NAME(d)); break; case LSHIFTR_CO: printf("shrl %s,%s",NAME(s2),NAME(d));break; case ASHIFTR_CO: printf("sarl %s,%s",NAME(s2),NAME(d));break; case SHIFTL_CO: printf("shll %s,%s",NAME(s2),NAME(d));break; case ROTATEL_CO: printf("roll %s,%s",NAME(s2),NAME(d));break; case ROTATEXL_CIO: printf("rlcl %s,%s",NAME(s2),NAME(d));break; case COMCY: printf("cmc");break; case MUL: printf("imull %s,%s",NAME(s2),NAME(d));break; #elif PYR case COPY: printf("movw %s,%s",NAME(s1),NAME(d));break; case EXCHANGE: printf("xchw %s,%s",NAME(s2),NAME(d));break; case ADD: printf("mova 0x%x(%s),%s",IMMEDIATE_VAL(s2),NAME(s1),NAME(d)); break; case ADD_CO: printf("addw %s,%s",NAME(s2),NAME(d));break; case ADD_CIO: printf("addwc %s,%s",NAME(s2),NAME(d));break; case ADC_CO: printf("subw %s,%s",NAME(s2),NAME(d));break; case ADC_CIO: printf("subwb %s,%s",NAME(s2),NAME(d));break; case AND_CC: printf("andw %s,%s",NAME(s2),NAME(d));break; case IOR_CC: printf("orw %s,%s",NAME(s2),NAME(d));break; case XOR_CC: printf("xorw %s,%s",NAME(s2),NAME(d)); break; case ANDC_CC: printf("bicw %s,%s",NAME(s2),NAME(d)); break; case LSHIFTR_CO: printf("lshrw %s,%s",NAME(s2),NAME(d));break; case ASHIFTR_CO: printf("ashrw %s,%s",NAME(s2),NAME(d));break; case SHIFTL_CO: printf("lshlw %s,%s",NAME(s2),NAME(d));break; case MUL: printf("mulw %s,%s",NAME(s2),NAME(d));break; #elif ALPHA case ADD: printf("addq %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SUB: if (IMMEDIATE_P(s1) && IMMEDIATE_VAL(s1) == -1) printf("ornot $31,%s,%s",NAME(s2),NAME(d)); else printf("subq %s,%s,%s",NAME(s1),NAME(s2),NAME(d)); break; case AND: printf("and %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case IOR: printf("bis %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case XOR: printf("xor %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ANDC: printf("bic %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case IORC: printf("ornot %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case EQV: printf("eqv %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case LSHIFTR:printf("srl %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case ASHIFTR:printf("sra %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case SHIFTL:printf("sll %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMPEQ: printf("cmpeq %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMPLE: printf("cmple %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMPLEU:printf("cmpleu %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMPLT: printf("cmplt %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMPLTU:printf("cmpltu %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVEQ:printf("cmoveq %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVNE:printf("cmovne %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVLT:printf("cmovlt %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVGE:printf("cmovge %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVLE:printf("cmovle %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; case CMOVGT:printf("cmovgt %s,%s,%s",NAME(s1),NAME(s2),NAME(d));break; #else #error no assembler output code for this CPU #endif default:abort(); } printf("\n"); } word tvalues[0x100]; /* TEST_SETS contains sets of input values and corresponding goal value used to test the correctness of a sequence. N_TEST_SETS says how many sets are defined. */ word *test_sets; int n_test_sets; word test_operands[] = { 0, 1, -1, -2, VALUE_MIN_SIGNED, VALUE_MAX_SIGNED, VALUE_MIN_SIGNED + 1, VALUE_MAX_SIGNED - 1, }; #define N_TEST_OPERANDS (sizeof(test_operands)/sizeof(test_operands[0])) void init_test_sets() { unsigned int loop_vars[8]; int pc, i, j; word *test_set; const int arity = goal_function_arity; word (*eval) (const word *) = eval_goal_function; if (sizeof (loop_vars) / sizeof (loop_vars[0]) <= arity) abort (); /* Allocate enough space in TEST_SETS for all combinations of TEST_OPERANDS and an additional 10,000 random test sets. */ { static int n_words; j = 1 + arity; for (i = arity - 1; i >= 0; i--) j *= N_TEST_OPERANDS; j += (1 + arity) * 10000; if (n_words < j) { test_sets = (n_words == 0 ? (word *) xmalloc (sizeof (word) * j) : (word *) xrealloc (test_sets, sizeof (word) * j)); n_words = j; } } test_set = test_sets; j = 0; /* Start with all combinations of operands from TEST_OPERANDS. */ for (i = arity - 1; i >= 0; i--) loop_vars[i] = 0; for (;;) { for (i = arity - 1; i >= 0; i--) tvalues[i] = *test_set++ = test_operands[loop_vars[i]]; /* Get the desired value for the current operand values. */ *test_set++ = (*eval)(tvalues); j++; /* General loop control. This implements ARITY loops using induction variables in loop_vars[0] through loop_vars[ARITY - 1]. */ i = 0; loop_vars[i] = (loop_vars[i] + 1) % N_TEST_OPERANDS; while (loop_vars[i] == 0) { i++; if (i >= arity) goto random; loop_vars[i] = (loop_vars[i] + 1) % N_TEST_OPERANDS; } } /* Now add the additional random test sets. */ random: for (i = 9999; i >= 0; i--) { for (pc = arity - 1; pc >= 0; pc--) tvalues[pc] = *test_set++ = random_word(); *test_set++ = (*eval)(tvalues); j++; } n_test_sets = j; } /* Test the correctness of a sequence in SEQUENCE[0] through SEQUENCE[N_INSNS - 1]. */ void test_sequence(insn_t *sequence, int n_insns) { int pc; int i, j; word *test_set = test_sets; const int arity = goal_function_arity; /* Test each of the precomputed values. */ for (j = n_test_sets; j > 0; j--) { /* Update the tvalues array in each iteration, as execution of the sequence might clobber the values. (On 2-operand machines.) */ for (i = arity - 1; i >= 0; i--) tvalues[i] = *test_set++; /* Execute the synthesised sequence for the current operand values. */ run_program (sequence, n_insns, tvalues); if (tvalues[sequence[n_insns - 1].d] != *test_set++) { /* Adaptively rearrange the order of the tests. This set of test values is better than all that preceed it. The optimal ordering changes with the search space. */ if ((j = n_test_sets - j) != 0) { int k = j >> 1; j *= (arity + 1); k *= (arity + 1); for (i = 0; i <= arity; i++) { word t = test_sets[j + i]; test_sets[j + i] = test_sets[k + i]; test_sets[k + i] = t; } } return; } } /* The tests passed. Print the instruction sequence. */ if (success == 0) printf("\n"); success++; printf("%d:", success); for (pc = 0; pc < n_insns; pc++) { insn_t insn; insn = sequence[pc]; if (flag_output_assembler) output_assembler(insn); else { if (insn.opcode == CMP) printf("\t%s(", GET_INSN_NAME(insn.opcode)); else printf("\tr%u:=%s(", insn.d, GET_INSN_NAME(insn.opcode)); if (IMMEDIATE_P(insn.s1)) { if ((signed_word) IMMEDIATE_VAL(insn.s1) >= 10 || (signed_word) IMMEDIATE_VAL(insn.s1) <= -10) printf("0x%lx", IMMEDIATE_VAL(insn.s1)); else printf("%ld", IMMEDIATE_VAL(insn.s1)); } else printf("r%u", insn.s1); if (!UNARY_OPERATION(insn)) { if (IMMEDIATE_P(insn.s2)) { if ((signed_word) IMMEDIATE_VAL(insn.s2) >= 10 || (signed_word) IMMEDIATE_VAL(insn.s2) <= -10) printf(",0x%lx", IMMEDIATE_VAL(insn.s2)); else printf(",%ld", IMMEDIATE_VAL(insn.s2)); } else printf(",r%u", insn.s2); } printf(")\n"); } } fflush(stdout); } /* Recursively investigate all possible instruction sequences for the current target. SEQUENCE contains the instructions defined so far. N_INSNS is the number of instructions, including the one we will generate this time, in SEQUENCE. VALUES contains the values in register 0..N_VALUES. N_VALUES is the number of registers that have been assigned values by the insns so far. GOAL_VALUE is the value we aim at, when the sequence is ready. ALLOWED_COST is the maximum allowed cost of the remaining sequence. CY_IN is the carry flag. It is negative if no instruction has yet defined it (this to pruning the search tree), and otherwise takes the values 0 or 1 according to the conventions of the current target. PRUNE_HINT contains flags to assist pruning of the search tree. */ #if SPARC || RS6000 || M88000 || AM29K || ALPHA void synth(insn_t *sequence, int n_insns, word *values, int n_values, word goal_value, int allowed_cost, int ci, int prune_hint) { int s1, s2; word v, r1, r2; int co; int last_dest; #ifdef TIMING int time_start = cputime(); #endif if (n_insns > 0) last_dest = sequence[n_insns - 1].d; else last_dest = -1; /* Binary operations with carry-in. */ if (ci >= 0 && flag_use_carry) { for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; for (s2 = s1 - 1; s2 >= 0; s2--) { r2 = values[s2]; if (allowed_cost <= 1 && (prune_hint & CY_JUST_SET) == 0) { /* We are in a leaf node. CY was not set (to 0, 1 or to a data dependent value) by the previous insn. So one of the input operands has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest && s2 != last_dest) continue; } #if SPARC || RS6000 || M88000 || AM29K /* sparc: addxcc rs6000: ae m88000: addu.cio am29k: addc */ PERFORM_ADD_CIO(v, co, r1, r2, ci); RECURSE(ADD_CIO, s1, s2, CY_JUST_SET); #endif #if SPARC || M88000 /* sparc: addx m88000: addu.ci */ PERFORM_ADD_CI(v, co, r1, r2, ci); RECURSE(ADD_CI, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if SPARC /* sparc: subxcc */ PERFORM_SUB_CIO(v, co, r1, r2, ci); RECURSE(SUB_CIO, s1, s2, CY_JUST_SET); PERFORM_SUB_CIO(v, co, r2, r1, ci); RECURSE(SUB_CIO, s2, s1, CY_JUST_SET); #endif #if SPARC /* sparc: subx */ PERFORM_SUB_CI(v, co, r1, r2, ci); RECURSE(SUB_CI, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_SUB_CI(v, co, r2, r1, ci); RECURSE(SUB_CI, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 || AM29K /* rs6000: sfe m88000: subu.cio am29k: subc */ PERFORM_ADC_CIO(v, co, r1, r2, ci); RECURSE(ADC_CIO, s1, s2, CY_JUST_SET); PERFORM_ADC_CIO(v, co, r2, r1, ci); RECURSE(ADC_CIO, s2, s1, CY_JUST_SET); #endif #if M88000 /* m88000: subu.ci */ PERFORM_ADC_CI(v, co, r1, r2, ci); RECURSE(ADC_CI, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_ADC_CI(v, co, r2, r1, ci); RECURSE(ADC_CI, s2, s1, prune_hint & ~CY_JUST_SET); #endif } } } /* Binary operations without carry-in. */ for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; for (s2 = s1 - 1; s2 >= 0; s2--) { r2 = values[s2]; if (allowed_cost <= 1) { /* We are in a leaf node. So one of the input operands has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest && s2 != last_dest) continue; } #ifdef DM PERFORM_UMULWIDEN_HI(v, co, r1, r2, ci); RECURSE(UMULWIDEN_HI, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if defined (DM) || defined (MM) PERFORM_MUL(v, co, r1, r2, ci); RECURSE(MUL, s1, s2, prune_hint & ~CY_JUST_SET); #endif #ifdef UDIV_WITH_SDIV PERFORM_SDIV (v, co, r1, r2, ci); RECURSE(SDIV, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K /* sparc: addcc rs6000: a m88000: addu.co am29k: add */ PERFORM_ADD_CO(v, co, r1, r2, ci); RECURSE(ADD_CO, s1, s2, CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || ALPHA /* sparc: add rs6000: cax m88000: addu alpha: addq */ PERFORM_ADD(v, co, r1, r2, ci); RECURSE(ADD, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if SPARC /* sparc: subcc */ PERFORM_SUB_CO(v, co, r1, r2, ci); RECURSE(SUB_CO, s1, s2, CY_JUST_SET); PERFORM_SUB_CO(v, co, r2, r1, ci); RECURSE(SUB_CO, s2, s1, CY_JUST_SET); #endif #if SPARC || M88000 || ALPHA /* sparc: sub m88000: subu alpha: subq */ PERFORM_SUB(v, co, r1, r2, ci); RECURSE(SUB, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_SUB(v, co, r2, r1, ci); RECURSE(SUB, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 || AM29K /* rs6000: sf m88000: subu.co am29k: sub */ PERFORM_ADC_CO(v, co, r1, r2, ci); RECURSE(ADC_CO, s1, s2, CY_JUST_SET); PERFORM_ADC_CO(v, co, r2, r1, ci); RECURSE(ADC_CO, s2, s1, CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_AND(v, co, r1, r2, ci); RECURSE(AND, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_IOR(v, co, r1, r2, ci); RECURSE(IOR, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_XOR(v, co, r1, r2, ci); RECURSE(XOR, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_ANDC(v, co, r1, r2, ci); RECURSE(ANDC, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_ANDC(v, co, r2, r1, ci); RECURSE(ANDC, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || ALPHA PERFORM_IORC(v, co, r1, r2, ci); RECURSE(IORC, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_IORC(v, co, r2, r1, ci); RECURSE(IORC, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_EQV(v, co, r1, r2, ci); RECURSE(EQV, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || AM29K PERFORM_NAND(v, co, r1, r2, ci); RECURSE(NAND, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_NOR(v, co, r1, r2, ci); RECURSE(NOR, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if RS6000 && !defined (AVOID_DOZ) PERFORM_DOZ(v, co, r1, r2, ci); RECURSE(DOZ, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_DOZ(v, co, r2, r1, ci); RECURSE(DOZ, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if AM29K PERFORM_CPEQ(v, co, r1, r2, ci); RECURSE(CPEQ, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPGE(v, co, r1, r2, ci); RECURSE(CPGE, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPGEU(v, co, r1, r2, ci); RECURSE(CPGEU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPGT(v, co, r1, r2, ci); RECURSE(CPGT, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPGTU(v, co, r1, r2, ci); RECURSE(CPGTU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPLE(v, co, r1, r2, ci); RECURSE(CPLE, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPLEU(v, co, r1, r2, ci); RECURSE(CPLEU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPLT(v, co, r1, r2, ci); RECURSE(CPLT, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPLTU(v, co, r1, r2, ci); RECURSE(CPLTU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CPNEQ(v, co, r1, r2, ci); RECURSE(CPNEQ, s1, s2, prune_hint & ~CY_JUST_SET); #endif #if ALPHA PERFORM_CMPEQ(v, co, r1, r2, ci); RECURSE(CMPEQ, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPLE(v, co, r1, r2, ci); RECURSE(CMPLE, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPLE(v, co, r2, r1, ci); RECURSE(CMPLE, s2, s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLEU(v, co, r1, r2, ci); RECURSE(CMPLEU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPLEU(v, co, r2, r1, ci); RECURSE(CMPLEU, s2, s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLT(v, co, r1, r2, ci); RECURSE(CMPLT, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPLT(v, co, r2, r1, ci); RECURSE(CMPLT, s2, s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLTU(v, co, r1, r2, ci); RECURSE(CMPLTU, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPLTU(v, co, r2, r1, ci); RECURSE(CMPLTU, s2, s1, prune_hint & ~CY_JUST_SET); #endif #if M88000 PERFORM_CMPPAR (v, co, r1, r2, ci); RECURSE(CMPPAR, s1, s2, prune_hint & ~CY_JUST_SET); PERFORM_CMPPAR (v, co, r2, r1, ci); RECURSE(CMPPAR, s2, s1, prune_hint & ~CY_JUST_SET); #endif } } /* Unary operations with carry-in. */ if (ci >= 0 && flag_use_carry) { for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; if (allowed_cost <= 1 && (prune_hint & CY_JUST_SET) == 0) { /* We are in a leaf node and CY was not set (to 1 or to a data dependent value) by the previous insn. The input operand has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest) continue; } #if SPARC || RS6000 || M88000 || AM29K /* d,cy = 2*r1 + cy sparc: addxcc s1,s1,d rs6000: ae d,s1,s1 m88000: addu.cio d,s1,s1 am29k: addc d,s1,s1 */ PERFORM_ADD_CIO(v, co, r1, r1, ci); RECURSE(ADD_CIO, s1, s1, CY_JUST_SET); #endif #if SPARC || M88000 /* d = 2*r1 + cy sparc: addx s1,s1,d m88000: addu.ci d,s1,s1 */ PERFORM_ADD_CI(v, co, r1, r1, ci); RECURSE(ADD_CI, s1, s1, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K /* d,cy = r1 + cy - 1 sparc: addxcc s1,-1,d rs6000: ame d,s1 m88000: subu.cio d,s1,r0 am29k: subc d,s1,0 */ PERFORM_ADD_CIO(v, co, r1, VALUE(-1), ci); RECURSE(ADD_CIO, s1, CNST(-1), CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K /* d,cy = r1 + cy sparc: addxcc s1,0,d rs6000: aze d,s1 m88000: addu.cio d,s1,r0 am29k: addc d,s1,0 */ PERFORM_ADD_CIO(v, co, r1, VALUE(0), ci); RECURSE(ADD_CIO, s1, CNST(0), CY_JUST_SET); #endif #if SPARC /* d,cy = 0 - r1 - cy sparc: subxcc %g0,s1,d */ PERFORM_SUB_CIO(v, co, VALUE(0), r1, ci); RECURSE(SUB_CIO, CNST(0), s1, CY_JUST_SET); #endif #if SPARC /* d = r1 + 1 - cy sparc: subx s1,-1,d */ PERFORM_SUB_CI(v, co, r1, VALUE(-1), ci); RECURSE(SUB_CI, s1, CNST(-1), prune_hint & ~CY_JUST_SET); #endif #if SPARC /* d,cy = r1 + 1 - cy sparc: subxcc s1,-1,d */ PERFORM_SUB_CIO(v, co, r1, VALUE(-1), ci); RECURSE(SUB_CIO, s1, CNST(-1), CY_JUST_SET); #endif #if RS6000 /* d,cy = -1 + ~r1 + cy rs6000: sfme d,s1 */ PERFORM_ADC_CIO(v, co, VALUE(-1), r1, ci); RECURSE(ADC_CIO, CNST(-1), s1, CY_JUST_SET); #endif #if RS6000 || M88000 || AM29K /* d,cy = ~r1 + cy m88000: subu.cio d,r0,s1 rs6000: sfze d,s1 am29k: subrc d,s1,0 */ PERFORM_ADC_CIO(v, co, VALUE(0), r1, ci); RECURSE(ADC_CIO, CNST(0), s1, CY_JUST_SET); #endif } } /* Unary operations without carry-in. */ for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; if (allowed_cost <= 1) { /* We are in a leaf node. The input operand has to be the result operand of the previous insns for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest) continue; } #ifdef DM PERFORM_INVDIV(v, co, r1, ci); RECURSE(INVDIV, s1, 0, prune_hint & ~CY_JUST_SET); PERFORM_INVMOD(v, co, r1, ci); RECURSE(INVMOD, s1, 0, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K /* d,cy = 2*r1 sparc: addcc s1,s1,d rs6000: a d,s1,s1 m88000: addu.co d,s1,s1 am29k: add d,s1,s1 */ PERFORM_ADD_CO(v, co, r1, r1, ci); RECURSE(ADD_CO, s1, s1, CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA /* d = r1 & 1 sparc: and s1,1,d rs6000: rlinm d,s1,0,31,31 m88000: mask d,s1,1 am29k: and d,s1,1 alpha: and s1,1,d */ PERFORM_AND(v, co, r1, VALUE(1), ci); RECURSE(AND, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 /* d = r1 & 0x80000000 rs6000: rlinm d,s1,0,0,0 m88000: mask.u d,s1,0x8000 */ PERFORM_AND(v, co, r1, VALUE_MIN_SIGNED, ci); RECURSE(AND, s1, CNST_0x80000000, prune_hint & ~CY_JUST_SET); /* d = r1 & 0x7fffffff rs6000: rlinm d,s1,0,1,31 m88000: and.u d,s1,0x7fff */ PERFORM_AND(v, co, r1, VALUE_MAX_SIGNED, ci); RECURSE(AND, s1, CNST_0x7FFFFFFF, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 PERFORM_XOR(v, co, r1, VALUE_MIN_SIGNED, ci); RECURSE(XOR, s1, CNST_0x80000000, prune_hint & ~CY_JUST_SET); PERFORM_IOR(v, co, r1, VALUE_MIN_SIGNED, ci); RECURSE(IOR, s1, CNST_0x80000000, prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA /* d = r1 ^ 1 sparc: xor s1,1,d rs6000: xoril d,s1,1 m88000: xor d,s1,1 am29k: xor d,s1,1 alpha: xor s1,1,d */ PERFORM_XOR(v, co, r1, VALUE(1), ci); RECURSE(XOR, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA /* d = ~r1 sparc: xnor %g0,s1,d rs6000: nand d,s1,s1 m88000: xor.c d,s1,r0 am29k: nand d,s1,s1 alpha: ornot $31,s1,d */ PERFORM_SUB(v, co, VALUE(-1), r1, ci); RECURSE(SUB, CNST(-1), s1, prune_hint & ~CY_JUST_SET); #endif #if RS6000 /* d,cy = -1 + ~r1 (i.e. one's complement and set carry.) rs6000: sfi d,s1,-1 */ PERFORM_ADC_CO(v, co, VALUE(-1), r1, ci); RECURSE(ADC_CO, CNST(-1), s1, CY_JUST_SET | CY_1); #endif #if SPARC || RS6000 || AM29K /* d,cy = r1 + 1 sparc: addcc s1,1,d rs6000: ai d,s1,1 am29k: add d,s1,1 */ PERFORM_ADD_CO(v, co, r1, VALUE(1), ci); RECURSE(ADD_CO, s1, CNST(1), CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || ALPHA /* d = r1 + 1 sparc: add s1,1,d rs6000: cal d,1(s1) m88000: addu d,s1,1 alpha: addq s1,1,d */ PERFORM_ADD(v, co, r1, VALUE(1), ci); RECURSE(ADD, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if 0 && RS6000 /* This has the same effect as a "xoriu". */ /* d = r1 + 0x80000000 rs6000: cau d,s1,0x8000 */ PERFORM_ADD(v, co, r1, VALUE_MIN_SIGNED, ci); RECURSE(ADD, s1, CNST_0x80000000, CY_JUST_SET); #endif #if SPARC || RS6000 || AM29K /* not M88000 */ /* d,cy = r1 + -1 sparc: addcc s1,-1,d rs6000: ai d,s1,-1 am29k: sub d,s1,1 */ PERFORM_ADD_CO(v, co, r1, VALUE(-1), ci); RECURSE(ADD_CO, s1, CNST(-1), CY_JUST_SET); #endif #if SPARC /* d,cy = r1 - 1. [This isn't redundant, in spite we add -1 above.] sparc: subcc s1,1,d */ PERFORM_SUB_CO(v, co, r1, VALUE(1), ci); RECURSE(SUB_CO, s1, CNST(1), CY_JUST_SET); #endif #if SPARC /* d,cy = -r1 sparc: subcc %g0,s1,d */ PERFORM_SUB_CO(v, co, VALUE(0), r1, ci); RECURSE(SUB_CO, CNST(0), s1, CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || ALPHA /* d = -r1 sparc: sub %g0,s1,d rs6000: neg d,s1 m88000: subu d,r0,s1 alpha: subq $31,s1,d */ PERFORM_SUB(v, co, VALUE(0), r1, ci); RECURSE(SUB, CNST(0), s1, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 || AM29K /* d,cy = -r1 rs6000: sf d,s1,0 m88000: subu.co d,r0,s1 am29k: subr d,s1,0 */ PERFORM_ADC_CO(v, co, VALUE(0), r1, ci); RECURSE(ADC_CO, CNST(0), s1, CY_JUST_SET); #endif #if RS6000 /* d = abs(r1) rs6000: abs d,s1 */ PERFORM_ABSVAL(v, co, r1, ci); RECURSE(ABSVAL, s1, 0, prune_hint & ~CY_JUST_SET); /* d = -abs(r1) rs6000: nabs d,s1 */ PERFORM_NABSVAL(v, co, r1, ci); RECURSE(NABSVAL, s1, 0, prune_hint & ~CY_JUST_SET); #endif #if RS6000 && !defined (AVOID_DOZ) PERFORM_DOZ(v, co, VALUE(0), r1, ci); RECURSE(DOZ, CNST(0), s1, prune_hint & ~CY_JUST_SET); PERFORM_DOZ(v, co, VALUE(-1), r1, ci); RECURSE(DOZ, CNST(-1), s1, prune_hint & ~CY_JUST_SET); #endif #if SHIFTS { int cnt; for (cnt = 1; cnt < BITS_PER_WORD; cnt++) { #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_LSHIFTR(v, co, r1, VALUE(cnt), ci); RECURSE(LSHIFTR, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); #endif #if SPARC || M88000 || AM29K || ALPHA PERFORM_ASHIFTR(v, co, r1, VALUE(cnt), ci); RECURSE(ASHIFTR, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); #endif #if RS6000 PERFORM_ASHIFTR_CON(v, co, r1, VALUE(cnt), ci); RECURSE(ASHIFTR_CON, s1, CNST(cnt), CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_SHIFTL(v, co, r1, VALUE(cnt), ci); RECURSE(SHIFTL, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 PERFORM_ROTATEL(v, co, r1, VALUE(cnt), ci); RECURSE(ROTATEL, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); #endif } } #else #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_LSHIFTR(v, co, r1, VALUE(1), ci); RECURSE(LSHIFTR, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if SPARC || M88000 || AM29K || ALPHA PERFORM_ASHIFTR(v, co, r1, VALUE(1), ci); RECURSE(ASHIFTR, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if RS6000 PERFORM_ASHIFTR_CON(v, co, r1, VALUE(1), ci); RECURSE(ASHIFTR_CON, s1, CNST(1), CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_SHIFTL(v, co, r1, VALUE(1), ci); RECURSE(SHIFTL, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 PERFORM_ROTATEL(v, co, r1, VALUE(1), ci); RECURSE(ROTATEL, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_LSHIFTR(v, co, r1, VALUE(BITS_PER_WORD-1), ci); RECURSE(LSHIFTR, s1, CNST(BITS_PER_WORD-1), prune_hint & ~CY_JUST_SET); #endif #if SPARC || M88000 || AM29K || ALPHA PERFORM_ASHIFTR(v, co, r1, VALUE(BITS_PER_WORD-1), ci); RECURSE(ASHIFTR, s1, CNST(BITS_PER_WORD-1), prune_hint & ~CY_JUST_SET); #endif #if RS6000 PERFORM_ASHIFTR_CON(v, co, r1, VALUE(BITS_PER_WORD-1), ci); RECURSE(ASHIFTR_CON, s1, CNST(BITS_PER_WORD-1), CY_JUST_SET); #endif #if SHIFT16 #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_LSHIFTR(v, co, r1, VALUE(16), ci); RECURSE(LSHIFTR, s1, CNST(16), prune_hint & ~CY_JUST_SET); #endif #if SPARC || M88000 || AM29K || ALPHA PERFORM_ASHIFTR(v, co, r1, VALUE(16), ci); RECURSE(ASHIFTR, s1, CNST(16), prune_hint & ~CY_JUST_SET); #endif #if RS6000 PERFORM_ASHIFTR_CON(v, co, r1, VALUE(16), ci); RECURSE(ASHIFTR_CON, s1, CNST(16), CY_JUST_SET); #endif #if SPARC || RS6000 || M88000 || AM29K || ALPHA PERFORM_SHIFTL(v, co, r1, VALUE(16), ci); RECURSE(SHIFTL, s1, CNST(16), prune_hint & ~CY_JUST_SET); #endif #if RS6000 || M88000 PERFORM_ROTATEL(v, co, r1, VALUE(16), ci); RECURSE(ROTATEL, s1, CNST(16), prune_hint & ~CY_JUST_SET); #endif #endif /* SHIFT16 */ #endif /* SHIFTS */ #if EXTRACTS { int cnt; for (cnt = 1; cnt < BITS_PER_WORD; cnt++) { #if M88000 PERFORM_EXTS1(v, co, r1, VALUE(cnt), ci); RECURSE(EXTS1, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); PERFORM_EXTU1(v, co, r1, VALUE(cnt), ci); RECURSE(EXTU1, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); PERFORM_EXTS2(v, co, r1, VALUE(cnt), ci); RECURSE(EXTS2, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); PERFORM_EXTU2(v, co, r1, VALUE(cnt), ci); RECURSE(EXTU2, s1, CNST(cnt), prune_hint & ~CY_JUST_SET); #endif } } #endif #if AM29K PERFORM_CPEQ(v, co, r1, VALUE(0), ci); RECURSE(CPEQ, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPGE(v, co, r1, VALUE(0), ci); RECURSE(CPGE, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPGEU(v, co, r1, VALUE(0), ci); RECURSE(CPGEU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPGT(v, co, r1, VALUE(0), ci); RECURSE(CPGT, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPGTU(v, co, r1, VALUE(0), ci); RECURSE(CPGTU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPLE(v, co, r1, VALUE(0), ci); RECURSE(CPLE, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPLEU(v, co, r1, VALUE(0), ci); RECURSE(CPLEU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPLT(v, co, r1, VALUE(0), ci); RECURSE(CPLT, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPLTU(v, co, r1, VALUE(0), ci); RECURSE(CPLTU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CPNEQ(v, co, r1, VALUE(0), ci); RECURSE(CPNEQ, s1, CNST(0), prune_hint & ~CY_JUST_SET); #endif #if ALPHA PERFORM_CMPEQ(v, co, r1, VALUE(0), ci); RECURSE(CMPEQ, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPLE(v, co, r1, VALUE(0), ci); RECURSE(CMPLE, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPLE(v, co, VALUE(0), r1, ci); RECURSE(CMPLE, CNST(0), s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLEU(v, co, r1, VALUE(0), ci); RECURSE(CMPLEU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPLEU(v, co, VALUE(0), r1, ci); RECURSE(CMPLEU, CNST(0), s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLT(v, co, r1, VALUE(0), ci); RECURSE(CMPLT, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPLT(v, co, VALUE(0), r1, ci); RECURSE(CMPLT, CNST(0), s1, prune_hint & ~CY_JUST_SET); PERFORM_CMPLTU(v, co, r1, VALUE(0), ci); RECURSE(CMPLTU, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPLTU(v, co, VALUE(0), r1, ci); RECURSE(CMPLTU, CNST(0), s1, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || AM29K PERFORM_CLZ(v, co, r1, ci); RECURSE(CLZ, s1, 0, prune_hint & ~CY_JUST_SET); #endif #if M88000 PERFORM_FF1(v, co, r1, ci); RECURSE(FF1, s1, 0, prune_hint & ~CY_JUST_SET); #endif #if M88000 PERFORM_CMPPAR (v, co, r1, VALUE(0), ci); RECURSE(CMPPAR, s1, CNST(0), prune_hint & ~CY_JUST_SET); PERFORM_CMPPAR (v, co, VALUE(0), r1, ci); RECURSE(CMPPAR, CNST(0), s1, prune_hint & ~CY_JUST_SET); #endif } #if ALPHA /* Alpha Conditional move instructions need special treatment. We let all other instructions assign the next higher-numbered register, but we can't do that here since cmov insns leave the register undefined if the instruction condition is not satisfied. Instead we let the cmov instructions non-deterministically overwrite all already-defined registers. */ for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; for (s2 = s1 - 1; s2 >= 0; s2--) { int dr; r2 = values[s2]; if (allowed_cost <= 1) { /* We are in a leaf node. */ /* One of the input operands has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest && s2 != last_dest) continue; } for (dr = n_values - 1; dr >= 0; dr--) { v = values[dr]; PERFORM_CMOVEQ (v, co, r1, r2, ci); CRECURSE_2OP(CMOVEQ, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVEQ (v, co, r2, r1, ci); CRECURSE_2OP(CMOVEQ, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVNE (v, co, r1, r2, ci); CRECURSE_2OP(CMOVNE, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVNE (v, co, r2, r1, ci); CRECURSE_2OP(CMOVNE, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLT (v, co, r1, r2, ci); CRECURSE_2OP(CMOVLT, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLT (v, co, r2, r1, ci); CRECURSE_2OP(CMOVLT, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGE (v, co, r1, r2, ci); CRECURSE_2OP(CMOVGE, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGE (v, co, r2, r1, ci); CRECURSE_2OP(CMOVGE, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLE (v, co, r1, r2, ci); CRECURSE_2OP(CMOVLE, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLE (v, co, r2, r1, ci); CRECURSE_2OP(CMOVLE, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGT (v, co, r1, r2, ci); CRECURSE_2OP(CMOVGT, dr, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGT (v, co, r2, r1, ci); CRECURSE_2OP(CMOVGT, dr, s2, s1, 1, prune_hint & ~CY_JUST_SET); } } } for (s1 = n_values - 1; s1 >= 0; s1--) { int dr; r1 = values[s1]; if (allowed_cost <= 1) { /* We are in a leaf node. The input operand has to be the result operand of the previous insns for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest) continue; } for (dr = n_values - 1; dr >= 0; dr--) { v = values[dr]; PERFORM_CMOVEQ (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVEQ, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVEQ (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVEQ, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVNE (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVNE, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVNE (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVNE, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLT (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVLT, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLT (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVLT, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGE (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVGE, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGE (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVGE, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLE (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVLE, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVLE (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVLE, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGT (v, co, r1, VALUE(0), ci); CRECURSE_2OP(CMOVGT, dr, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); PERFORM_CMOVGT (v, co, VALUE(0), r1, ci); CRECURSE_2OP(CMOVGT, dr, CNST(0), s1, 1, prune_hint & ~CY_JUST_SET); } } #endif /* ALPHA */ /* 0-ary instructions, just dependent on carry. */ if (ci >= 0 && flag_use_carry && (allowed_cost <= 1 ? ((prune_hint & CY_JUST_SET) != 0) : 1)) { /* We don't do "0 - 1 - cy" or "0 + 1 + cy" here. It would probably give very few new sequences. */ #if SPARC || M88000 /* d = cy. sparc: addx %g0,0,d m88000: addu.ci d,r0,r0 */ PERFORM_ADD_CI(v, co, VALUE(0), VALUE(0), ci); RECURSE(ADD_CI, CNST(0), CNST(0), prune_hint & ~CY_JUST_SET); #endif #if SPARC || M88000 /* d = cy, cy = 0. sparc: addxcc %g0,0,d m88000: addu.cio d,r0,r0 */ PERFORM_ADD_CIO(v, co, VALUE(0), VALUE(0), ci); RECURSE(ADD_CIO, CNST(0), CNST(0), CY_JUST_SET | CY_0); #endif #if SPARC /* Using SUB_CIO instead would make no difference. It'd just set carry to it's old value. */ /* d = -cy. sparc: subx %g0,0,d */ PERFORM_SUB_CI(v, co, VALUE(0), VALUE(0), ci); RECURSE(SUB_CI, CNST(0), CNST(0), prune_hint & ~CY_JUST_SET); #endif #if SPARC /* d = 1 - cy. sparc: subx %g0,-1,d */ PERFORM_SUB_CI(v, co, VALUE(0), VALUE(-1), ci); RECURSE(SUB_CI, CNST(0), CNST(-1), CY_JUST_SET | CY_1); #endif #if SPARC /* d = 1 - cy, cy = 1. sparc: subxcc %g0,-1,d */ PERFORM_SUB_CIO(v, co, VALUE(0), VALUE(-1), ci); RECURSE(SUB_CIO, CNST(0), CNST(-1), CY_JUST_SET | CY_1); #endif #if SPARC /* Using ADD_CIO instead would make no difference. It'd just set carry to it's old value. */ /* d = -1 + cy. sparc: addx %g0,-1,d */ PERFORM_ADD_CI(v, co, VALUE(0), VALUE(-1), ci); RECURSE(ADD_CI, CNST(0), CNST(-1), prune_hint & ~CY_JUST_SET); #endif #if RS6000 || AM29K /* Use subu.ci on 88k instead with same result */ /* d = -1 + cy, cy = cy rs6000: sfe d,d,d am29k: subc d,d,d */ PERFORM_ADC_CIO(v, co, VALUE(0), VALUE(0), ci); RECURSE(ADC_CIO, n_values, n_values, prune_hint & ~CY_JUST_SET); #endif #if M88000 /* d = -1 + cy m88000: subu.ci d,r0,r0 */ PERFORM_ADC_CI(v, co, VALUE(0), VALUE(0), ci); RECURSE(ADC_CI, CNST(0), CNST(0), prune_hint & ~CY_JUST_SET); #endif } /* Move instructions. Don't do this if we are just permitted to do one more instruction. */ if (allowed_cost > 1) { #if SPARC || RS6000 || M88000 || AM29K /* d = 0x80000000 sparc: sethi %hi(0x80000000),d rs6000: liu d,0x8000 m88000: or.u d,r0,0x8000 am29k: cpeq d,gr1,gr1 */ PERFORM_COPY(v, co, VALUE_MIN_SIGNED, ci); RECURSE(COPY, CNST_0x80000000, 0, prune_hint & ~CY_JUST_SET); /* d = -1 sparc: mov -1,d rs6000: lil d,-1 m88000: subu d,r0,1 am29k: constn d,1 */ PERFORM_COPY(v, co, VALUE(-1), ci); RECURSE(COPY, CNST(-1), 0, prune_hint & ~CY_JUST_SET); /* d = 1 sparc: mov 1,d rs6000: lil d,1 m88000: addu d,r0,1 am29k: const d,1 */ PERFORM_COPY(v, co, VALUE(1), ci); RECURSE(COPY, CNST(1), 0, prune_hint & ~CY_JUST_SET); #endif #if RS6000 || AM29K /* sparc and 88k should not need this. */ /* d = 0 sparc: mov 0,d rs6000: lil d,0 m88000: or d,r0,0 am29k: const d,0 */ PERFORM_COPY(v, co, VALUE(0), ci); RECURSE(COPY, CNST(0), 0, prune_hint & ~CY_JUST_SET); #endif #if M88000 /* d = 0x7fffffff m88000: set d,r0,31<0> */ PERFORM_COPY(v, co, VALUE_MAX_SIGNED, ci); RECURSE(COPY, CNST_0x7FFFFFFF, 0, prune_hint & ~CY_JUST_SET); #endif } #ifdef TIMING timings[allowed_cost] += cputime() - time_start; #endif } #endif /* This function is commented above, before the previous function. */ #if M68000 || I386 || PYR void synth(insn_t *sequence, int n_insns, word *values, int n_values, word goal_value, int allowed_cost, int ci, int prune_hint) { int s1, s2; word v, r1, r2; int co; int last_dest; if (n_insns > 0) last_dest = sequence[n_insns - 1].d; else last_dest = -1; /* Binary operations with carry-in. */ if (ci >= 0 && (prune_hint & CY_0) == 0 && flag_use_carry) { for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; for (s2 = n_values - 1; s2 >= 0; s2--) { r2 = values[s2]; if (allowed_cost <= 1 && (prune_hint & CY_JUST_SET) == 0) { /* We are in a leaf node. CY was not set (to 1 or to a data dependent value) by the previous insn. So one of the input operands has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest && s2 != last_dest) continue; } #if M68000 || I386 || PYR /* m68000: addx i80386: adc pyramid: addwc */ PERFORM_ADD_CIO(v, co, r1, r2, ci); CRECURSE_2OP(ADD_CIO, s1, s1, s2, 1, CY_JUST_SET); #endif #if M68000 || I386 if (s1 != s2) { /* m68000: subx i80386: sbb */ PERFORM_SUB_CIO(v, co, r1, r2, ci); CRECURSE_2OP(SUB_CIO, s1, s1, s2, 1, CY_JUST_SET); } #endif #if PYR if (s1 != s2) { /* pyramid: subwb */ PERFORM_ADC_CIO(v, co, r1, r2, ci); CRECURSE_2OP(ADC_CIO, s1, s1, s2, 1, CY_JUST_SET); } #endif } } } /* Binary operations without carry-in. */ for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; for (s2 = n_values - 1; s2 >= 0; s2--) { r2 = values[s2]; if (allowed_cost <= 1) { /* We are in a leaf node. So one of the input operands has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest && s2 != last_dest) continue; } #if M68000 || I386 || PYR /* m68000: add i80386: add pyramid: addw */ PERFORM_ADD_CO(v, co, r1, r2, ci); CRECURSE_2OP(ADD_CO, s1, s1, s2, 1, CY_JUST_SET); #endif if (s1 != s2) { #if M68000 || I386 /* m68000: sub i80386: sub */ PERFORM_SUB_CO(v, co, r1, r2, ci); CRECURSE_2OP(SUB_CO, s1, s1, s2, 1, CY_JUST_SET); #endif #if PYR /* pyramid: subw */ PERFORM_ADC_CO(v, co, r1, r2, ci); CRECURSE_2OP(ADC_CO, s1, s1, s2, 1, CY_JUST_SET); #endif #if M68000 PERFORM_AND(v, co, r1, r2, ci); CRECURSE_2OP(AND, s1, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_IOR(v, co, r1, r2, ci); CRECURSE_2OP(IOR, s1, s1, s2, 1, prune_hint & ~CY_JUST_SET); PERFORM_XOR(v, co, r1, r2, ci); CRECURSE_2OP(XOR, s1, s1, s2, 1, prune_hint & ~CY_JUST_SET); #endif #if I386 PERFORM_AND_RC(v, co, r1, r2, ci); CRECURSE_2OP(AND_RC, s1, s1, s2, 1, CY_JUST_SET | CY_0); PERFORM_IOR_RC(v, co, r1, r2, ci); CRECURSE_2OP(IOR_RC, s1, s1, s2, 1, CY_JUST_SET | CY_0); PERFORM_XOR_RC(v, co, r1, r2, ci); CRECURSE_2OP(XOR_RC, s1, s1, s2, 1, CY_JUST_SET | CY_0); #endif #if PYR PERFORM_AND_CC(v, co, r1, r2, ci); CRECURSE_2OP(AND_CC, s1, s1, s2, 1, 0); PERFORM_ANDC_CC(v, co, r1, r2, ci); CRECURSE_2OP(ANDC_CC, s1, s1, s2, 1, 0); PERFORM_IOR_CC(v, co, r1, r2, ci); CRECURSE_2OP(IOR_CC, s1, s1, s2, 1, 0); PERFORM_XOR_CC(v, co, r1, r2, ci); CRECURSE_2OP(XOR_CC, s1, s1, s2, 1, 0); #endif #if I386 PERFORM_CMP(v, co, r1, r2, ci); /* kludge: lie that the result is written to register . */ CRECURSE_2OP(CMP, n_values, s1, s2, 1, CY_JUST_SET); #endif } #if M68000 || I386 || PYR /* Exchange registers. An ugly kludge. */ if (s1 < s2) { values[s2] = r1; /* Assign r2 to v to make `recurse' and rely on `recurse' to handle the writing of it to the values array. */ v = r2; CRECURSE_2OP(EXCHANGE, s1, s1, s2, 1, prune_hint & ~CY_JUST_SET); values[s2] = r2; } #endif } } /* Unary operations with carry-in. */ if (ci >= 0 && (prune_hint & CY_0) == 0 && flag_use_carry) { for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; if (allowed_cost <= 1 && (prune_hint & CY_JUST_SET) == 0) { /* We are in a leaf node. CY was not set (to 1 or to a data dependent value) by the previous insn. The input operand has to be the result operand of the previous insn for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest) continue; } #if I386 || PYR /* d,cy = r1 + 1 + cy i80386: adc 1,d pyramid: addwc $1,d */ PERFORM_ADD_CIO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ADD_CIO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if I386 /* d,cy = r1 - 1 - cy i80386: sbb 1,d */ PERFORM_SUB_CIO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(SUB_CIO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if PYR /* d,cy = r1 + (-2) + cy pyramid: subwb $1,d */ PERFORM_ADC_CIO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ADC_CIO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if I386 || PYR /* d,cy = r1 + (-1) + cy i80386: adc -1,d pyramid: addwc $-1,d */ PERFORM_ADD_CIO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(ADD_CIO, s1, s1, CNST(-1), 1, CY_JUST_SET); #endif #if I386 /* d,cy = r1 - -1 - cy i80386: sbb -1,d */ PERFORM_SUB_CIO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(SUB_CIO, s1, s1, CNST(-1), 1, CY_JUST_SET); #endif #if PYR /* d,cy = r1 + cy [or if you prefer, r1 + 0 + cy] pyramid: subwb $-1,d */ PERFORM_ADC_CIO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(ADC_CIO, s1, s1, CNST(-1), 1, CY_JUST_SET); #endif #if I386 || PYR /* d,cy = r1 + cy i80386: adc 0,d pyramid: addwc $0,d */ PERFORM_ADD_CIO(v, co, r1, VALUE(0), ci); CRECURSE_2OP(ADD_CIO, s1, s1, CNST(0), 1, CY_JUST_SET); #endif #if I386 /* d,cy = r1 - cy i80386: sbb 0,d */ PERFORM_SUB_CIO(v, co, r1, VALUE(0), ci); CRECURSE_2OP(SUB_CIO, s1, s1, CNST(0), 1, CY_JUST_SET); #endif #if PYR /* d,cy = r1 + (-1) + cy pyramid: subwb $0,d */ PERFORM_ADC_CIO(v, co, r1, VALUE(0), ci); CRECURSE_2OP(ADC_CIO, s1, s1, CNST(0), 1, CY_JUST_SET); #endif #if M68000 /* d,cy = 0 - r1 - cy m68000: negx d */ PERFORM_SUB_CIO(v, co, VALUE(0), r1, ci); CRECURSE_2OP(SUB_CIO, s1, CNST(0), s1, 1, CY_JUST_SET); #endif #if M68000 /* d,cy = circular rotate left thru carry m68000: roxll #1,d */ PERFORM_ROTATEXL_CIO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ROTATEXL_CIO, s1, s1, CNST(1), SHIFT_COST(1), CY_JUST_SET); #endif #if I386 PERFORM_ROTATEXL_CIO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ROTATEXL_CIO, s1, s1, CNST(BITS_PER_WORD-1), 2, CY_JUST_SET); PERFORM_ROTATEXL_CIO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ROTATEXL_CIO, s1, s1, CNST(1), 2, CY_JUST_SET); #endif } } /* Unary operations without carry-in. */ for (s1 = n_values - 1; s1 >= 0; s1--) { r1 = values[s1]; if (allowed_cost <= 1) { /* We are in a leaf node. The input operand has to be the result operand of the previous insns for that insn to be meaningful. */ if (last_dest >= 0 && s1 != last_dest) continue; } else { /* Certain instructions should not terminate a sequence. So we only generate them in non-leaf nodes. */ #if M68000 || I386 || PYR /* d = r1 m68000: move s1,d i80386: move s1,d pyramid: movw s1,d */ PERFORM_COPY(v, co, r1, ci); CRECURSE_NEW(COPY, n_values, s1, CNST(0), 1, prune_hint & ~CY_JUST_SET); #endif #if I386 /* cmp kludge: lie that the result is written to register . */ /* i80386: cmp -1,s1 */ PERFORM_CMP(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(CMP, n_values, s1, CNST(-1), 1, CY_JUST_SET); /* i80386: cmp 1,s1 */ PERFORM_CMP(v, co, r1, VALUE(1), ci); CRECURSE_2OP(CMP, n_values, s1, CNST(1), 1, CY_JUST_SET); /* i80386: cmp 0x7fffffff,s1 */ PERFORM_CMP(v, co, r1, VALUE_MAX_SIGNED, ci); CRECURSE_2OP(CMP, n_values, s1, CNST_0x7FFFFFFF, 2, CY_JUST_SET); /* i80386: cmp 0x80000000,s1 */ PERFORM_CMP(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(CMP, n_values, s1, CNST_0x80000000, 2, CY_JUST_SET); #endif } #if M68000 || PYR PERFORM_LSHIFTR_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(LSHIFTR_CO, s1, s1, CNST(1), SHIFT_COST(1), CY_JUST_SET); PERFORM_ASHIFTR_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ASHIFTR_CO, s1, s1, CNST(1), SHIFT_COST(1), CY_JUST_SET); PERFORM_SHIFTL_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(SHIFTL_CO, s1, s1, CNST(1), SHIFT_COST(1), CY_JUST_SET); /* Pyramids's rotlw and rotrw clobber cy */ #endif #if M68000 PERFORM_ROTATEL_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ROTATEL_CO, s1, s1, CNST(1), SHIFT_COST(1), CY_JUST_SET); #endif #if PYR PERFORM_LSHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(LSHIFTR_CO, s1, s1, CNST(BITS_PER_WORD-1), 1, CY_JUST_SET); PERFORM_ASHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ASHIFTR_CO, s1, s1, CNST(BITS_PER_WORD-1), 1, CY_JUST_SET); PERFORM_SHIFTL_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(SHIFTL_CO, s1, s1, CNST(BITS_PER_WORD-1), 1, CY_JUST_SET); /* Pyramids's rotlw and rotrw clobber cy */ #endif #if I386 PERFORM_LSHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(LSHIFTR_CO, s1, s1, CNST(BITS_PER_WORD-1), 2, CY_JUST_SET); PERFORM_ASHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ASHIFTR_CO, s1, s1, CNST(BITS_PER_WORD-1), 2, CY_JUST_SET); PERFORM_SHIFTL_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(SHIFTL_CO, s1, s1, CNST(BITS_PER_WORD-1), 2, CY_JUST_SET); PERFORM_ROTATEL_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ROTATEL_CO, s1, s1, CNST(BITS_PER_WORD-1), 2, CY_JUST_SET); PERFORM_LSHIFTR_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(LSHIFTR_CO, s1, s1, CNST(1), 2, CY_JUST_SET); PERFORM_ASHIFTR_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ASHIFTR_CO, s1, s1, CNST(1), 2, CY_JUST_SET); PERFORM_SHIFTL_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(SHIFTL_CO, s1, s1, CNST(1), 2, CY_JUST_SET); PERFORM_ROTATEL_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ROTATEL_CO, s1, s1, CNST(1), 2, CY_JUST_SET); #endif #if M68000 /* m68000: andw $1,d */ PERFORM_AND(v, co, r1, VALUE(1), ci); CRECURSE_2OP(AND, s1, s1, CNST(1), 1, prune_hint & ~CY_JUST_SET); PERFORM_AND(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(AND, s1, s1, CNST_0x80000000, 2, prune_hint & ~CY_JUST_SET); PERFORM_IOR(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(IOR, s1, s1, CNST_0x80000000, 2, prune_hint & ~CY_JUST_SET); /* d = r1 ^ 1 m68000: eorw #1,d */ PERFORM_XOR(v, co, r1, VALUE(1), ci); CRECURSE_2OP(XOR, s1, s1, CNST(1), 1, prune_hint & ~CY_JUST_SET); PERFORM_XOR(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(XOR, s1, s1, CNST_0x80000000, 2, prune_hint & ~CY_JUST_SET); #endif #if I386 /* i80386: andb $1,d */ PERFORM_AND_RC(v, co, r1, VALUE(1), ci); CRECURSE_2OP(AND_RC, s1, s1, CNST(1), 1, CY_JUST_SET | CY_0); PERFORM_AND_RC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(AND_RC, s1, s1, CNST_0x80000000, 2, CY_JUST_SET | CY_0); PERFORM_IOR_RC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(IOR_RC, s1, s1, CNST_0x80000000, 2, CY_JUST_SET | CY_0); /* d = r1 ^ 1 i80386: xorb $1,d */ PERFORM_XOR_RC(v, co, r1, VALUE(1), ci); CRECURSE_2OP(XOR_RC, s1, s1, CNST(1), 1, CY_JUST_SET | CY_0); PERFORM_XOR_RC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(XOR_RC, s1, s1, CNST_0x80000000, 2, CY_JUST_SET | CY_0); #endif #if PYR PERFORM_AND_CC(v, co, r1, VALUE(1), ci); CRECURSE_2OP(AND_CC, s1, s1, CNST(1), 1, 0); PERFORM_AND_CC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(AND_CC, s1, s1, CNST_0x80000000, 2, 0); PERFORM_IOR_CC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(IOR_CC, s1, s1, CNST_0x80000000, 2, 0); /* d = r1 ^ 1 pyramid: xorw $1,d */ PERFORM_XOR_CC(v, co, r1, VALUE(1), ci); CRECURSE_2OP(XOR_CC, s1, s1, CNST(1), 1, 0); PERFORM_XOR_CC(v, co, r1, VALUE_MIN_SIGNED, ci); CRECURSE_2OP(XOR_CC, s1, s1, CNST_0x80000000, 2, 0); #endif #if M68000 || I386 /* d = ~r1 m68000: not d i80386: not d */ PERFORM_SUB(v, co, VALUE(-1), r1, ci); CRECURSE_2OP(SUB, s1, CNST(-1), s1, 1, prune_hint & ~CY_JUST_SET); #endif #if PYR /* d = ~r1 pyramid: mcomw s1,d */ /* We need a new insn: SUB_CC, for Subtract and Clobber Carry */ #endif #if I386 /* d = r1 + 1 i80386: inc d */ PERFORM_ADD(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ADD, s1, s1, CNST(1), 2, prune_hint & ~CY_JUST_SET); #endif #if PYR /* d = r1 + 1 pyramid: mova 1(s1),d */ PERFORM_ADD(v, co, r1, VALUE(1), ci); RECURSE(ADD, s1, CNST(1), prune_hint & ~CY_JUST_SET); #endif #if I386 /* d = r1 - 1 i80386: dec d */ PERFORM_SUB(v, co, r1, VALUE(1), ci); CRECURSE_2OP(SUB, s1, s1, CNST(1), 1, prune_hint & ~CY_JUST_SET); #endif #if PYR /* d = r1 - 1 pyramid: mova -1(s1),d */ PERFORM_ADD(v, co, r1, VALUE(-1), ci); RECURSE(ADD, s1, CNST(-1), prune_hint & ~CY_JUST_SET); #endif #if M68000 || I386 || PYR /* d,cy = r1 + 1 m68000: addq 1,d i80386: add 1,d [short immediate form] pyramid: addw $1,d */ PERFORM_ADD_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ADD_CO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if M68000 || I386 /* d,cy = r1 - 1 m68000: subq 1,d i80386: sub 1,d [short immediate form] */ PERFORM_SUB_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(SUB_CO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if PYR && 0 /* same effect as addw $-1,d */ /* d,cy = r1 + (-1) pyramid: subw 1,d */ PERFORM_ADC_CO(v, co, r1, VALUE(1), ci); CRECURSE_2OP(ADC_CO, s1, s1, CNST(1), 1, CY_JUST_SET); #endif #if M68000 /* d,cy = r1 + (-1) m68000: add -1,d */ PERFORM_ADD_CO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(ADD_CO, s1, s1, CNST(-1), 2, CY_JUST_SET); #endif #if I386 || PYR /* d,cy = r1 + (-1) i80386: add -1,d pyramid: addw $-1,d */ PERFORM_ADD_CO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(ADD_CO, s1, s1, CNST(-1), 1, CY_JUST_SET); #endif #if M68000 /* d,cy = r1 - (-1) m68000: sub -1,d */ PERFORM_SUB_CO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(SUB_CO, s1, s1, CNST(-1), 2, CY_JUST_SET); #endif #if I386 /* d,cy = r1 - (-1) i80386: sub -1,d */ PERFORM_SUB_CO(v, co, r1, VALUE(-1), ci); CRECURSE_2OP(SUB_CO, s1, s1, CNST(-1), 1, CY_JUST_SET); #endif #if M68000 || I386 /* d,cy = -r1 m68000: neg d i80386: neg d */ PERFORM_SUB_CO(v, co, VALUE(0), r1, ci); CRECURSE_2OP(SUB_CO, s1, CNST(0), s1, 1, CY_JUST_SET); #endif #if PYR /* d,cy = 0 + (-r1) pyramid: rsubw $0,d */ PERFORM_ADC_CO(v, co, VALUE(0), r1, ci); CRECURSE_2OP(ADC_CO, s1, CNST(0), s1, 1, CY_JUST_SET); #endif } #if M68020 && !M68000 /* don't do this for plain 68000 */ /* kludge for immediate shift on 68k */ if (last_dest >= 0 && last_dest == n_values - 1 && values[last_dest] == VALUE(BITS_PER_WORD-1) && sequence[n_insns - 1].opcode == COPY) { for (s1 = n_values - 2; s1 >= 0; s1--) { r1 = values[s1]; PERFORM_LSHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(LSHIFTR_CO, s1, s1, last_dest, 1, CY_JUST_SET); PERFORM_ASHIFTR_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ASHIFTR_CO, s1, s1, last_dest, 1, CY_JUST_SET); PERFORM_SHIFTL_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(SHIFTL_CO, s1, s1, last_dest, 1, CY_JUST_SET); PERFORM_ROTATEL_CO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ROTATEL_CO, s1, s1, last_dest, 1, CY_JUST_SET); if (ci >= 0) { PERFORM_ROTATEXL_CIO(v, co, r1, VALUE(BITS_PER_WORD-1), ci); CRECURSE_2OP(ROTATEXL_CIO, s1, s1, last_dest, 1, CY_JUST_SET); } } } #endif if (ci >= 0 && (prune_hint & CY_0) == 0 && flag_use_carry && (allowed_cost <= 1 ? ((prune_hint & CY_JUST_SET) != 0) : 1)) { #if M68000 || I386 /* d = -cy, cy = cy m68000: subx d,d i80386: sbb d,d */ PERFORM_SUB_CIO(v, co, VALUE(0), VALUE(0), ci); CRECURSE_NEW(SUB_CIO, n_values, n_values, n_values, 1, prune_hint & ~CY_JUST_SET); /* cy not really affected */ #endif #if PYR /* d = -cy, cy = cy pyramid: subwb d,d */ PERFORM_ADC_CIO(v, co, VALUE(0), VALUE(0), ci); CRECURSE_NEW(ADC_CIO, n_values, n_values, n_values, 1, prune_hint & ~CY_JUST_SET); /* cy not really affected */ #endif #if I386 /* slow on m68000 */ /* i80386: cmc */ co = ci ^ 1; CRECURSE_2OP(COMCY, n_values, n_values, n_values, 1, CY_JUST_SET); #endif } /* Move instructions. Don't do this if we are just permitted to do one more instruction. */ if (allowed_cost > 1) { #if M68000 || PYR /* d = 0 m68000: moveq 0,d pyramid: movw 0,d */ PERFORM_COPY(v, co, VALUE(0), ci); CRECURSE_NEW(COPY, n_values, CNST(0), CNST(0), 1, prune_hint & ~CY_JUST_SET); #endif #if M68000 || I386 /* d = 0, cy = 0 m68000: sub d,d i80386: sub d,d */ PERFORM_SUB_CO(v, co, r1, r1, ci); CRECURSE_NEW(SUB_CO, n_values, n_values, n_values, 1, CY_JUST_SET | CY_0); #endif #if PYR /* d = 0, cy = 0 pyramid: subw d,d */ PERFORM_ADC_CO(v, co, r1, r1, ci); CRECURSE_NEW(ADC_CO, n_values, n_values, n_values, 1, CY_JUST_SET | CY_0); #endif #if M68000 /* d = 31 m68000: moveq 31,d */ PERFORM_COPY(v, co, VALUE(BITS_PER_WORD-1), ci); CRECURSE_NEW(COPY, n_values, CNST(BITS_PER_WORD-1), CNST(0), 1, prune_hint & ~CY_JUST_SET); #endif #if M68000 || PYR /* d = 1 m68000: moveq 1,d pyramid: movw $1,d */ PERFORM_COPY(v, co, VALUE(1), ci); CRECURSE_NEW(COPY, n_values, CNST(1), CNST(0), 1, prune_hint & ~CY_JUST_SET); /* d = -1 m68000: moveq -1,d pyramid: movw $-1,d */ PERFORM_COPY(v, co, VALUE(-1), ci); CRECURSE_NEW(COPY, n_values, CNST(-1), CNST(0), 1, prune_hint & ~CY_JUST_SET); #endif #if M68000 || I386 || PYR /* these cost 2 cost units */ /* d = 0x80000000 */ PERFORM_COPY(v, co, VALUE_MIN_SIGNED, ci); CRECURSE_NEW(COPY, n_values, CNST_0x80000000, CNST(0), 2, prune_hint & ~CY_JUST_SET); /* d = 0x7fffffff */ PERFORM_COPY(v, co, VALUE_MAX_SIGNED, ci); CRECURSE_NEW(COPY, n_values, CNST_0x7FFFFFFF, CNST(0), 2, prune_hint & ~CY_JUST_SET); #endif } } #endif /* Call `synth' allowing deeper and deeper searches for each call. This way we achieve iterative deepening search. MAXMAX_COST is the maximum cost for any sequence we will accept. */ void main_synth(int maxmax_cost, int allowed_extra_cost) { int max_cost; word values[0x100]; insn_t sequence[0x100]; int i, ii; init_immediates(tvalues); init_immediates(values); init_test_sets(); /* Speed hack: Try to find random values that makes the goal function take a value != 0. Many false sequences give 0 for all input, and this hack achieve quick reject of these sequences. */ for (i = 0; i < 50; i++) { for (ii = 0; ii < goal_function_arity; ii++) values[ii] = random_word(); if ((*eval_goal_function)(values) != 0) break; } ii = 0; #if KNOW_START switch (goal_function) { case FFS: #if M88000 /* Best ffs starting place. */ sequence[ii++] = (insn_t) { ADC_CO, CNST(0), 0, 1 }; sequence[ii++] = (insn_t) { AND, 0, 1, 2 }; #endif break; case ZDEPI_FOR_MOVSI: #if SPARC sequence[ii++] = (insn_t) { SUB, CNST(0), 0, 1 }; sequence[ii++] = (insn_t) { AND, 0, 1, 2 }; #endif break; default: break; } #endif fprintf(stderr, "Superoptimizing at cost"); success = 0; for (max_cost = 1; max_cost <= maxmax_cost; max_cost++) { #if TIMING for (i = 0; i <= max_cost; i++) timings[i] = 0; #endif if (success) fprintf (stderr, "[cost %d]\n", max_cost + ii); else fprintf(stderr, " %d", max_cost + ii); fflush(stderr); i = run_program (sequence, ii, values); /* Don't pass CY_JUST_SET ever, since we don't know which of the predefined insn above set cy. */ synth(sequence, ii, values, goal_function_arity+ii, (*eval_goal_function)(values), max_cost, i, NO_PRUNE); #ifdef STATISTICS if (isatty(fileno(stdout)) == isatty(fileno(stderr))) printf("\n"); printf("heuristic accept count:%u\n", heuristic_accept_count); printf("heuristic reject count:%u\n", heuristic_reject_count); #endif #if TIMING for (i = 1; i <= max_cost; i++) printf ("time %d: %d\n", i, timings[i] - timings[i - 1]); #endif if (success) { allowed_extra_cost--; if (allowed_extra_cost < 0) { static char *s[] = {"", "s"}; fprintf(stderr, " [%d sequence%s found]\n", success, s[success != 1]); return; } } } fprintf(stderr, " failure.\n"); } /* Create a function for each DEF_GOAL. When optimized, these are very efficient. */ #undef DEF_GOAL #ifdef __STDC__ #define DEF_GOAL(SYM,ARITY,NAME,CODE) \ word SYM ## _func (const word *v) \ GOAL_FUNCTION (ARITY, CODE) #else #define DEF_GOAL(SYM,ARITY,NAME,CODE) \ word SYM/**/_func (v) word *v; \ GOAL_FUNCTION (ARITY, CODE) #endif #define GOAL_FUNCTION(ARITY,CODE) \ { \ word r, v0, v1, v2, v3; \ switch (ARITY) \ { \ default: \ abort (); \ case 4: v3 = v[3]; \ case 3: v2 = v[2]; \ case 2: v1 = v[1]; \ case 1: v0 = v[0]; \ } \ CODE; \ return r; \ } #undef DEF_SYNONYM #define DEF_SYNONYM(SYM,NAME) #include "goal.def" struct { char *fname; enum goal_func fcode; int arity; char *c_code; word (*function)(const word*); } goal_table[] = { /* Start off with entries so that goal_names[i].fcode == i. */ #undef DEF_GOAL #ifdef __STDC__ #define DEF_GOAL(SYM,ARITY,NAME,CODE) {NAME, SYM, ARITY, #CODE, SYM ## _func}, #else #define DEF_GOAL(SYM,ARITY,NAME,CODE) {NAME, SYM, ARITY, "CODE", SYM/**/_func}, #endif #undef DEF_SYNONYM #define DEF_SYNONYM(SYM,NAME) #include "goal.def" /* Now add the synonyms. */ #undef DEF_GOAL #define DEF_GOAL(SYM,ARITY,NAME,CODE) #undef DEF_SYNONYM #define DEF_SYNONYM(SYM,NAME) {NAME, SYM, 0, 0}, #include "goal.def" }; #define GET_GOAL_NAME(X) (goal_table[X].fname) #define GET_GOAL_ARITY(X) (goal_table[X].arity) #define GET_GOAL_C_CODE(X) (goal_table[X].c_code) #define GET_GOAL_FUNCTION(X) (goal_table[X].function) int main(int argc, char **argv) { int maxmax_cost = 5; int allowed_extra_cost = 0; int flag_all = 0; goal_function = LAST_AND_UNUSED_GOAL_CODE; argv++; argc--; while (argc > 0) { char *arg = argv[0]; int arglen = strlen(arg); if (arglen < 2) arglen = 2; if (!strncmp(arg, "-version", arglen)) { printf ("GSO version %s\n", version_string); if (argc == 1) exit (0); } else if (!strncmp(arg, "-assembler", arglen)) flag_output_assembler = 1; else if (!strncmp(arg, "-no-carry-insns", arglen)) flag_use_carry = 0; else if (!strncmp(arg, "-all", arglen)) flag_all = 1; else if (!strncmp(arg, "-max-cost", arglen)) { argv++; argc--; if (argc == 0) { fprintf(stderr, "superoptimizer: argument to `-max-cost' expected\n"); exit(-1); } maxmax_cost = atoi(argv[0]); } else if (!strncmp(arg, "-extra-cost", arglen)) { argv++; argc--; if (argc == 0) { fprintf(stderr, "superoptimizer: argument `-extra-cost' expected\n"); exit(-1); } allowed_extra_cost = atoi(argv[0]); } else if (!strncmp(arg, "-f", 2)) { int i; for (i = 0; i < sizeof(goal_table) / sizeof(goal_table[0]); i++) { if (!strcmp(arg + 2, goal_table[i].fname)) { goal_function = goal_table[i].fcode; goal_function_arity = GET_GOAL_ARITY(goal_function); eval_goal_function = GET_GOAL_FUNCTION(goal_function); break; } } if (goal_function == LAST_AND_UNUSED_GOAL_CODE) { fprintf(stderr, "superoptimizer: unknown goal function\n"); exit(-1); } } else { fprintf(stderr, "superoptimizer: syntax error at command line\n"); exit(-1); } argv++; argc--; } if (flag_all) { for (goal_function = 0; goal_function < LAST_AND_UNUSED_GOAL_CODE; goal_function++) { fprintf(stderr, "Searching for goal %s\n", GET_GOAL_NAME (goal_function)); goal_function_arity = GET_GOAL_ARITY(goal_function); eval_goal_function = GET_GOAL_FUNCTION(goal_function); main_synth(maxmax_cost, allowed_extra_cost); if (success) fprintf(stderr, "%s\n", GET_GOAL_C_CODE(goal_function)); } return 0; } if (goal_function == LAST_AND_UNUSED_GOAL_CODE) { fprintf(stderr, "superoptimizer: missing goal function definition\n"); exit(-1); } fprintf(stderr, "Searching for %s\n", GET_GOAL_C_CODE(goal_function)); main_synth(maxmax_cost, allowed_extra_cost); return !success; } /* Aux stuff that should go into a separate file. */ int ffs_internal(x) word x; { int co, ci; word d; PERFORM_FFS(d, co, x, ci); return d; } const char clz_tab[] = { 32,31,30,30,29,29,29,29,28,28,28,28,28,28,28,28, 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, 26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, 26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, }; const char ctz_tab[] = { 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, }; const char ff1_tab[] = { 32,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, };