Initial commit to Gerrit
[profile/ivi/orc.git] / orc / orcprogram-sse.c
1
2 #include "config.h"
3
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7
8 #include <sys/types.h>
9
10 #include <orc/orcprogram.h>
11 #include <orc/orcx86.h>
12 #include <orc/orcsse.h>
13 #include <orc/orcutils.h>
14 #include <orc/orcdebug.h>
15
16 #undef MMX
17 #define SIZE 65536
18
19 #define ORC_SSE_ALIGNED_DEST_CUTOFF 64
20
21 void orc_sse_emit_loop (OrcCompiler *compiler, int offset, int update);
22
23 void orc_compiler_sse_init (OrcCompiler *compiler);
24 unsigned int orc_compiler_sse_get_default_flags (void);
25 void orc_compiler_sse_assemble (OrcCompiler *compiler);
26 void orc_compiler_sse_register_rules (OrcTarget *target);
27 void orc_sse_emit_invariants (OrcCompiler *compiler);
28
29
30 void orc_compiler_rewrite_vars (OrcCompiler *compiler);
31 void orc_compiler_dump (OrcCompiler *compiler);
32 void sse_load_constant (OrcCompiler *compiler, int reg, int size, int value);
33 void sse_load_constant_long (OrcCompiler *compiler, int reg,
34     OrcConstant *constant);
35 static const char * sse_get_flag_name (int shift);
36
37 static OrcTarget sse_target = {
38   "sse",
39 #if defined(HAVE_I386) || defined(HAVE_AMD64)
40   TRUE,
41 #else
42   FALSE,
43 #endif
44   ORC_VEC_REG_BASE,
45   orc_compiler_sse_get_default_flags,
46   orc_compiler_sse_init,
47   orc_compiler_sse_assemble,
48   { { 0 } },
49   0,
50   NULL,
51   sse_load_constant,
52   sse_get_flag_name,
53   NULL,
54   sse_load_constant_long
55 };
56
57
58 extern int orc_x86_sse_flags;
59 extern int orc_x86_mmx_flags;
60
61 void
62 orc_sse_init (void)
63 {
64 #if defined(HAVE_AMD64) || defined(HAVE_I386)
65   /* initializes cache information */
66   orc_sse_get_cpu_flags ();
67 #endif
68
69 #if defined(HAVE_I386)
70 #ifndef MMX
71   if (!(orc_x86_sse_flags & ORC_TARGET_SSE_SSE2)) {
72     sse_target.executable = FALSE;
73   }
74 #else
75   if (!(orc_x86_mmx_flags & ORC_TARGET_MMX_MMX)) {
76     mmx_target.executable = FALSE;
77   }
78 #endif
79 #endif
80
81   orc_target_register (&sse_target);
82
83   orc_compiler_sse_register_rules (&sse_target);
84 }
85
86 unsigned int
87 orc_compiler_sse_get_default_flags (void)
88 {
89   unsigned int flags = 0;
90
91 #ifdef HAVE_AMD64
92   flags |= ORC_TARGET_SSE_64BIT;
93 #endif
94   if (_orc_compiler_flag_debug) {
95     flags |= ORC_TARGET_SSE_FRAME_POINTER;
96   }
97   
98 #if defined(HAVE_AMD64) || defined(HAVE_I386)
99 #ifndef MMX
100   flags |= orc_x86_sse_flags;
101 #else
102   flags |= orc_x86_mmx_flags;
103 #endif
104 #else
105 #ifndef MMX
106   flags |= ORC_TARGET_SSE_SSE2;
107   flags |= ORC_TARGET_SSE_SSE3;
108   flags |= ORC_TARGET_SSE_SSSE3;
109 #else
110   flags |= ORC_TARGET_MMX_MMX;
111   flags |= ORC_TARGET_MMX_3DNOW;
112 #endif
113 #endif
114
115   return flags;
116 }
117
118 static const char *
119 sse_get_flag_name (int shift)
120 {
121   static const char *flags[] = {
122 #ifndef MMX
123     "sse2", "sse3", "ssse3", "sse41", "sse42", "sse4a", "sse5",
124     "frame_pointer", "short_jumps", "64bit"
125 #else
126     "mmx", "mmxext", "3dnow", "3dnowext", "ssse3", "sse41", "",
127     "frame_pointer", "short_jumps", "64bit"
128 #endif
129   };
130
131   if (shift >= 0 && shift < sizeof(flags)/sizeof(flags[0])) {
132     return flags[shift];
133   }
134
135   return NULL;
136 }
137
138 void
139 orc_compiler_sse_init (OrcCompiler *compiler)
140 {
141   int i;
142
143   if (compiler->target_flags & ORC_TARGET_SSE_64BIT) {
144     compiler->is_64bit = TRUE;
145   }
146   if (compiler->target_flags & ORC_TARGET_SSE_FRAME_POINTER) {
147     compiler->use_frame_pointer = TRUE;
148   }
149   if (!(compiler->target_flags & ORC_TARGET_SSE_SHORT_JUMPS)) {
150     compiler->long_jumps = TRUE;
151   }
152   
153
154   if (compiler->is_64bit) {
155     for(i=ORC_GP_REG_BASE;i<ORC_GP_REG_BASE+16;i++){
156       compiler->valid_regs[i] = 1;
157     }
158     compiler->valid_regs[X86_ESP] = 0;
159 #ifndef MMX
160     for(i=X86_XMM0;i<X86_XMM0+16;i++){
161       compiler->valid_regs[i] = 1;
162     }
163 #else
164     for(i=X86_XMM0;i<X86_XMM0+8;i++){
165       compiler->valid_regs[i] = 1;
166     }
167 #endif
168     compiler->save_regs[X86_EBX] = 1;
169     compiler->save_regs[X86_EBP] = 1;
170     compiler->save_regs[X86_R12] = 1;
171     compiler->save_regs[X86_R13] = 1;
172     compiler->save_regs[X86_R14] = 1;
173     compiler->save_regs[X86_R15] = 1;
174 #ifdef HAVE_OS_WIN32
175     compiler->save_regs[X86_EDI] = 1;
176     compiler->save_regs[X86_ESI] = 1;
177     for(i=X86_XMM0+6;i<X86_XMM0+16;i++){
178       compiler->save_regs[i] = 1;
179     }
180 #endif
181   } else {
182     for(i=ORC_GP_REG_BASE;i<ORC_GP_REG_BASE+8;i++){
183       compiler->valid_regs[i] = 1;
184     }
185     compiler->valid_regs[X86_ESP] = 0;
186     if (compiler->use_frame_pointer) {
187       compiler->valid_regs[X86_EBP] = 0;
188     }
189     for(i=X86_XMM0;i<X86_XMM0+8;i++){
190       compiler->valid_regs[i] = 1;
191     }
192     compiler->save_regs[X86_EBX] = 1;
193     compiler->save_regs[X86_EDI] = 1;
194     compiler->save_regs[X86_EBP] = 1;
195   }
196   for(i=0;i<128;i++){
197     compiler->alloc_regs[i] = 0;
198     compiler->used_regs[i] = 0;
199   }
200
201   if (compiler->is_64bit) {
202 #ifdef HAVE_OS_WIN32
203     compiler->exec_reg = X86_ECX;
204     compiler->gp_tmpreg = X86_EDX;
205 #else
206     compiler->exec_reg = X86_EDI;
207     compiler->gp_tmpreg = X86_ECX;
208 #endif
209   } else {
210     compiler->gp_tmpreg = X86_ECX;
211     if (compiler->use_frame_pointer) {
212       compiler->exec_reg = X86_EBX;
213     } else {
214       compiler->exec_reg = X86_EBP;
215     }
216   }
217   compiler->valid_regs[compiler->gp_tmpreg] = 0;
218   compiler->valid_regs[compiler->exec_reg] = 0;
219
220   switch (compiler->max_var_size) {
221     case 1:
222       compiler->loop_shift = 4;
223       break;
224     case 2:
225       compiler->loop_shift = 3;
226       break;
227     case 4:
228       compiler->loop_shift = 2;
229       break;
230     case 8:
231       compiler->loop_shift = 1;
232       break;
233     default:
234       ORC_ERROR("unhandled max var size %d", compiler->max_var_size);
235       break;
236   }
237 #ifdef MMX
238   compiler->loop_shift--;
239 #endif
240
241   /* This limit is arbitrary, but some large functions run slightly
242      slower when unrolled (ginger Core2 6,15,6), and only some small
243      functions run faster when unrolled.  Most are the same speed. */
244   if (compiler->n_insns <= 10) {
245     compiler->unroll_shift = 1;
246   }
247   if (!compiler->long_jumps) {
248     compiler->unroll_shift = 0;
249   }
250   if (compiler->loop_shift == 0) {
251     /* FIXME something is broken with loop_shift=0, unroll_shift=1 */
252     compiler->unroll_shift = 0;
253   }
254   compiler->alloc_loop_counter = TRUE;
255   compiler->allow_gp_on_stack = TRUE;
256
257   {
258     for(i=0;i<compiler->n_insns;i++){
259       OrcInstruction *insn = compiler->insns + i;
260       OrcStaticOpcode *opcode = insn->opcode;
261
262       if (strcmp (opcode->name, "ldreslinb") == 0 ||
263           strcmp (opcode->name, "ldreslinl") == 0 ||
264           strcmp (opcode->name, "ldresnearb") == 0 ||
265           strcmp (opcode->name, "ldresnearl") == 0) {
266         compiler->vars[insn->src_args[0]].need_offset_reg = TRUE;
267       }
268     }
269   }
270 }
271
272 void
273 sse_save_accumulators (OrcCompiler *compiler)
274 {
275   int i;
276   int src;
277   int tmp;
278
279   for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
280     OrcVariable *var = compiler->vars + i;
281
282     if (compiler->vars[i].name == NULL) continue;
283     switch (compiler->vars[i].vartype) {
284       case ORC_VAR_TYPE_ACCUMULATOR:
285         src = compiler->vars[i].alloc;
286         tmp = orc_compiler_get_temp_reg (compiler);
287
288 #ifndef MMX
289         orc_sse_emit_pshufd (compiler, ORC_SSE_SHUF(3,2,3,2), src, tmp);
290 #else
291         orc_mmx_emit_pshufw (compiler, ORC_MMX_SHUF(3,2,3,2), src, tmp);
292 #endif
293
294         if (compiler->vars[i].size == 2) {
295           orc_sse_emit_660f (compiler, "paddw", 0xfd, tmp, src);
296         } else {
297           orc_sse_emit_660f (compiler, "paddd", 0xfe, tmp, src);
298         }
299
300 #ifndef MMX
301         orc_sse_emit_pshufd (compiler, ORC_SSE_SHUF(1,1,1,1), src, tmp);
302
303         if (compiler->vars[i].size == 2) {
304           orc_sse_emit_660f (compiler, "paddw", 0xfd, tmp, src);
305         } else {
306           orc_sse_emit_660f (compiler, "paddd", 0xfe, tmp, src);
307         }
308 #endif
309
310         if (compiler->vars[i].size == 2) {
311 #ifndef MMX
312           orc_sse_emit_pshuflw (compiler, ORC_SSE_SHUF(1,1,1,1), src, tmp);
313 #else
314           orc_mmx_emit_pshufw (compiler, ORC_MMX_SHUF(1,1,1,1), src, tmp);
315 #endif
316
317           orc_sse_emit_660f (compiler, "paddw", 0xfd, tmp, src);
318         }
319
320         if (compiler->vars[i].size == 2) {
321           orc_x86_emit_mov_sse_reg (compiler, src, compiler->gp_tmpreg);
322           orc_x86_emit_and_imm_reg (compiler, 4, 0xffff, compiler->gp_tmpreg);
323           orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
324               (int)ORC_STRUCT_OFFSET(OrcExecutor, accumulators[i-ORC_VAR_A1]),
325               compiler->exec_reg);
326         } else {
327           orc_x86_emit_mov_sse_memoffset (compiler, 4, src,
328               (int)ORC_STRUCT_OFFSET(OrcExecutor, accumulators[i-ORC_VAR_A1]),
329               compiler->exec_reg,
330               var->is_aligned, var->is_uncached);
331         }
332
333         break;
334       default:
335         break;
336     }
337   }
338 }
339
340 void
341 sse_load_constant (OrcCompiler *compiler, int reg, int size, int value)
342 {
343   orc_sse_load_constant (compiler, reg, size, value);
344 }
345
346 void
347 orc_sse_load_constant (OrcCompiler *compiler, int reg, int size, orc_uint64 value)
348 {
349   int i;
350
351   if (size == 8) {
352     int offset = ORC_STRUCT_OFFSET(OrcExecutor,arrays[ORC_VAR_T1]);
353
354     /* FIXME how ugly and slow! */
355     orc_x86_emit_mov_imm_reg (compiler, 4, value>>0,
356         compiler->gp_tmpreg);
357     orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
358         offset + 0, compiler->exec_reg);
359
360     orc_x86_emit_mov_imm_reg (compiler, 4, value>>32,
361         compiler->gp_tmpreg);
362     orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
363         offset + 4, compiler->exec_reg);
364
365     orc_x86_emit_mov_memoffset_sse (compiler, 8, offset, compiler->exec_reg,
366         reg, FALSE);
367 #ifndef MMX
368     orc_sse_emit_pshufd (compiler, ORC_SSE_SHUF(1,0,1,0), reg, reg);
369 #endif
370     return;
371   }
372
373   if (size == 1) {
374     value &= 0xff;
375     value |= (value << 8);
376     value |= (value << 16);
377   }
378   if (size == 2) {
379     value &= 0xffff;
380     value |= (value << 16);
381   }
382
383   ORC_ASM_CODE(compiler, "# loading constant %d 0x%08x\n", (int)value, (int)value);
384   if (value == 0) {
385     orc_sse_emit_pxor(compiler, reg, reg);
386     return;
387   }
388   if (value == 0xffffffff) {
389     orc_sse_emit_pcmpeqb (compiler, reg, reg);
390     return;
391   }
392   if (compiler->target_flags & ORC_TARGET_SSE_SSSE3) {
393     if (value == 0x01010101) {
394       orc_sse_emit_pcmpeqb (compiler, reg, reg);
395       orc_sse_emit_pabsb (compiler, reg, reg);
396       return;
397     }
398   }
399
400   for(i=1;i<32;i++){
401     orc_uint32 v;
402     v = (0xffffffff<<i);
403     if (value == v) {
404       orc_sse_emit_pcmpeqb (compiler, reg, reg);
405       orc_sse_emit_pslld (compiler, i, reg);
406       return;
407     }
408     v = (0xffffffff>>i);
409     if (value == v) {
410       orc_sse_emit_pcmpeqb (compiler, reg, reg);
411       orc_sse_emit_psrld (compiler, i, reg);
412       return;
413     }
414   }
415   for(i=1;i<16;i++){
416     orc_uint32 v;
417     v = (0xffff & (0xffff<<i)) | (0xffff0000 & (0xffff0000<<i));
418     if (value == v) {
419       orc_sse_emit_pcmpeqb (compiler, reg, reg);
420       orc_sse_emit_psllw (compiler, i, reg);
421       return;
422     }
423     v = (0xffff & (0xffff>>i)) | (0xffff0000 & (0xffff0000>>i));
424     if (value == v) {
425       orc_sse_emit_pcmpeqb (compiler, reg, reg);
426       orc_sse_emit_psrlw (compiler, i, reg);
427       return;
428     }
429   }
430
431   orc_x86_emit_mov_imm_reg (compiler, 4, value, compiler->gp_tmpreg);
432   orc_x86_emit_mov_reg_sse (compiler, compiler->gp_tmpreg, reg);
433 #ifndef MMX
434   orc_sse_emit_pshufd (compiler, ORC_SSE_SHUF(0,0,0,0), reg, reg);
435 #else
436   orc_mmx_emit_pshufw (compiler, ORC_MMX_SHUF(1,0,1,0), reg, reg);
437 #endif
438 }
439
440 void
441 sse_load_constant_long (OrcCompiler *compiler, int reg,
442     OrcConstant *constant)
443 {
444   int i;
445   int offset = ORC_STRUCT_OFFSET(OrcExecutor,arrays[ORC_VAR_T1]);
446
447   /* FIXME this is slower than it could be */
448
449   ORC_ASM_CODE(compiler, "# loading constant %08x %08x %08x %08x\n",
450       constant->full_value[0], constant->full_value[1],
451       constant->full_value[2], constant->full_value[3]);
452
453   for(i=0;i<4;i++){
454     orc_x86_emit_mov_imm_reg (compiler, 4, constant->full_value[i],
455         compiler->gp_tmpreg);
456     orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
457         offset + 4*i, compiler->exec_reg);
458   }
459   orc_x86_emit_mov_memoffset_sse (compiler, 16, offset, compiler->exec_reg,
460       reg, FALSE);
461
462 }
463
464 void
465 sse_load_constants_outer (OrcCompiler *compiler)
466 {
467   int i;
468   for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
469     if (compiler->vars[i].name == NULL) continue;
470     switch (compiler->vars[i].vartype) {
471       case ORC_VAR_TYPE_CONST:
472         break;
473       case ORC_VAR_TYPE_PARAM:
474         break;
475       case ORC_VAR_TYPE_SRC:
476       case ORC_VAR_TYPE_DEST:
477         break;
478       case ORC_VAR_TYPE_ACCUMULATOR:
479         orc_sse_emit_pxor (compiler,
480             compiler->vars[i].alloc, compiler->vars[i].alloc);
481         break;
482       case ORC_VAR_TYPE_TEMP:
483         break;
484       default:
485         ORC_COMPILER_ERROR(compiler,"bad vartype");
486         break;
487     }
488   }
489
490   orc_sse_emit_invariants (compiler);
491
492   /* FIXME move to a better place */
493   for(i=0;i<compiler->n_constants;i++){
494     compiler->constants[i].alloc_reg =
495       orc_compiler_get_constant_reg (compiler);
496   }
497
498   for(i=0;i<compiler->n_constants;i++){
499     if (compiler->constants[i].alloc_reg) {
500       if (compiler->constants[i].is_long) {
501         sse_load_constant_long (compiler, compiler->constants[i].alloc_reg,
502             compiler->constants + i);
503       } else {
504         sse_load_constant (compiler, compiler->constants[i].alloc_reg,
505             4, compiler->constants[i].value);
506       }
507     }
508   }
509
510   {
511     for(i=0;i<compiler->n_insns;i++){
512       OrcInstruction *insn = compiler->insns + i;
513       OrcStaticOpcode *opcode = insn->opcode;
514
515       if (strcmp (opcode->name, "ldreslinb") == 0 ||
516           strcmp (opcode->name, "ldreslinl") == 0 ||
517           strcmp (opcode->name, "ldresnearb") == 0 ||
518           strcmp (opcode->name, "ldresnearl") == 0) {
519         if (compiler->vars[insn->src_args[1]].vartype == ORC_VAR_TYPE_PARAM) {
520           orc_x86_emit_mov_memoffset_reg (compiler, 4,
521               (int)ORC_STRUCT_OFFSET(OrcExecutor, params[insn->src_args[1]]),
522               compiler->exec_reg,
523               compiler->vars[insn->src_args[0]].ptr_offset);
524         } else {
525           orc_x86_emit_mov_imm_reg (compiler, 4,
526               compiler->vars[insn->src_args[1]].value.i,
527               compiler->vars[insn->src_args[0]].ptr_offset);
528         }
529       }
530     }
531   }
532 }
533
534 void
535 sse_load_constants_inner (OrcCompiler *compiler)
536 {
537   int i;
538   for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
539     if (compiler->vars[i].name == NULL) continue;
540     switch (compiler->vars[i].vartype) {
541       case ORC_VAR_TYPE_CONST:
542         break;
543       case ORC_VAR_TYPE_PARAM:
544         break;
545       case ORC_VAR_TYPE_SRC:
546       case ORC_VAR_TYPE_DEST:
547         if (compiler->vars[i].ptr_register) {
548           orc_x86_emit_mov_memoffset_reg (compiler, compiler->is_64bit ? 8 : 4,
549               (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]), compiler->exec_reg,
550               compiler->vars[i].ptr_register);
551         }
552         break;
553       case ORC_VAR_TYPE_ACCUMULATOR:
554         break;
555       case ORC_VAR_TYPE_TEMP:
556         break;
557       default:
558         ORC_COMPILER_ERROR(compiler,"bad vartype");
559         break;
560     }
561   }
562 }
563
564 void
565 sse_add_strides (OrcCompiler *compiler)
566 {
567   int i;
568
569   for(i=0;i<ORC_N_COMPILER_VARIABLES;i++){
570     if (compiler->vars[i].name == NULL) continue;
571     switch (compiler->vars[i].vartype) {
572       case ORC_VAR_TYPE_CONST:
573         break;
574       case ORC_VAR_TYPE_PARAM:
575         break;
576       case ORC_VAR_TYPE_SRC:
577       case ORC_VAR_TYPE_DEST:
578         orc_x86_emit_mov_memoffset_reg (compiler, 4,
579             (int)ORC_STRUCT_OFFSET(OrcExecutor, params[i]), compiler->exec_reg,
580             compiler->gp_tmpreg);
581         orc_x86_emit_add_reg_memoffset (compiler, compiler->is_64bit ? 8 : 4,
582             compiler->gp_tmpreg,
583             (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[i]), compiler->exec_reg);
584
585         if (compiler->vars[i].ptr_register == 0) {
586           ORC_COMPILER_ERROR(compiler, "unimplemented: stride on mem pointer");
587         }
588         break;
589       case ORC_VAR_TYPE_ACCUMULATOR:
590         break;
591       case ORC_VAR_TYPE_TEMP:
592         break;
593       default:
594         ORC_COMPILER_ERROR(compiler,"bad vartype");
595         break;
596     }
597   }
598 }
599
600 static int
601 get_align_var (OrcCompiler *compiler)
602 {
603   int i;
604   for(i=ORC_VAR_D1;i<=ORC_VAR_S8;i++){
605     if (compiler->vars[i].size == 0) continue;
606     if ((compiler->vars[i].size << compiler->loop_shift) >= 16) {
607       return i;
608     }
609   }
610   for(i=ORC_VAR_D1;i<=ORC_VAR_S8;i++){
611     if (compiler->vars[i].size == 0) continue;
612     if ((compiler->vars[i].size << compiler->loop_shift) >= 8) {
613       return i;
614     }
615   }
616   for(i=ORC_VAR_D1;i<=ORC_VAR_S8;i++){
617     if (compiler->vars[i].size == 0) continue;
618     return i;
619   }
620
621   ORC_COMPILER_ERROR(compiler, "could not find alignment variable");
622
623   return -1;
624 }
625
626 static int
627 get_shift (int size)
628 {
629   switch (size) {
630     case 1:
631       return 0;
632     case 2:
633       return 1;
634     case 4:
635       return 2;
636     case 8:
637       return 3;
638     default:
639       ORC_ERROR("bad size %d", size);
640   }
641   return -1;
642 }
643
644
645 static void
646 orc_emit_split_3_regions (OrcCompiler *compiler)
647 {
648   int align_var;
649   int align_shift;
650   int var_size_shift;
651
652   align_var = get_align_var (compiler);
653   var_size_shift = get_shift (compiler->vars[align_var].size);
654   align_shift = var_size_shift + compiler->loop_shift;
655
656   /* determine how many iterations until align array is aligned (n1) */
657   orc_x86_emit_mov_imm_reg (compiler, 4, 16, X86_EAX);
658   orc_x86_emit_sub_memoffset_reg (compiler, 4,
659       (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[align_var]),
660       compiler->exec_reg, X86_EAX);
661   orc_x86_emit_and_imm_reg (compiler, 4, (1<<align_shift) - 1, X86_EAX);
662   orc_x86_emit_sar_imm_reg (compiler, 4, var_size_shift, X86_EAX);
663
664   /* check if n1 is greater than n. */
665   orc_x86_emit_cmp_reg_memoffset (compiler, 4, X86_EAX,
666       (int)ORC_STRUCT_OFFSET(OrcExecutor,n), compiler->exec_reg);
667
668   orc_x86_emit_jle (compiler, 6);
669
670   /* If so, we have a standard 3-region split. */
671   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
672       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter1), compiler->exec_reg);
673     
674   /* Calculate n2 */
675   orc_x86_emit_mov_memoffset_reg (compiler, 4,
676       (int)ORC_STRUCT_OFFSET(OrcExecutor,n), compiler->exec_reg,
677       compiler->gp_tmpreg);
678   orc_x86_emit_sub_reg_reg (compiler, 4, X86_EAX, compiler->gp_tmpreg);
679
680   orc_x86_emit_mov_reg_reg (compiler, 4, compiler->gp_tmpreg, X86_EAX);
681
682   orc_x86_emit_sar_imm_reg (compiler, 4,
683       compiler->loop_shift + compiler->unroll_shift,
684       compiler->gp_tmpreg);
685   orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
686       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2), compiler->exec_reg);
687
688   /* Calculate n3 */
689   orc_x86_emit_and_imm_reg (compiler, 4,
690       (1<<(compiler->loop_shift + compiler->unroll_shift))-1, X86_EAX);
691   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
692       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter3), compiler->exec_reg);
693
694   orc_x86_emit_jmp (compiler, 7);
695
696   /* else, iterations are all unaligned: n1=n, n2=0, n3=0 */
697   orc_x86_emit_label (compiler, 6);
698
699   orc_x86_emit_mov_memoffset_reg (compiler, 4,
700       (int)ORC_STRUCT_OFFSET(OrcExecutor,n), compiler->exec_reg, X86_EAX);
701   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
702       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter1), compiler->exec_reg);
703   orc_x86_emit_mov_imm_reg (compiler, 4, 0, X86_EAX);
704   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
705       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2), compiler->exec_reg);
706   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
707       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter3), compiler->exec_reg);
708
709   orc_x86_emit_label (compiler, 7);
710 }
711
712 static void
713 orc_emit_split_2_regions (OrcCompiler *compiler)
714 {
715   int align_var;
716   int align_shift;
717   int var_size_shift;
718
719   align_var = get_align_var (compiler);
720   var_size_shift = get_shift (compiler->vars[align_var].size);
721   align_shift = var_size_shift + compiler->loop_shift;
722
723   /* Calculate n2 */
724   orc_x86_emit_mov_memoffset_reg (compiler, 4,
725       (int)ORC_STRUCT_OFFSET(OrcExecutor,n), compiler->exec_reg,
726       compiler->gp_tmpreg);
727   orc_x86_emit_mov_reg_reg (compiler, 4, compiler->gp_tmpreg, X86_EAX);
728   orc_x86_emit_sar_imm_reg (compiler, 4,
729       compiler->loop_shift + compiler->unroll_shift,
730       compiler->gp_tmpreg);
731   orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
732       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2), compiler->exec_reg);
733
734   /* Calculate n3 */
735   orc_x86_emit_and_imm_reg (compiler, 4,
736       (1<<(compiler->loop_shift + compiler->unroll_shift))-1, X86_EAX);
737   orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
738       (int)ORC_STRUCT_OFFSET(OrcExecutor,counter3), compiler->exec_reg);
739 }
740
741 #ifndef MMX
742 static int
743 orc_program_has_float (OrcCompiler *compiler)
744 {
745   int j;
746   for(j=0;j<compiler->n_insns;j++){
747     OrcInstruction *insn = compiler->insns + j;
748     OrcStaticOpcode *opcode = insn->opcode;
749     if (opcode->flags & ORC_STATIC_OPCODE_FLOAT) return TRUE;
750   }
751   return FALSE;
752 }
753 #endif
754
755 #define LABEL_REGION1_SKIP 1
756 #define LABEL_INNER_LOOP_START 2
757 #define LABEL_REGION2_SKIP 3
758 #define LABEL_OUTER_LOOP 4
759 #define LABEL_OUTER_LOOP_SKIP 5
760 #define LABEL_STEP_DOWN(x) (8+(x))
761 #define LABEL_STEP_UP(x) (13+(x))
762
763
764 void
765 orc_compiler_sse_assemble (OrcCompiler *compiler)
766 {
767 #ifndef MMX
768   int set_mxcsr = FALSE;
769 #endif
770   int align_var;
771
772   if (0 && orc_x86_assemble_copy_check (compiler)) {
773     /* The rep movs implementation isn't faster most of the time */
774     orc_x86_assemble_copy (compiler);
775     return;
776   }
777
778   align_var = get_align_var (compiler);
779
780   compiler->vars[align_var].is_aligned = FALSE;
781
782   {
783     orc_sse_emit_loop (compiler, 0, 0);
784
785     compiler->codeptr = compiler->code;
786     free (compiler->asm_code);
787     compiler->asm_code = NULL;
788     compiler->asm_code_len = 0;
789     memset (compiler->labels, 0, sizeof (compiler->labels));
790     compiler->n_fixups = 0;
791   }
792
793   if (compiler->error) return;
794
795   orc_x86_emit_prologue (compiler);
796
797 #ifndef MMX
798   if (orc_program_has_float (compiler)) {
799     set_mxcsr = TRUE;
800     orc_sse_set_mxcsr (compiler);
801   }
802 #endif
803
804   sse_load_constants_outer (compiler);
805
806   if (compiler->program->is_2d) {
807     if (compiler->program->constant_m > 0) {
808       orc_x86_emit_mov_imm_reg (compiler, 4, compiler->program->constant_m,
809           X86_EAX);
810       orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
811           (int)ORC_STRUCT_OFFSET(OrcExecutor, params[ORC_VAR_A2]),
812           compiler->exec_reg);
813     } else {
814       orc_x86_emit_mov_memoffset_reg (compiler, 4,
815           (int)ORC_STRUCT_OFFSET(OrcExecutor, params[ORC_VAR_A1]),
816           compiler->exec_reg, X86_EAX);
817       orc_x86_emit_test_reg_reg (compiler, 4, X86_EAX, X86_EAX);
818       orc_x86_emit_jle (compiler, LABEL_OUTER_LOOP_SKIP);
819       orc_x86_emit_mov_reg_memoffset (compiler, 4, X86_EAX,
820           (int)ORC_STRUCT_OFFSET(OrcExecutor, params[ORC_VAR_A2]),
821           compiler->exec_reg);
822     }
823
824     orc_x86_emit_label (compiler, LABEL_OUTER_LOOP);
825   }
826
827   if (compiler->program->constant_n > 0 &&
828       compiler->program->constant_n <= ORC_SSE_ALIGNED_DEST_CUTOFF) {
829     /* don't need to load n */
830   } else if (compiler->loop_shift > 0) {
831     if (!compiler->has_iterator_opcode) {
832       /* split n into three regions, with center region being aligned */
833       orc_emit_split_3_regions (compiler);
834     } else {
835       orc_emit_split_2_regions (compiler);
836     }
837   } else {
838     /* loop shift is 0, no need to split */
839     orc_x86_emit_mov_memoffset_reg (compiler, 4,
840         (int)ORC_STRUCT_OFFSET(OrcExecutor,n), compiler->exec_reg,
841         compiler->gp_tmpreg);
842     orc_x86_emit_mov_reg_memoffset (compiler, 4, compiler->gp_tmpreg,
843         (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2), compiler->exec_reg);
844   }
845
846   sse_load_constants_inner (compiler);
847
848   if (compiler->program->constant_n > 0 &&
849       compiler->program->constant_n <= ORC_SSE_ALIGNED_DEST_CUTOFF) {
850     int n_left = compiler->program->constant_n;
851     int save_loop_shift;
852     int loop_shift;
853
854     compiler->offset = 0;
855
856     save_loop_shift = compiler->loop_shift;
857     while (n_left >= (1<<compiler->loop_shift)) {
858       ORC_ASM_CODE(compiler, "# LOOP SHIFT %d\n", compiler->loop_shift);
859       orc_sse_emit_loop (compiler, compiler->offset, 0);
860
861       n_left -= 1<<compiler->loop_shift;
862       compiler->offset += 1<<compiler->loop_shift;
863     }
864     for(loop_shift = compiler->loop_shift-1; loop_shift>=0; loop_shift--) {
865       if (n_left >= (1<<loop_shift)) {
866         compiler->loop_shift = loop_shift;
867         ORC_ASM_CODE(compiler, "# LOOP SHIFT %d\n", loop_shift);
868         orc_sse_emit_loop (compiler, compiler->offset, 0);
869         n_left -= 1<<loop_shift;
870         compiler->offset += 1<<loop_shift;
871       }
872     }
873     compiler->loop_shift = save_loop_shift;
874
875   } else {
876     int ui, ui_max;
877     int emit_region1 = TRUE;
878     int emit_region3 = TRUE;
879
880     if (compiler->has_iterator_opcode) {
881       emit_region1 = FALSE;
882     }
883     if (compiler->loop_shift == 0) {
884       emit_region1 = FALSE;
885       emit_region3 = FALSE;
886     }
887
888     if (emit_region1) {
889       int save_loop_shift;
890       int l;
891
892       save_loop_shift = compiler->loop_shift;
893       compiler->vars[align_var].is_aligned = FALSE;
894
895       for (l=0;l<save_loop_shift;l++){
896         compiler->loop_shift = l;
897         ORC_ASM_CODE(compiler, "# LOOP SHIFT %d\n", compiler->loop_shift);
898
899         orc_x86_emit_test_imm_memoffset (compiler, 4, 1<<compiler->loop_shift,
900             (int)ORC_STRUCT_OFFSET(OrcExecutor,counter1), compiler->exec_reg);
901         orc_x86_emit_je (compiler, LABEL_STEP_UP(compiler->loop_shift));
902         orc_sse_emit_loop (compiler, 0, 1<<compiler->loop_shift);
903         orc_x86_emit_label (compiler, LABEL_STEP_UP(compiler->loop_shift));
904       }
905
906       compiler->loop_shift = save_loop_shift;
907       compiler->vars[align_var].is_aligned = TRUE;
908     }
909
910     orc_x86_emit_label (compiler, LABEL_REGION1_SKIP);
911
912     orc_x86_emit_cmp_imm_memoffset (compiler, 4, 0,
913         (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2), compiler->exec_reg);
914     orc_x86_emit_je (compiler, LABEL_REGION2_SKIP);
915
916     if (compiler->loop_counter != ORC_REG_INVALID) {
917       orc_x86_emit_mov_memoffset_reg (compiler, 4,
918           (int)ORC_STRUCT_OFFSET(OrcExecutor, counter2), compiler->exec_reg,
919           compiler->loop_counter);
920     }
921
922     ORC_ASM_CODE(compiler, "# LOOP SHIFT %d\n", compiler->loop_shift);
923     orc_x86_emit_align (compiler);
924     orc_x86_emit_label (compiler, LABEL_INNER_LOOP_START);
925     ui_max = 1<<compiler->unroll_shift;
926     for(ui=0;ui<ui_max;ui++) {
927       compiler->offset = ui<<compiler->loop_shift;
928       orc_sse_emit_loop (compiler, compiler->offset,
929           (ui==ui_max-1) << (compiler->loop_shift + compiler->unroll_shift));
930     }
931     compiler->offset = 0;
932     if (compiler->loop_counter != ORC_REG_INVALID) {
933       orc_x86_emit_add_imm_reg (compiler, 4, -1, compiler->loop_counter, TRUE);
934     } else {
935       orc_x86_emit_dec_memoffset (compiler, 4,
936           (int)ORC_STRUCT_OFFSET(OrcExecutor,counter2),
937           compiler->exec_reg);
938     }
939     orc_x86_emit_jne (compiler, LABEL_INNER_LOOP_START);
940     orc_x86_emit_label (compiler, LABEL_REGION2_SKIP);
941
942     if (emit_region3) {
943       int save_loop_shift;
944       int l;
945
946       save_loop_shift = compiler->loop_shift + compiler->unroll_shift;
947       compiler->vars[align_var].is_aligned = FALSE;
948
949       for(l=save_loop_shift - 1; l >= 0; l--) {
950         compiler->loop_shift = l;
951         ORC_ASM_CODE(compiler, "# LOOP SHIFT %d\n", compiler->loop_shift);
952
953         orc_x86_emit_test_imm_memoffset (compiler, 4, 1<<compiler->loop_shift,
954             (int)ORC_STRUCT_OFFSET(OrcExecutor,counter3), compiler->exec_reg);
955         orc_x86_emit_je (compiler, LABEL_STEP_DOWN(compiler->loop_shift));
956         orc_sse_emit_loop (compiler, 0, 1<<compiler->loop_shift);
957         orc_x86_emit_label (compiler, LABEL_STEP_DOWN(compiler->loop_shift));
958       }
959
960       compiler->loop_shift = save_loop_shift;
961     }
962   }
963
964   if (compiler->program->is_2d && compiler->program->constant_m != 1) {
965     sse_add_strides (compiler);
966
967     orc_x86_emit_add_imm_memoffset (compiler, 4, -1,
968         (int)ORC_STRUCT_OFFSET(OrcExecutor,params[ORC_VAR_A2]),
969         compiler->exec_reg);
970     orc_x86_emit_jne (compiler, LABEL_OUTER_LOOP);
971     orc_x86_emit_label (compiler, LABEL_OUTER_LOOP_SKIP);
972   }
973
974   sse_save_accumulators (compiler);
975
976 #ifndef MMX
977   if (set_mxcsr) {
978     orc_sse_restore_mxcsr (compiler);
979   }
980 #else
981   orc_x86_emit_emms (compiler);
982 #endif
983   orc_x86_emit_epilogue (compiler);
984
985   orc_x86_do_fixups (compiler);
986 }
987
988 void
989 orc_sse_emit_loop (OrcCompiler *compiler, int offset, int update)
990 {
991   int j;
992   int k;
993   OrcInstruction *insn;
994   OrcStaticOpcode *opcode;
995   OrcRule *rule;
996
997   for(j=0;j<compiler->n_insns;j++){
998     insn = compiler->insns + j;
999     opcode = insn->opcode;
1000
1001     compiler->insn_index = j;
1002
1003     if (insn->flags & ORC_INSN_FLAG_INVARIANT) continue;
1004
1005     ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
1006
1007     compiler->min_temp_reg = ORC_VEC_REG_BASE;
1008
1009     compiler->insn_shift = compiler->loop_shift;
1010     if (insn->flags & ORC_INSTRUCTION_FLAG_X2) {
1011       compiler->insn_shift += 1;
1012     }
1013     if (insn->flags & ORC_INSTRUCTION_FLAG_X4) {
1014       compiler->insn_shift += 2;
1015     }
1016
1017     rule = insn->rule;
1018     if (rule && rule->emit) {
1019       if (!(insn->opcode->flags & (ORC_STATIC_OPCODE_ACCUMULATOR|ORC_STATIC_OPCODE_LOAD|ORC_STATIC_OPCODE_STORE)) &&
1020           compiler->vars[insn->dest_args[0]].alloc !=
1021           compiler->vars[insn->src_args[0]].alloc) {
1022         orc_x86_emit_mov_sse_reg_reg (compiler,
1023             compiler->vars[insn->src_args[0]].alloc,
1024             compiler->vars[insn->dest_args[0]].alloc);
1025       }
1026       rule->emit (compiler, rule->emit_user, insn);
1027     } else {
1028       ORC_COMPILER_ERROR(compiler,"No rule for: %s", opcode->name);
1029     }
1030   }
1031
1032   if (update) {
1033     for(k=0;k<ORC_N_COMPILER_VARIABLES;k++){
1034       OrcVariable *var = compiler->vars + k;
1035
1036       if (var->name == NULL) continue;
1037       if (var->vartype == ORC_VAR_TYPE_SRC ||
1038           var->vartype == ORC_VAR_TYPE_DEST) {
1039         int offset;
1040         if (var->update_type == 0) {
1041           offset = 0;
1042         } else if (var->update_type == 1) {
1043           offset = (var->size * update) >> 1;
1044         } else {
1045           offset = var->size * update;
1046         }
1047
1048         if (offset != 0) {
1049           if (compiler->vars[k].ptr_register) {
1050             orc_x86_emit_add_imm_reg (compiler, compiler->is_64bit ? 8 : 4,
1051                 offset,
1052                 compiler->vars[k].ptr_register, FALSE);
1053           } else {
1054             orc_x86_emit_add_imm_memoffset (compiler, compiler->is_64bit ? 8 : 4,
1055                 offset,
1056                 (int)ORC_STRUCT_OFFSET(OrcExecutor, arrays[k]),
1057                 compiler->exec_reg);
1058           }
1059         }
1060       }
1061     }
1062   }
1063 }
1064
1065 void
1066 orc_sse_emit_invariants (OrcCompiler *compiler)
1067 {
1068   int j;
1069   OrcInstruction *insn;
1070   OrcStaticOpcode *opcode;
1071   OrcRule *rule;
1072
1073   for(j=0;j<compiler->n_insns;j++){
1074     insn = compiler->insns + j;
1075     opcode = insn->opcode;
1076
1077     if (!(insn->flags & ORC_INSN_FLAG_INVARIANT)) continue;
1078
1079     ORC_ASM_CODE(compiler,"# %d: %s\n", j, insn->opcode->name);
1080
1081     compiler->insn_shift = compiler->loop_shift;
1082     if (insn->flags & ORC_INSTRUCTION_FLAG_X2) {
1083       compiler->insn_shift += 1;
1084     }
1085     if (insn->flags & ORC_INSTRUCTION_FLAG_X4) {
1086       compiler->insn_shift += 2;
1087     }
1088
1089     rule = insn->rule;
1090     if (rule && rule->emit) {
1091       rule->emit (compiler, rule->emit_user, insn);
1092     } else {
1093       ORC_COMPILER_ERROR(compiler,"No rule for: %s", opcode->name);
1094     }
1095   }
1096 }
1097