summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-08-11 22:15:01 +0200
committerEugen Wissner <belka@caraus.de>2017-08-11 22:15:01 +0200
commitdea0eb9a370a157b0bb4e6295bb56b2320fa02b8 (patch)
tree6cfcf7f4afe8d55dc7ac2dd4cb10760c513b071a /source
parent7c2abadb90d2196c1f51a0e656a68981a7e7fa77 (diff)
downloadtanya-dea0eb9a370a157b0bb4e6295bb56b2320fa02b8.tar.gz
Add function for comparing memory regions
memory.op.cmp.
Diffstat (limited to 'source')
-rw-r--r--source/tanya/memory/arch/x86_64.d101
-rw-r--r--source/tanya/memory/op.d121
2 files changed, 217 insertions, 5 deletions
diff --git a/source/tanya/memory/arch/x86_64.d b/source/tanya/memory/arch/x86_64.d
index 26d948e..834c3da 100644
--- a/source/tanya/memory/arch/x86_64.d
+++ b/source/tanya/memory/arch/x86_64.d
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
- * Implementions of functions found in $(D_PSYMBOL tanya.memory.op) for X86-64.
+ * Implementions of functions found in $(D_PSYMBOL tanya.memory.op) for x64.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
@@ -51,7 +51,7 @@ pure nothrow @system @nogc
asm pure nothrow @nogc
{
cmp RDX, 0x08;
- jc aligned_8;
+ jc aligned_1;
test EDI, 0x07;
jz aligned_8;
@@ -69,6 +69,7 @@ pure nothrow @system @nogc
and EDX, 0x07;
jz end;
+ aligned_1:
// Write the remaining bytes.
mov RCX, RDX;
rep;
@@ -340,3 +341,99 @@ pure nothrow @system @nogc
ret;
}
}
+
+pragma(inline, true)
+package (tanya.memory) int cmp(const void[] r1, const void[] r2)
+pure nothrow @system @nogc
+{
+ asm pure nothrow @nogc
+ {
+ naked;
+
+ // RDI and RSI should be preserved.
+ mov R9, RDI;
+ mov R8, RSI;
+ }
+ // Set the registers for cmpsb/cmpsq.
+ version (Windows) asm pure nothrow @nogc
+ {
+ // RDX - r1.
+ // RCX - r2.
+
+ mov RDI, [ RCX + 8 ];
+ mov RSI, [ RDX + 8 ];
+ mov RDX, [ RDX ];
+ mov RCX, [ RCX ];
+ }
+ else asm pure nothrow @nogc
+ {
+ // RDX - r1 length.
+ // RCX - r1 data.
+ // RDI - r2 length
+ // RSI - r2 data.
+
+ mov RSI, RCX;
+ mov RCX, RDI;
+ mov RDI, R8;
+ }
+ asm pure nothrow @nogc
+ {
+ // Compare the lengths.
+ cmp RDX, RCX;
+ jl less;
+ jg greater;
+
+ // Check if we're aligned.
+ cmp RDX, 0x08;
+ jc aligned_1;
+ test EDI, 0x07;
+ jz aligned_8;
+
+ naligned:
+ cmpsb;
+ jl less;
+ jg greater;
+
+ dec RDX;
+ test EDI, 0x07;
+ jnz naligned;
+
+ aligned_8:
+ mov RCX, RDX;
+ shr RCX, 0x03;
+
+ repe;
+ cmpsq;
+ jl less;
+ jg greater;
+
+ and EDX, 0x07;
+ jz equal;
+
+ aligned_1: // Compare the remaining bytes.
+ mov RCX, RDX;
+
+ repe;
+ cmpsb;
+ jl less;
+ jg greater;
+
+ equal:
+ xor RAX, RAX; // Return 0.
+ jmp end;
+
+ greater:
+ mov RAX, 1;
+ jmp end;
+
+ less:
+ mov RAX, -1;
+ jmp end;
+
+ end: // Restore registers.
+ mov RSI, R8;
+ mov RDI, R9;
+
+ ret;
+ }
+}
diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d
index 9b15586..2134355 100644
--- a/source/tanya/memory/op.d
+++ b/source/tanya/memory/op.d
@@ -92,7 +92,7 @@ pure nothrow @safe @nogc unittest
ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
ubyte[9] target;
source.copy(target);
- assert(source == target);
+ assert(cmp(source, target) == 0);
}
private pure nothrow @safe @nogc unittest
@@ -111,7 +111,7 @@ private pure nothrow @safe @nogc unittest
ubyte[8] source = [1, 2, 3, 4, 5, 6, 7, 8];
ubyte[8] target;
source.copy(target);
- assert(source == target);
+ assert(cmp(source, target) == 0);
}
}
@@ -283,5 +283,120 @@ pure nothrow @safe @nogc unittest
ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
copyBackward(mem[0 .. 4], mem[2 .. $]);
- assert(expected == mem);
+ assert(cmp(expected, mem) == 0);
+}
+
+private nothrow @safe @nogc unittest
+{
+ ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ];
+ ubyte[9] r2;
+
+ copyBackward(r1, r2);
+ assert(cmp(r1, r2) == 0);
+}
+
+/**
+ * Compares two memory areas $(D_PARAM r1) and $(D_PARAM r2).
+ *
+ * $(D_PSYMBOL cmp) returns a positive integer if
+ * $(D_INLINECODE r1.length > r2.length) or the first `n` compared bytes of
+ * $(D_PARAM r1) found to be greater than the first `n` bytes of $(D_PARAM r2),
+ *
+ * $(D_PSYMBOL cmp) returns a negative integer if
+ * $(D_INLINECODE r2.length > r1.length) or the first `n` compared bytes of
+ * $(D_PARAM r1) found to be less than the first `n` bytes of $(D_PARAM r2),
+ *
+ * `0` is returned otherwise.
+ *
+ * Returns: Positive integer if $(D_INLINECODE r1 > r2),
+ * negative integer if $(D_INLINECODE r2 > r1),
+ * `0` if $(D_INLINECODE r1 == r2).
+ */
+int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc
+{
+ version (D_InlineAsm_X86_64)
+ {
+ return tanya.memory.arch.x86_64.cmp(r1, r2);
+ }
+ else // Naive implementation.
+ {
+ if (r1.length > r2.length)
+ {
+ return 1;
+ }
+ else if (r1.length < r2.length)
+ {
+ return -1;
+ }
+ auto p1 = cast(const(ubyte)*) r1;
+ auto p2 = cast(const(ubyte)*) r2;
+ auto count = r1.length;
+
+ // Check if the pointers are aligned or at least can be aligned
+ // properly.
+ if (((cast(size_t) p1) & alignMask) == ((cast(size_t) p2) & alignMask))
+ {
+ // Align the pointers if possible.
+ for (; ((cast(size_t) p1) & alignMask) != 0; ++p1, ++p2, --count)
+ {
+ if (*p1 != *p2)
+ {
+ return *p1 - *p2;
+ }
+ }
+ // Compare size_t.sizeof bytes at once.
+ for (; count >= size_t.sizeof; count -= size_t.sizeof)
+ {
+ if (*(cast(const(size_t)*) p1) > *(cast(const(size_t)*) p2))
+ {
+ return 1;
+ }
+ else if (*(cast(const(size_t)*) p1) < *(cast(const(size_t)*) p2))
+ {
+ return -1;
+ }
+ p1 += size_t.sizeof;
+ p2 += size_t.sizeof;
+ }
+ }
+ // Compare the remaining bytes by one.
+ for (; count--; ++p1, ++p2)
+ {
+ if (*p1 != *p2)
+ {
+ return *p1 - *p2;
+ }
+ }
+ return 0;
+ }
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ];
+ ubyte[3] r2 = [ 'c', 'a', 'b' ];
+
+ assert(cmp(r1[0 .. 3], r2[]) < 0);
+ assert(cmp(r2[], r1[0 .. 3]) > 0);
+
+ assert(cmp(r1, r2) > 0);
+ assert(cmp(r2, r1) < 0);
+}
+
+private pure nothrow @safe @nogc unittest
+{
+ ubyte[16] r1 = [
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ ];
+ ubyte[16] r2 = [
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ ];
+
+ assert(cmp(r1, r2) == 0);
+ assert(cmp(r1[1 .. $], r2[1 .. $]) == 0);
+ assert(cmp(r1[0 .. $ - 1], r2[0 .. $ - 1]) == 0);
+ assert(cmp(r1[0 .. 8], r2[0 .. 8]) == 0);
}