diff --git a/changelog/std-meta-statisissorted.dd b/changelog/std-meta-staticissorted.dd similarity index 100% rename from changelog/std-meta-statisissorted.dd rename to changelog/std-meta-staticissorted.dd diff --git a/std/algorithm/sorting.d b/std/algorithm/sorting.d index e1549283f35..d27870a4a50 100644 --- a/std/algorithm/sorting.d +++ b/std/algorithm/sorting.d @@ -1812,7 +1812,7 @@ Params: Returns: The initial range wrapped as a $(D SortedRange) with the predicate $(D binaryFun!less). -Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort) is used for unstable sorting and +Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort, Introsort) is used for unstable sorting and $(HTTP en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting. Each algorithm has benefits beyond stability. Introsort is generally faster but Timsort may achieve greater speeds on data with low entropy or if predicate calls diff --git a/std/digest/sha.d b/std/digest/sha.d index 5964055ffd5..11770715596 100644 --- a/std/digest/sha.d +++ b/std/digest/sha.d @@ -101,17 +101,14 @@ unittest hash1 = sha1.finish(); } -version(D_PIC) -{ - // Do not use (Bug9378). -} -else version(Win64) +version(Win64) { // wrong calling convention } else version(D_InlineAsm_X86) { - private version = USE_SSSE3; + version (D_PIC) {} // Bugzilla 9378 + else private version = USE_SSSE3; } else version(D_InlineAsm_X86_64) { @@ -216,11 +213,20 @@ struct SHA(uint hashBlockSize, uint digestSize) version(USE_SSSE3) { import core.cpuid : ssse3; - import std.internal.digest.sha_SSSE3 : transformSSSE3; + import std.internal.digest.sha_SSSE3 : sse3_constants=constants, transformSSSE3; static void transform(uint[5]* state, const(ubyte[64])* block) pure nothrow @nogc { - return ssse3 ? transformSSSE3(state, block) : transformX86(state, block); + if (ssse3) + { + version (D_InlineAsm_X86_64) + // constants as extra argument for PIC, see Bugzilla 9378 + transformSSSE3(state, block, &sse3_constants); + else + transformSSSE3(state, block); + } + else + transformX86(state, block); } } else diff --git a/std/internal/digest/sha_SSSE3.d b/std/internal/digest/sha_SSSE3.d index 168061084a3..f20a5987b0c 100644 --- a/std/internal/digest/sha_SSSE3.d +++ b/std/internal/digest/sha_SSSE3.d @@ -15,14 +15,14 @@ */ module std.internal.digest.sha_SSSE3; -version(D_PIC) +version(D_InlineAsm_X86) { - // Do not use (Bug9378). -} -else version(D_InlineAsm_X86) -{ - private version = USE_SSSE3; - private version = _32Bit; + version (D_PIC) {} // Bugzilla 9378 + else + { + private version = USE_SSSE3; + private version = _32Bit; + } } else version(D_InlineAsm_X86_64) { @@ -108,6 +108,7 @@ version(USE_SSSE3) private immutable string SP = "RSP"; private immutable string BUFFER_PTR = "R9"; private immutable string STATE_PTR = "R8"; + private immutable string CONSTANTS_PTR = "R10"; // Registers for temporary results (XMM10 and XMM11 are also used temporary) private immutable string W_TMP = "XMM8"; @@ -120,15 +121,11 @@ version(USE_SSSE3) private immutable string X_CONSTANT = "XMM13"; } - /* The control words for the byte shuffle instruction. */ - align(16) private immutable uint[4] bswap_shufb_ctl = - [ - 0x0001_0203, 0x0405_0607, 0x0809_0a0b, 0x0c0d_0e0f - ]; - - /* The round constants. */ - align(16) private immutable uint[16] constants = + /* The control words for the byte shuffle instruction and the round constants. */ + align(16) public immutable uint[20] constants = [ + // The control words for the byte shuffle instruction. + 0x0001_0203, 0x0405_0607, 0x0809_0a0b, 0x0c0d_0e0f, // Constants for round 0-19 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999, // Constants for round 20-39 @@ -152,10 +149,22 @@ version(USE_SSSE3) return s.idup; } + /** Returns the reference to the byte shuffle control word. */ + private nothrow pure string bswap_shufb_ctl() + { + version (_64Bit) + return "["~CONSTANTS_PTR~"]"; + else + return "[constants]"; + } + /** Returns the reference to constant used in round i. */ private nothrow pure string constant(uint i) { - return "[constants + 16*"~to_string(i/20)~"]"; + version (_64Bit) + return "16 + 16*"~to_string(i/20)~"["~CONSTANTS_PTR~"]"; + else + return "[constants + 16 + 16*"~to_string(i/20)~"]"; } /** Returns the XMM register number used in round i */ @@ -304,9 +313,9 @@ version(USE_SSSE3) { if (i == 0) { - return swt3264(["movdqa "~X_SHUFFLECTL~",[bswap_shufb_ctl]", + return swt3264(["movdqa "~X_SHUFFLECTL~","~bswap_shufb_ctl(), "movdqa "~X_CONSTANT~","~constant(i)], - ["movdqa "~X_SHUFFLECTL~",[bswap_shufb_ctl]", + ["movdqa "~X_SHUFFLECTL~","~bswap_shufb_ctl(), "movdqa "~X_CONSTANT~","~constant(i)]); } version(_64Bit) @@ -589,8 +598,9 @@ version(USE_SSSE3) { /* * Parameters: - * RSI contains pointer to state - * RDI contains pointer to input buffer + * RDX contains pointer to state + * RSI contains pointer to input buffer + * RDI contains pointer to constants * * Stack layout as follows: * +----------------+ @@ -610,8 +620,9 @@ version(USE_SSSE3) "push RBP", "push RBX", // Save parameters - "mov "~STATE_PTR~", RSI", //pointer to state - "mov "~BUFFER_PTR~", RDI", //pointer to buffer + "mov "~STATE_PTR~", RDX", //pointer to state + "mov "~BUFFER_PTR~", RSI", //pointer to buffer + "mov "~CONSTANTS_PTR~", RDI", //pointer to constants to avoid absolute addressing // Align stack "sub RSP, 4*16+8", ]; @@ -643,10 +654,17 @@ version(USE_SSSE3) } } + // constants as extra argument for PIC, see Bugzilla 9378 + import std.meta : AliasSeq; + version (_64Bit) + alias ExtraArgs = AliasSeq!(typeof(&constants)); + else + alias ExtraArgs = AliasSeq!(); + /** * */ - public void transformSSSE3(uint[5]* state, const(ubyte[64])* buffer) pure nothrow @nogc + public void transformSSSE3(uint[5]* state, const(ubyte[64])* buffer, ExtraArgs) pure nothrow @nogc { mixin(wrap(["naked;"] ~ prologue())); // Precalc first 4*16=64 bytes diff --git a/std/traits.d b/std/traits.d index 134e787b0ad..809a7ea0269 100644 --- a/std/traits.d +++ b/std/traits.d @@ -1308,7 +1308,7 @@ alias ParameterDefaultValueTuple = ParameterDefaults; /** -Returns the attributes attached to a function $(D func). +Returns the FunctionAttribute mask for function $(D func). See_Also: $(LREF hasFunctionAttributes) @@ -1503,8 +1503,8 @@ private FunctionAttribute extractAttribFlags(Attribs...)() Checks whether a function has the given attributes attached. Params: - func = function to check - attributes = variadic number of function attributes as strings + args = Function to check, followed by a + variadic number of function attributes as strings Returns: `true`, if the function has the list of attributes attached and `false` otherwise. @@ -1513,7 +1513,7 @@ See_Also: $(LREF functionAttributes) */ template hasFunctionAttributes(args...) - if (isCallable!(args[0]) && args.length > 0 + if (args.length > 0 && isCallable!(args[0]) && allSatisfy!(isSomeString, typeof(args[1 .. $]))) { enum bool hasFunctionAttributes = { @@ -1536,7 +1536,7 @@ unittest static assert(hasFunctionAttributes!(func, "@safe", "pure")); static assert(!hasFunctionAttributes!(func, "@trusted")); - // for templates types are automatically inferred + // for templates attributes are automatically inferred bool myFunc(T)(T b) { return !b; @@ -7442,7 +7442,7 @@ template isType(X...) if (X.length == 1) * `true` if `X` is a function, `false` otherwise * * See_Also: - * Use $(REF isFunctionPointer) or $(REF isDelegate) for detecting those types + * Use $(LREF isFunctionPointer) or $(LREF isDelegate) for detecting those types * respectively. */ template isFunction(X...) if (X.length == 1)