deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

deps: enable AVX-512 OpenSSL asm with clang - #65136

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm
Aug 11, 2026
Merged

deps: enable AVX-512 OpenSSL asm with clang#65136
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
lemire:clang-openssl-avx512-asm

Conversation

@lemire

@lemirelemire commented Aug 8, 2026

Copy link
Copy Markdown
Member

I was trying to find out which compile was better for compiling Node.js : GCC or LLVM/clang. One of my benchmark showed that GCC was massively better. After investigating, I found that it was a configuration issue that disabled part of OpenSSL under AVX-512. Note that I am using Linux.

We don't need to worry about Apple Clang because AVX-512 on Apple systems is a narrow niche.

Node.js ships two pre-generated sets of OpenSSL assembly: asm, which contains the AVX-512 routines, and asm_avx2, which does not. The set is picked in deps/openssl/openssl.gyp based on gas_version or nasm_version, but configure.py only reports gas_version when the compiler is not clang, because clang uses its own integrated assembler and has no GNU assembler version to report. Consequently every clang build silently falls back to the AVX-512-less asm_avx2 set, with no warning.

The result is that ossl_vaes_vpclmulqdq_capable() is assembled as a stub that always returns 0, so OpenSSL never selects ossl_aes_gcm_encrypt_avx512() and uses the older AES-NI path instead. On a Zen 5 machine this costs roughly 1.6x on AES-256-GCM, 1.7x on ChaCha20-Poly1305 and 1.8x on RSA-2048 signing.

Accept llvm_version in the condition, the way deps/openssl/openssl.gypi already does for the AVX2 set. clang's integrated assembler has handled AVX512IFMA since 7.0 at least and VAES / VPCLMULQDQ since 7.0 at least; 8.0 is used as a conservative floor, well below the clang that Node.js is built with today.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/gyp
  • @nodejs/security-wg

@lemire
lemire requested a lite review from CopilotAugust 8, 2026 13:53
@nodejs-github-botnodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. needs-ci PRs that need a full CI run. openssl Issues and PRs related to the OpenSSL dependency. labels Aug 8, 2026
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from c8f1ee4 to 4faf749CompareAugust 8, 2026 13:56
@lemirelemire added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates OpenSSL build selection logic so clang builds can use the AVX-512-capable pre-generated OpenSSL assembly set, aligning performance-sensitive crypto paths with gcc builds and avoiding silent fallback to the AVX2-only asm set.

Changes:

  • Extend the deps/openssl/openssl.gyp condition that selects openssl_asm*.gypi to also accept sufficiently new llvm_version (LLVM/clang integrated assembler).
  • Apply the same selection logic to both the main OpenSSL target and the FIPS module target.
Suppressed comments (1)

deps/openssl/openssl.gyp:119

  • Same issue as above for the FIPS target: llvm_version can bypass the nasm_version check on Windows, but Windows still uses nasm.exe to assemble these files. This may incorrectly select the AVX-512 asm set when NASM is unavailable/too old.
 }, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 38 to +40
}, 'gas_version and v(gas_version) >= v("2.26") or '
'nasm_version and v(nasm_version) >= v("2.11.8")', {
'nasm_version and v(nasm_version) >= v("2.11.8") or '
'llvm_version and v(llvm_version) >= v("8.0")', {

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that if llvm_version indicates a recent version, then nasm should be adequate to build the resulting objects. You'd have a misconfigured system otherwise.

@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 8, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
@lemire
lemireforce-pushed the clang-openssl-avx512-asm branch from 4faf749 to 322485dCompareAugust 8, 2026 14:49
@lemirelemire added request-ci Add this label to start a Jenkins CI on a PR. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Aug 11, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 11, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@richardlaurichardlau added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 175cd52 into nodejs:mainAug 11, 2026
75 of 77 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 175cd52

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
Node.js ships two pre-generated sets of OpenSSL assembly: `asm`, which
contains the AVX-512 routines, and `asm_avx2`, which does not. The
set is picked in deps/openssl/openssl.gyp based on `gas_version` or
`nasm_version`, but configure.py only reports `gas_version` when the
compiler is not clang, because clang uses its own integrated
assembler and has no GNU assembler version to report. Consequently
every clang build silently falls back to the AVX-512-less `asm_avx2`
set, with no warning.
The result is that `ossl_vaes_vpclmulqdq_capable()` is assembled as a
stub that always returns 0, so OpenSSL never selects
`ossl_aes_gcm_encrypt_avx512()` and uses the older AES-NI path
instead. On an Intel Xeon Gold 6548N this costs roughly 1.6x on
AES-256-GCM and 1.8x on both ChaCha20-Poly1305 and RSA-2048 signing.
This is not limited to custom builds: BUILDING.md documents that the
official linux-x64 binaries are produced with clang, and the shipped
v25.x and v26.x binaries contain the stub.
Accept `llvm_version` in the condition, the way
deps/openssl/openssl.gypi already does for the AVX2 set. clang's
integrated assembler has handled AVX512IFMA since 3.9 and VAES /
VPCLMULQDQ since 6.0; 8.0 is used as a conservative floor, well below
the clang 19.1 that Node.js already requires.
PR-URL: #65136
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.dependenciesPRs that add, update, or configure Node.js dependencies.needs-ciPRs that need a full CI run.opensslIssues and PRs related to the OpenSSL dependency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@lemire@nodejs-github-bot@jasnell@lpinca@avivkeller@richardlau