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.
This commit is contained in:
parent
ed92e3993e
commit
2934bb16d7
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.memory.arch.x86_64;
|
module tanya.memory.arch.x86_64;
|
||||||
|
|
||||||
|
import tanya.memory.op;
|
||||||
|
|
||||||
version (D_InlineAsm_X86_64):
|
version (D_InlineAsm_X86_64):
|
||||||
|
|
||||||
pragma(inline, true)
|
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)
|
pragma(inline, true)
|
||||||
package (tanya.memory) void zero(void[] memory)
|
package (tanya.memory) void fill(ubyte Byte)(void[] memory)
|
||||||
pure nothrow @system @nogc
|
pure nothrow @system @nogc
|
||||||
{
|
{
|
||||||
asm pure nothrow @nogc
|
asm pure nothrow @nogc
|
||||||
@ -94,7 +110,6 @@ pure nothrow @system @nogc
|
|||||||
* RCX - array.
|
* RCX - array.
|
||||||
*/
|
*/
|
||||||
mov R8, [ RCX ];
|
mov R8, [ RCX ];
|
||||||
mov R9, [ RCX + 8 ];
|
|
||||||
}
|
}
|
||||||
else asm pure nothrow @nogc
|
else asm pure nothrow @nogc
|
||||||
{
|
{
|
||||||
@ -103,53 +118,55 @@ pure nothrow @system @nogc
|
|||||||
* RDI - length.
|
* RDI - length.
|
||||||
*/
|
*/
|
||||||
mov R8, RDI;
|
mov R8, RDI;
|
||||||
mov R9, RSI;
|
|
||||||
}
|
}
|
||||||
|
mixin(MovArrayPointer!"R9");
|
||||||
|
|
||||||
asm pure nothrow @nogc
|
asm pure nothrow @nogc
|
||||||
{
|
{
|
||||||
// Check for zero length.
|
// Check for zero length.
|
||||||
test R8, R8;
|
test R8, R8;
|
||||||
jz end;
|
jz end;
|
||||||
|
}
|
||||||
// Set to 0.
|
// Set 128- and 64-bit registers to values we want to fill with.
|
||||||
pxor XMM0, XMM0;
|
static if (Byte == 0)
|
||||||
|
{
|
||||||
|
asm pure nothrow @nogc
|
||||||
|
{
|
||||||
|
xor RAX, RAX;
|
||||||
|
pxor XMM0, XMM0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum ulong FilledBytes = FilledBytes!Byte;
|
||||||
|
asm pure nothrow @nogc
|
||||||
|
{
|
||||||
|
mov RAX, FilledBytes;
|
||||||
|
movq XMM0, RAX;
|
||||||
|
movlhps XMM0, XMM0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asm pure nothrow @nogc
|
||||||
|
{
|
||||||
// Check if the pointer is aligned to a 16-byte boundary.
|
// Check if the pointer is aligned to a 16-byte boundary.
|
||||||
and R9, -0x10;
|
and R9, -0x10;
|
||||||
}
|
}
|
||||||
// Compute the number of misaligned bytes.
|
// Compute the number of misaligned bytes.
|
||||||
version (Windows) asm pure nothrow @nogc
|
mixin(MovArrayPointer!"R10");
|
||||||
{
|
|
||||||
mov RAX, [ RCX + 8 ];
|
|
||||||
}
|
|
||||||
else asm pure nothrow @nogc
|
|
||||||
{
|
|
||||||
mov RAX, RSI;
|
|
||||||
}
|
|
||||||
asm pure nothrow @nogc
|
asm pure nothrow @nogc
|
||||||
{
|
{
|
||||||
sub RAX, R9;
|
sub R10, R9;
|
||||||
|
|
||||||
test RAX, RAX;
|
test R10, R10;
|
||||||
jz aligned;
|
jz aligned;
|
||||||
|
|
||||||
// Get the number of bytes to be written until we are aligned.
|
// Get the number of bytes to be written until we are aligned.
|
||||||
mov RDX, 0x10;
|
mov RDX, 0x10;
|
||||||
sub RDX, RAX;
|
sub RDX, R10;
|
||||||
}
|
|
||||||
version (Windows) asm pure nothrow @nogc
|
|
||||||
{
|
|
||||||
mov R9, [ RCX + 8 ];
|
|
||||||
}
|
|
||||||
else asm pure nothrow @nogc
|
|
||||||
{
|
|
||||||
mov R9, RSI;
|
|
||||||
}
|
}
|
||||||
|
mixin(MovArrayPointer!"R9");
|
||||||
asm pure nothrow @nogc
|
asm pure nothrow @nogc
|
||||||
{
|
{
|
||||||
// Set RAX to zero, so we can set bytes and dwords.
|
|
||||||
xor RAX, RAX;
|
|
||||||
|
|
||||||
naligned:
|
naligned:
|
||||||
mov [ R9 ], AL; // Write a byte.
|
mov [ R9 ], AL; // Write a byte.
|
||||||
|
|
||||||
|
@ -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:
|
* Param:
|
||||||
|
* Byte = The value to fill $(D_PARAM memory) with.
|
||||||
* memory = Memory block.
|
* 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)
|
version (D_InlineAsm_X86_64)
|
||||||
{
|
{
|
||||||
tanya.memory.arch.x86_64.zero(memory);
|
tanya.memory.arch.x86_64.fill!Byte(memory);
|
||||||
}
|
}
|
||||||
else // Naive implementation.
|
else // Naive implementation.
|
||||||
{
|
{
|
||||||
@ -133,7 +149,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
|
|||||||
// Align.
|
// Align.
|
||||||
while (((cast(size_t) vp) & alignmentMask) != 0)
|
while (((cast(size_t) vp) & alignmentMask) != 0)
|
||||||
{
|
{
|
||||||
*vp++ = 0;
|
*vp++ = Byte;
|
||||||
--n;
|
--n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +157,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
|
|||||||
auto sp = cast(size_t*) vp;
|
auto sp = cast(size_t*) vp;
|
||||||
while (n / size_t.sizeof > 0)
|
while (n / size_t.sizeof > 0)
|
||||||
{
|
{
|
||||||
*sp++ = 0;
|
*sp++ = FilledBytes!Byte;
|
||||||
n -= size_t.sizeof;
|
n -= size_t.sizeof;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +165,7 @@ void zero(void[] memory) pure nothrow @trusted @nogc
|
|||||||
vp = cast(ubyte*) sp;
|
vp = cast(ubyte*) sp;
|
||||||
while (n--)
|
while (n--)
|
||||||
{
|
{
|
||||||
*vp = 0;
|
*vp = Byte;
|
||||||
++vp;
|
++vp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,14 +175,14 @@ void zero(void[] memory) pure nothrow @trusted @nogc
|
|||||||
pure nothrow @safe @nogc unittest
|
pure nothrow @safe @nogc unittest
|
||||||
{
|
{
|
||||||
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
memory.zero();
|
memory.fill!0();
|
||||||
foreach (ubyte v; memory)
|
foreach (ubyte v; memory)
|
||||||
{
|
{
|
||||||
assert(v == 0);
|
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.
|
// lengths.
|
||||||
pure nothrow @safe @nogc private unittest
|
pure nothrow @safe @nogc private unittest
|
||||||
{
|
{
|
||||||
@ -178,10 +194,15 @@ pure nothrow @safe @nogc private unittest
|
|||||||
{
|
{
|
||||||
v = i;
|
v = i;
|
||||||
}
|
}
|
||||||
zero(memory[j .. $]);
|
fill(memory[j .. $]);
|
||||||
foreach (ubyte v; memory[j .. $])
|
foreach (ubyte v; memory[j .. $])
|
||||||
{
|
{
|
||||||
assert(v == 0);
|
assert(v == 0);
|
||||||
}
|
}
|
||||||
|
fill!1(memory[j .. $]);
|
||||||
|
foreach (ubyte v; memory[j .. $])
|
||||||
|
{
|
||||||
|
assert(v == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user