Skip to content

Improve memcmp and compareImpl implementations #870

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Sep 29, 2019
Merged
28 changes: 24 additions & 4 deletions std/assembly/util/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,30 @@ export function memset(dest: usize, c: u8, n: usize): void { // see: musl/src/st

// @ts-ignore: decorator
@inline
export function memcmp(vl: usize, vr: usize, n: usize): i32 { // see: musl/src/string/memcmp.c
export function memcmp(vl: usize, vr: usize, n: usize): i32 {
if (vl == vr) return 0;
while (n != 0 && load<u8>(vl) == load<u8>(vr)) {
n--; vl++; vr++;
if (ASC_SHRINK_LEVEL < 2) {
if ((vl & 7) == (vr & 7)) {
while (vl & 7) {
if (!n) return 0;
let a = <i32>load<u8>(vl);
let b = <i32>load<u8>(vr);
if (a != b) return a - b;
n--; vl++; vr++;
}
while (n >= 8) {
if (load<u64>(vl) != load<u64>(vr)) break;
vl += 8;
vr += 8;
n -= 8;
}
}
}
while (n--) {
let a = <i32>load<u8>(vl);
let b = <i32>load<u8>(vr);
if (a != b) return a - b;
vl++; vr++;
}
return n ? <i32>load<u8>(vl) - <i32>load<u8>(vr) : 0;
return 0;
}
21 changes: 17 additions & 4 deletions std/assembly/util/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,26 @@ const Powers10Lo: f64[] = [
];

export function compareImpl(str1: string, index1: usize, str2: string, index2: usize, len: usize): i32 {
var result = 0;
var ptr1 = changetype<usize>(str1) + (index1 << 1);
var ptr2 = changetype<usize>(str2) + (index2 << 1);
while (len && !(result = <i32>load<u16>(ptr1) - <i32>load<u16>(ptr2))) {
--len, ptr1 += 2, ptr2 += 2;
if (ASC_SHRINK_LEVEL < 2) {
if (len >= 4 && !((ptr1 & 7) | (ptr2 & 7))) {
do {
if (load<u64>(ptr1) != load<u64>(ptr2)) break;
ptr1 += 8;
ptr2 += 8;
len -= 4;
} while (len >= 4);
}
}
return result;
while (len--) {
let a = <i32>load<u16>(ptr1);
let b = <i32>load<u16>(ptr2);
if (a != b) return a - b;
ptr1 += 2;
ptr2 += 2;
}
return 0;
}

export function isSpace(c: i32): bool {
Expand Down
85 changes: 66 additions & 19 deletions tests/compiler/builtins.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -84,36 +84,83 @@
)
(func $~lib/util/string/compareImpl (; 8 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32)
loop $continue|0
local.get $2
if (result i32)
(local $4 i32)
local.get $0
i32.const 7
i32.and
local.get $1
i32.const 7
i32.and
i32.or
i32.eqz
i32.const 0
local.get $2
i32.const 4
i32.ge_u
select
if
loop $continue|0
local.get $0
i32.load16_u
i64.load
local.get $1
i32.load16_u
i32.sub
local.tee $3
i32.eqz
else
i32.const 0
i64.load
i64.eq
if
local.get $0
i32.const 8
i32.add
local.set $0
local.get $1
i32.const 8
i32.add
local.set $1
local.get $2
i32.const 4
i32.sub
local.tee $2
i32.const 4
i32.ge_u
br_if $continue|0
end
end
if
end
loop $continue|1
block $break|1
local.get $2
local.tee $3
i32.const 1
i32.sub
local.set $2
local.get $3
i32.eqz
br_if $break|1
local.get $0
i32.const 2
i32.add
local.set $0
i32.load16_u
local.tee $3
local.get $1
i32.const 2
i32.add
local.set $1
br $continue|0
i32.load16_u
local.tee $4
i32.ne
if
local.get $3
local.get $4
i32.sub
return
else
local.get $0
i32.const 2
i32.add
local.set $0
local.get $1
i32.const 2
i32.add
local.set $1
br $continue|1
end
unreachable
end
end
local.get $3
i32.const 0
)
(func $~lib/string/String.__eq (; 9 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32)
Expand Down
100 changes: 78 additions & 22 deletions tests/compiler/builtins.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
(global $~lib/builtins/f64.MIN_SAFE_INTEGER f64 (f64.const -9007199254740991))
(global $~lib/builtins/f64.MAX_SAFE_INTEGER f64 (f64.const 9007199254740991))
(global $~lib/builtins/f64.EPSILON f64 (f64.const 2.220446049250313e-16))
(global $~lib/ASC_SHRINK_LEVEL i32 (i32.const 0))
(export "memory" (memory $0))
(export "test" (func $builtins/test))
(start $start)
Expand Down Expand Up @@ -126,59 +127,114 @@
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 i32)
local.get $0
call $~lib/rt/stub/__retain
drop
local.get $2
call $~lib/rt/stub/__retain
drop
i32.const 0
local.set $5
local.get $0
local.get $1
i32.const 1
i32.shl
i32.add
local.set $6
local.set $5
local.get $2
local.get $3
i32.const 1
i32.shl
i32.add
local.set $7
block $break|0
loop $continue|0
local.get $4
if (result i32)
local.set $6
local.get $4
i32.const 4
i32.ge_u
if (result i32)
local.get $5
i32.const 7
i32.and
local.get $6
i32.const 7
i32.and
i32.or
i32.eqz
else
i32.const 0
end
if
block $break|0
loop $continue|0
local.get $5
i64.load
local.get $6
i32.load16_u
local.get $7
i32.load16_u
i64.load
i64.ne
if
br $break|0
end
local.get $5
i32.const 8
i32.add
local.set $5
local.get $6
i32.const 8
i32.add
local.set $6
local.get $4
i32.const 4
i32.sub
local.tee $5
i32.eqz
else
i32.const 0
local.set $4
local.get $4
i32.const 4
i32.ge_u
br_if $continue|0
end
i32.eqz
br_if $break|0
end
end
block $break|1
loop $continue|1
local.get $4
local.tee $7
i32.const 1
i32.sub
local.set $4
local.get $7
i32.eqz
br_if $break|1
local.get $5
i32.load16_u
local.set $7
local.get $6
i32.load16_u
local.set $8
local.get $7
local.get $8
i32.ne
if
local.get $7
local.get $8
i32.sub
local.set $9
local.get $0
call $~lib/rt/stub/__release
local.get $2
call $~lib/rt/stub/__release
local.get $9
return
end
local.get $5
i32.const 2
i32.add
local.set $6
local.get $7
local.set $5
local.get $6
i32.const 2
i32.add
local.set $7
br $continue|0
local.set $6
br $continue|1
end
unreachable
end
local.get $5
i32.const 0
local.set $8
local.get $0
call $~lib/rt/stub/__release
Expand Down
Loading