153 lines
2.5 KiB
ArmAsm
153 lines
2.5 KiB
ArmAsm
.global sort
|
|
|
|
# a0 = pointer to array to be sorted
|
|
# a1 = length of array (signed)
|
|
# a2 = element size (unsigned)
|
|
# a3 - comparison function
|
|
# a4 - context
|
|
sort:
|
|
# insertion sort
|
|
# for i = 0 to n-1
|
|
# for j = i downto 0
|
|
# if a[j-1] > a[j]
|
|
# swap a[j-1], a[j]
|
|
|
|
# i = 0
|
|
# for n-1 downto 0
|
|
# i += esize
|
|
# j = i
|
|
# while j > 0:
|
|
# if cmp(j-esize, j) > 0
|
|
# swap(j-esize, j)
|
|
# else
|
|
# break
|
|
# j -= esize
|
|
#
|
|
|
|
# bail early if n <= 1
|
|
li t0, 1
|
|
bgt a1, t0, 0f
|
|
li a0, 0
|
|
ret
|
|
0:
|
|
|
|
# check if n*esize overflows or is negative
|
|
mulhu t1, a1, a2
|
|
beqz t1, 0f
|
|
li a0, -1
|
|
ret
|
|
0:
|
|
|
|
sd ra, -1*8(sp)
|
|
sd s0, -2*8(sp)
|
|
sd s1, -3*8(sp)
|
|
sd s2, -4*8(sp)
|
|
sd s3, -5*8(sp)
|
|
sd s4, -6*8(sp)
|
|
sd s5, -7*8(sp)
|
|
sd s6, -8*8(sp)
|
|
addi sp, sp, -8*8
|
|
|
|
mv s0, a2 # pointer to element i - base
|
|
# s1 is pointer to element j - base
|
|
mv s2, a0 # base pointer
|
|
mv s3, a1 # array len
|
|
mv s4, a2 # element size
|
|
mv s5, a3 # cmp
|
|
mv s6, a4 # context
|
|
|
|
# we know we have at least 2 elements,
|
|
# so no check necessary at the top of the loop
|
|
addi s3, s3, -1
|
|
.Louter.top:
|
|
# i += esize
|
|
# j = i
|
|
add s0, s0, s4
|
|
mv s1, s0
|
|
|
|
.Linner.top:
|
|
add a1, s1, s2 # create pointers
|
|
sub a0, a1, s4
|
|
mv a2, s6
|
|
jalr s5 # cmp
|
|
#li a0, 1
|
|
blez a0, .Lcmp.less
|
|
|
|
.Lcmp.greater:
|
|
.Lswap:
|
|
add a1, s1, s2
|
|
sub a0, a1, s4
|
|
mv a2, s4
|
|
call swap
|
|
|
|
.Linner.step:
|
|
sub s1, s1, s4
|
|
bnez s1, .Linner.top
|
|
|
|
.Lcmp.less:
|
|
.Louter.step:
|
|
addi s3, s3, -1 # n -= 1
|
|
bnez s3, .Louter.top
|
|
|
|
.Lreturn:
|
|
addi sp, sp, 8*8
|
|
ld ra, -1*8(sp)
|
|
ld s0, -2*8(sp)
|
|
ld s1, -3*8(sp)
|
|
ld s2, -4*8(sp)
|
|
ld s3, -5*8(sp)
|
|
ld s4, -6*8(sp)
|
|
ld s5, -7*8(sp)
|
|
ld s6, -8*8(sp)
|
|
ret
|
|
|
|
.Lerror:
|
|
li a0, -1
|
|
j .Lreturn
|
|
|
|
swap:
|
|
# TODO: larger things
|
|
li t0, 8
|
|
bgtu a2, t0, bigswap
|
|
beq a2, t0, swap8
|
|
li t0, 4
|
|
beq a2, t0, swap4
|
|
li t0, 2
|
|
beq a2, t0, swap2
|
|
li t0, 1
|
|
beq a2, t0, swap1
|
|
beqz a2, .Lret
|
|
|
|
# TODO: weird size: 0, 3, 5, 6, 7
|
|
.Lret:
|
|
ret
|
|
|
|
swap8:
|
|
ld t0, (a0)
|
|
ld t1, (a1)
|
|
sd t1, (a0)
|
|
sd t0, (a1)
|
|
ret
|
|
swap4:
|
|
lwu t0, (a0)
|
|
lwu t1, (a1)
|
|
sw t1, (a0)
|
|
sw t0, (a1)
|
|
ret
|
|
swap2:
|
|
lhu t0, (a0)
|
|
lhu t1, (a1)
|
|
sh t1, (a0)
|
|
sh t0, (a1)
|
|
ret
|
|
swap1:
|
|
lbu t0, (a0)
|
|
lbu t1, (a1)
|
|
sb t1, (a0)
|
|
sb t0, (a1)
|
|
ret
|
|
|
|
bigswap:
|
|
# TODO
|
|
ret
|