summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-08-06 06:22:28 +0200
committerEugen Wissner <belka@caraus.de>2017-08-06 06:22:28 +0200
commit2934bb16d726292ae29998cb559cc9602bc3e065 (patch)
tree1abc9764f29c1c4689d89aec74d1b6343d333663
parented92e3993ee5350d3c523b848631cbf4ba5eca78 (diff)
downloadtanya-2934bb16d726292ae29998cb559cc9602bc3e065.tar.gz
Rename memory.op.zero into fill
- Rename memory.op.zero to fill, which accepts one template parameter: one byte to fill the memory with. - Fix bug on x86_64: RAX (register keeping the value to fill with) isn't set if the pointer was already aligned.
-rw-r--r--source/tanya/memory/arch/x86_64.d73
-rw-r--r--source/tanya/memory/op.d39
2 files changed, 75 insertions, 37 deletions
diff --git a/source/tanya/memory/arch/x86_64.d b/source/tanya/memory/arch/x86_64.d
index 2db1aaa..a9caec5 100644
--- a/source/tanya/memory/arch/x86_64.d
+++ b/source/tanya/memory/arch/x86_64.d
@@ -12,6 +12,8 @@
*/
module tanya.memory.arch.x86_64;
+import tanya.memory.op;
+
version (D_InlineAsm_X86_64):
pragma(inline, true)
@@ -80,8 +82,22 @@ pure nothrow @system @nogc
}
}
+private enum const(char[]) MovArrayPointer(string Destination)()
+{
+ string asmCode = "asm pure nothrow @nogc { mov ";
+ version (Windows)
+ {
+ asmCode ~= Destination ~ ", [ RCX + 8 ];";
+ }
+ else
+ {
+ asmCode ~= Destination ~ ", RSI;";
+ }
+ return asmCode ~ "}";
+}
+
pragma(inline, true)
-package (tanya.memory) void zero(void[] memory)
+package (tanya.memory) void fill(ubyte Byte)(void[] memory)
pure nothrow @system @nogc
{
asm pure nothrow @nogc
@@ -94,7 +110,6 @@ pure nothrow @system @nogc
* RCX - array.
*/
mov R8, [ RCX ];
- mov R9, [ RCX + 8 ];
}
else asm pure nothrow @nogc
{
@@ -103,53 +118,55 @@ pure nothrow @system @nogc
* RDI - length.
*/
mov R8, RDI;
- mov R9, RSI;
}
+ mixin(MovArrayPointer!"R9");
+
asm pure nothrow @nogc
{
// Check for zero length.
test R8, R8;
jz end;
-
- // Set to 0.
- pxor XMM0, XMM0;
-
- // Check if the pointer is aligned to a 16-byte boundary.
- and R9, -0x10;
}
- // Compute the number of misaligned bytes.
- version (Windows) asm pure nothrow @nogc
+ // Set 128- and 64-bit registers to values we want to fill with.
+ static if (Byte == 0)
{
- mov RAX, [ RCX + 8 ];
+ asm pure nothrow @nogc
+ {
+ xor RAX, RAX;
+ pxor XMM0, XMM0;
+ }
}
- else asm pure nothrow @nogc
+ else
{
- mov RAX, RSI;
+ enum ulong FilledBytes = FilledBytes!Byte;
+ asm pure nothrow @nogc
+ {
+ mov RAX, FilledBytes;
+ movq XMM0, RAX;
+ movlhps XMM0, XMM0;
+ }
}
asm pure nothrow @nogc
{
- sub RAX, R9;
+ // Check if the pointer is aligned to a 16-byte boundary.
+ and R9, -0x10;
+ }
+ // Compute the number of misaligned bytes.
+ mixin(MovArrayPointer!"R10");
+ asm pure nothrow @nogc
+ {
+ sub R10, R9;
- test RAX, RAX;
+ test R10, R10;
jz aligned;
// Get the number of bytes to be written until we are aligned.
mov RDX, 0x10;
- sub RDX, RAX;
- }
- version (Windows) asm pure nothrow @nogc
- {
- mov R9, [ RCX + 8 ];
- }
- else asm pure nothrow @nogc
- {
- mov R9, RSI;
+ sub RDX, R10;
}
+ mixin(MovArrayPointer!"R9");
asm pure nothrow @nogc
{
- // Set RAX to zero, so we can set bytes and dwords.
- xor RAX, RAX;
-
naligned:
mov [ R9 ], AL; // Write a byte.
diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d
index 25f7d25..e0a3dea 100644
--- a/source/tanya/memory/op.d
+++ b/source/tanya/memory/op.d
@@ -113,17 +113,33 @@ private pure nothrow @safe @nogc unittest
}
}
+/*
+ * size_t value each of which bytes is set to `Byte`.
+ */
+package template FilledBytes(ubyte Byte, ubyte I = 0)
+{
+ static if (I == size_t.sizeof)
+ {
+ enum size_t FilledBytes = Byte;
+ }
+ else
+ {
+ enum size_t FilledBytes = (FilledBytes!(Byte, I + 1) << 8) | Byte;
+ }
+}
+
/**
- * Fills $(D_PARAM memory) with zero-valued bytes.
+ * Fills $(D_PARAM memory) with single $(D_PARAM Byte)s.
*
* Param:
+ * Byte = The value to fill $(D_PARAM memory) with.
* memory = Memory block.
*/
-void zero(void[] memory) pure nothrow @trusted @nogc
+void fill(ubyte Byte = 0)(void[] memory) pure nothrow @trusted @nogc
{
version (D_InlineAsm_X86_64)
{
- tanya.memory.arch.x86_64.zero(memory);
+ tanya.memory.arch.x86_64.fill!Byte(memory);
}
else // Naive implementation.
{
@@ -133,7 +149,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
// Align.
while (((cast(size_t) vp) & alignmentMask) != 0)
{
- *vp++ = 0;
+ *vp++ = Byte;
--n;
}
@@ -141,7 +157,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
auto sp = cast(size_t*) vp;
while (n / size_t.sizeof > 0)
{
- *sp++ = 0;
+ *sp++ = FilledBytes!Byte;
n -= size_t.sizeof;
}
@@ -149,7 +165,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
vp = cast(ubyte*) sp;
while (n--)
{
- *vp = 0;
+ *vp = Byte;
++vp;
}
}
@@ -159,14 +175,14 @@ void zero(void[] memory) pure nothrow @trusted @nogc
pure nothrow @safe @nogc unittest
{
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- memory.zero();
+ memory.fill!0();
foreach (ubyte v; memory)
{
assert(v == 0);
}
}
-// Stress test. Checks that `zero` can handle unaligned pointers and different
+// Stress test. Checks that `fill` can handle unaligned pointers and different
// lengths.
pure nothrow @safe @nogc private unittest
{
@@ -178,10 +194,15 @@ pure nothrow @safe @nogc private unittest
{
v = i;
}
- zero(memory[j .. $]);
+ fill(memory[j .. $]);
foreach (ubyte v; memory[j .. $])
{
assert(v == 0);
}
+ fill!1(memory[j .. $]);
+ foreach (ubyte v; memory[j .. $])
+ {
+ assert(v == 1);
+ }
}
}