1 module tame.internal; 2 3 package: 4 5 version (X86_64) { 6 enum isAMD64 = true; 7 enum isX86 = false; 8 } else version (X86) { 9 enum isAMD64 = false; 10 enum isX86 = true; 11 } else { 12 enum isX86 = false; 13 enum isAMD64 = false; 14 } 15 16 version (LDC) { 17 enum isLDC = true; 18 enum isGDC = false; 19 enum isDMD = false; 20 } else version (GNU) { 21 enum isLDC = false; 22 enum isGDC = true; 23 enum isDMD = false; 24 } else version (DigitalMars) { 25 enum isLDC = false; 26 enum isGDC = false; 27 enum isDMD = true; 28 } 29 30 version (DigitalMars) { 31 enum noinline; 32 enum forceinline; 33 enum sse4; 34 } else version (GNU) { 35 import gcc.attribute; 36 37 enum noinline = gcc.attribute.attribute("noinline"); 38 enum forceinline = gcc.attribute.attribute("forceinline"); 39 enum sse4_2 = gcc.attribute.attribute("target", "sse4.2"); 40 } else version (LDC) { 41 import ldc.attributes; 42 43 enum noinline = ldc.attributes.optStrategy("none"); 44 enum forceinline = ldc.attributes.llvmAttr("always_inline", "true"); 45 enum sse4_2 = ldc.attributes.target("+sse4.2"); 46 } 47 import std.traits : Unqual; 48 49 pure nothrow @nogc: 50 51 /******************************************************************************* 52 * 53 * Count leading zeroes. 54 * 55 * Params: 56 * u = the unsigned value to scan 57 * 58 * Returns: 59 * The number of leading zero bits before the first one bit. If `u` is `0`, 60 * the result is undefined. 61 * 62 **************************************/ 63 version (DigitalMars) { 64 import core.bitop : bsr, bsf; 65 66 U clz(U)(U u) if (is(Unqual!U : size_t)) { 67 pragma(inline, true); 68 enum U max = 8 * U.sizeof - 1; 69 return max - bsr(u); 70 } 71 72 static if (isX86) { 73 uint clz(U)(U u) if (is(Unqual!U == ulong)) { 74 pragma(inline, true); 75 uint hi = u >> 32; 76 return hi ? 31 - bsr(hi) : 63 - bsr(cast(uint)u); 77 } 78 } 79 } else version (GNU) { 80 import gcc.builtins; 81 82 alias clz = __builtin_clz; 83 static if (isX86) { 84 uint clz(ulong u) { 85 uint hi = u >> 32; 86 return hi ? __builtin_clz(hi) : 32 + __builtin_clz(cast(uint)u); 87 } 88 } else 89 alias clz = __builtin_clzl; 90 } else version (LDC) { 91 U clz(U)(U u) if (is(Unqual!U : size_t)) { 92 pragma(inline, true); 93 import ldc.intrinsics; 94 95 return llvm_ctlz(u, false); 96 } 97 98 static if (size_t.sizeof == 4) { 99 uint clz(U)(U u) if (is(Unqual!U == ulong)) { 100 pragma(inline, true); 101 import ldc.intrinsics; 102 103 return cast(uint)llvm_ctlz(u, false); 104 } 105 } 106 } 107 108 @safe unittest { 109 assert(clz(0x01234567) == 7); 110 assert(clz(0x0123456701234567UL) == 7); 111 assert(clz(0x0000000001234567UL) == 7 + 32); 112 } 113 114 /** 115 * Aligns a pointer to the closest multiple of $(D pot) (a power of two), 116 * which is equal to or larger than $(D value). 117 */ 118 T* alignPtrNext(T)(scope T* ptr, in size_t pot) 119 in (pot > 0 && pot.isPowerOf2) { 120 return cast(T*)((cast(size_t)ptr + (pot - 1)) & -pot); 121 } 122 123 unittest { 124 assert(alignPtrNext(cast(void*)65, 64) == cast(void*)128); 125 } 126 127 @safe { 128 /// Returns whether the (positive) argument is an integral power of two. 129 @property bool isPowerOf2(in size_t n) 130 in (n > 0) { 131 return (n & n - 1) == 0; 132 } 133 134 version (LDC) { 135 import core.simd; 136 137 pragma(LDC_intrinsic, "llvm.x86.sse2.pmovmskb.128") 138 uint moveMask(ubyte16); 139 } else version (GNU) { 140 import gcc.builtins; 141 142 alias moveMask = __builtin_ia32_pmovmskb128; 143 } 144 145 template SIMDFromScalar(V, alias scalar) { 146 // This wrapper is needed for optimal performance with LDC and 147 // doesn't hurt GDC's inlining. 148 V SIMDFromScalar() { 149 enum V asVectorEnum = scalar; 150 return asVectorEnum; 151 } 152 } 153 }