Browse Source

tigcclib: save 20 bytes on the shell sort implementation used in qsort(), while making it faster for all array sizes.
While at it: in the "Sort Integers" example, use integer comparison instead of floating-point comparison...

git-svn-id: file:///var/svn/tigccpp/trunk@1357 9552661e-59e3-4036-b4f2-dbe53926924f

debrouxl 14 years ago
parent
commit
8adf16e0ee
2 changed files with 190 additions and 17 deletions
  1. 189 16
      tigcc/archive/qsort.c
  2. 1 1
      tigcc/examples/Sort Integers.c

+ 189 - 16
tigcc/archive/qsort.c

@@ -3,20 +3,193 @@
 // Do not use register a5; callback function might need it.
 register long __tbl asm ("a5");
 
-__ATTR_LIB_C__ void qsort(void *list, short num_items, short size, compare_t cmp_func)
-{
-  unsigned short gap,byte_gap,i,j;                
-  char *p,*a,*b,temp;                       
-  for (gap=((unsigned short)num_items)>>1; gap>0; gap>>=1)    // Yes, this is not a quicksort,
-    {                                                         // but works fast enough...    
-      byte_gap=gap*(unsigned short)size;
-      for(i=byte_gap; i<((unsigned short)num_items)*(unsigned short)size; i+=size)
-        for(p=(char*)list+i-byte_gap; p>=(char*)list; p-= byte_gap)
-          {
-            a=p; b=p+byte_gap;
-            if(cmp_func(a,b)<=0) break;
-            for(j=size;j;j--)
-              temp=*a, *a++=*b, *b++=temp;
-          }
+// This is not a quick sort, it's a shell sort.
+// For sorting data that has no significant statistical property, on embedded platforms
+// without processor caches, the shell sort is one of the very best size/speed tradeoffs.
+__ATTR_LIB_C__ void qsort(void *list, short num_items, short size, compare_t cmp_func);
+
+asm("
+| d3 <- p
+| d4 <- a+byte_gap
+| d5 <- k
+| d6 <- i
+| d7 <- size
+| a2 <- cmp_func
+| a3 <- byte_gap
+| a4 <- list
+| a6 <- num_items * size
+.text
+	.even
+	.globl qsort
+qsort:
+	movem.l %d3-%d7/%a2-%a4/%a6,-(%sp)
+	move.l %a0,%a4	;# list, list
+	move.w %d1,%d7	;# size, size
+	move.l %a1,%a2	;# cmp_func, cmp_func
+	move.w #4096,%d5	;#, k
+	cmp.w #16,%d0	;#, num_items
+	bhi.s .L4	;#
+	moveq #1,%d5	;#, k
+.L4:
+	mulu.w %d7,%d0	;# size, num_items
+	move.w %d0,%a6	;# num_items, num_items.61
+	bra.s .L5	;#
+.L6:
+	move.w %d5,%d6	;# k, i
+	mulu.w %d7,%d6	;# size, i
+	move.l %d6,%d0	;# i, byte_gap
+	neg.l %d0
+	move.l %d0,%a3
+	bra.s .L7	;#
+.L8:
+	moveq #0,%d0	;# i
+	move.w %d6,%d0	;# i, i
+	move.l %a4,%d3	;# list, p
+	add.l %d0,%d3	;# i, p
+	add.l %a3,%d3	;# D.1283, p
+	move.l %d3,%d4	;# p, ivtmp.60
+	sub.l %a3,%d4	;# D.1283, ivtmp.60
+	bra.s .L9	;#
+.L10:
+	move.l %d4,-(%sp)	;# ivtmp.60,
+	move.l %d3,-(%sp)	;# p,
+	jsr (%a2)	;#
+	addq.l #8,%sp	;#,
+	tst.w %d0	;#
+	ble.s .L11	;#
+	move.l %d4,%a1	;# ivtmp.60, ivtmp.47
+	move.w %d7,%d1	;# size, j
+	move.l %d3,%a0	;# p, a
+	subq.w #1,%d1	;#
+.L14:
+	move.b (%a0),%d0	;#* a, temp
+	move.b (%a1),(%a0)+	;#* ivtmp.47,
+	move.b %d0,(%a1)+	;# temp,
+	dbf %d1,.L14	;#, j
+
+	add.l %a3,%d3	;# D.1283, p
+	add.l %a3,%d4	;# ivtmp.53, ivtmp.60
+.L9:
+	cmp.l %d3,%a4	;# p, list
+	bls.s .L10	;#
+.L11:
+	add.w %d7,%d6	;# size, i
+.L7:
+	cmp.w %a6,%d6	;# num_items.61, i
+	bcs.s .L8	;#
+	lsr.w #1,%d5	;#, tmp59
+	move.w %d5,%d0	;# k, tmp60
+	lsr.w #3,%d0	;#, tmp60
+	sub.w %d0,%d5	;# tmp60, k
+.L5:
+	tst.w %d5	;# k
+	bne.s .L6	;#
+	movm.l (%sp)+,%d3-%d7/%a2-%a4/%a6
+	rts
+");
+
+
+// The assembly routine above was created using the following C code as a starting point:
+/*{
+    unsigned short byte_gap,i;
+    short j;
+    unsigned short k;
+    char *p,*a,temp;
+
+    k = ((unsigned short)num_items <= 16) ? 1 : 4096;
+    num_items = (unsigned short)num_items * (unsigned short)size;
+
+    for (; k > 0; k = (k>>1) - (k>>4)) {
+        byte_gap=k*(unsigned short)size;
+        for(i=byte_gap; i<(unsigned short)num_items; i+=size) {
+            for(p=(char*)list+i-byte_gap; p>=(char*)list; p-= byte_gap) {
+                a=p;
+                if(cmp_func(a,a+byte_gap)<=0) break;
+                for(j=size;j;j--) {
+                    temp=*a; *a=*(a+byte_gap); *(a+byte_gap)=temp; a++;
+                }
+            }
+        }
     }
-}
+}*/
+
+// Compiling it with -Os under GCC 4.1.2-tigcc-4 yielded:
+/*
+	subq.w #8,%sp
+	movm.l #0x1f3a,-(%sp)
+	move.l %a0,%a4	;# list, list
+	move.w %d1,%d7	;# size, size
+	move.l %a1,40(%sp)	;# cmp_func, cmp_func
+	muls.w %d1,%d0	;# size, num_items
+	move.w %d0,%a3	;# num_items, num_items.60
+	move.w #4096,%d2	;#, k
+	moveq #16,%d0	;#,
+	cmp.w %a3,%d0	;# num_items.60,
+	jbcs .L18	;#
+	moveq #1,%d2	;#, k
+	jbra .L18	;#
+.L5:
+	move.w %d2,%d6	;# k, i
+	muls.w %d7,%d6	;# size, i
+	move.w %d6,%a6	;# i, byte_gap
+	jbra .L6	;#
+.L7:
+	moveq #0,%d5	;# D.1283
+	move.w %a6,%d5	;# byte_gap, D.1283
+	moveq #0,%d0	;# i
+	move.w %d6,%d0	;# i, i
+	move.l %a4,%d3	;# list, p
+	add.l %d0,%d3	;# i, p
+	sub.l %d5,%d3	;# D.1283, p
+	move.l %d5,%d0	;# D.1283,
+	neg.l %d0	;#
+	move.l %d0,%a2	;#, ivtmp.53
+	move.l %d3,%d4	;# p, ivtmp.59
+	add.l %d5,%d4	;# D.1283, ivtmp.59
+	jbra .L8	;#
+.L9:
+	move.l %d4,-(%sp)	;# ivtmp.59,
+	move.l %d3,-(%sp)	;# p,
+	move.l %d2,44(%sp)	;#,
+	move.l 48(%sp),%a0	;# cmp_func,
+	jbsr (%a0)	;#
+	addq.l #8,%sp	;#,
+	move.l 36(%sp),%d2	;#,
+	tst.w %d0	;#
+	jble .L10	;#
+	move.l %d4,%a1	;# ivtmp.59, ivtmp.47
+	move.w %d7,%d1	;# size, j
+	move.l %d3,%a0	;# p, a
+	jbra .L12	;#
+.L13:
+	move.b (%a0),%d0	;#* a, temp
+	move.b (%a1),(%a0)+	;#* ivtmp.47,
+	move.b %d0,(%a1)+	;# temp,
+	subq.w #1,%d1	;#, j
+.L12:
+	tst.w %d1	;# j
+	jbne .L13	;#
+	sub.l %d5,%d3	;# D.1283, p
+	add.l %a2,%d4	;# ivtmp.53, ivtmp.59
+.L8:
+	cmp.l %d3,%a4	;# p, list
+	jbls .L9	;#
+.L10:
+	add.w %d7,%d6	;# size, i
+.L6:
+	cmp.w %a3,%d6	;# num_items.60, i
+	jbcs .L7	;#
+	move.w %d2,%d1	;# k, tmp58
+	lsr.w #1,%d1	;#, tmp58
+	move.w %d2,%d0	;# k, tmp59
+	lsr.w #4,%d0	;#, tmp59
+	move.w %d1,%d2	;# tmp58, k
+	sub.w %d0,%d2	;# tmp59, k
+.L18:
+	tst.w %d2	;# k
+	jbne .L5	;#
+	movm.l (%sp)+,#0x5cf8
+	addq.w #8,%sp
+	rts
+*/
+// In six steps, 30 bytes were saved, yielding the ASM routine at the top of this file.

+ 1 - 1
tigcc/examples/Sort Integers.c

@@ -12,7 +12,7 @@
 // Comparison Function
 CALLBACK short int_comp(const void *a, const void *b)
 {
-  return fcmp (*(const short*)a, *(const short*)b);
+  return (*(const short*)a) - (*(const short*)b);
 }
 
 // Main Function