') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Vector128.ShiftRightLogical doesn't use machine-instructions for some types (`byte` / `sbyte`) · Issue #75770 · dotnet/runtime · GitHub
Skip to content

Vector128.ShiftRightLogical doesn't use machine-instructions for some types (byte / sbyte) #75770

Description

@gfoidl

Vector128.ShiftRightLogical has overloads for all primitive numeric types, and so it puts into mind that these operations are backed by efficient hw-code. This may be a trap for some types, as it falls back to a software solution.

While porting some code from SSE to xplat-instrinsics that made me wonder (why are there movsxd which shouldn't be there, and from where comes a loop where none should be) until I remembered that in Sse2 there's no such instruction...

This table summarizes the CQ for the numeric types (I don't know about AdvSimd, thus left that column out):

TypecodegenSse2-method available
byte
short✔️✔️
int✔️✔️
long✔️✔️
nint✔️
nuint✔️
sbyte
ushort✔️✔️
uint✔️✔️
ulong✔️✔️

As can be seen there's no strict correlation between codegen for the xplat-ShiftRightLogical and the availability of a Sse2-method (in both directions).

If this is not just a JIT's CQ-issue, then there should be any measure / indicator for the user to don't be surprised by the codegen or more important by perf.

We now push users towards using the xplat-instrinsics (which makes sense IMO), but I think we can't expect that every user inspects the generated machine-code.

Generalizing a bit: if there are known methods that aren't really intrinsified (by architecture, by design, ran out of time, etc.) maybe it's possible to provide any kind of hint in intellisense like it does for supported APIs:
grafik

Where it states something like:

SSE2 - intrinsified
AdvSimd - software fallback

Would it be enough for such info to have them in the xml doc-comments?

Having an analyzer that issues an suggestion / hint that software fallback will be used is another option.
To keep this up-to-date maybe some kind of meta-data would be needed on each Vector128-method that indicates the state of intrinsification. Maybe that overkill, though.

Repro

[MethodImpl(MethodImplOptions.NoInlining)]staticVector128<sbyte>DoSse(Vector128<sbyte>vec){returnSse2.ShiftRightLogical(vec.AsInt32(),4).AsSByte();}[MethodImpl(MethodImplOptions.NoInlining)]staticVector128<sbyte>DoXplatNaive(Vector128<sbyte>vec){returnVector128.ShiftRightLogical(vec,4);}[MethodImpl(MethodImplOptions.NoInlining)]staticVector128<sbyte>DoXplat(Vector128<sbyte>vec){returnVector128.ShiftRightLogical(vec.AsInt32(),4).AsSByte();}

produces on .NET 7 RC 2

; Assembly listing for method Program:<<Main>$>g__DoSse|0_0(Vector128`1):Vector128`1; Emitting BLENDED_CODE for X64 CPU with AVX - Windows; Tier-1 compilation; optimized code; rsp based frame; partially interruptible; No PGO dataG_M000_IG01: ;; offset=0000H C5F877 vzeroupperG_M000_IG02: ;; offset=0003H C5F91002 vmovupdxmm0, xmmword ptr [rdx] C5F972D004 vpsrld xmm0,xmm0,4 C5F91101 vmovupd xmmword ptr [rcx],xmm0 488BC1 movrax,rcxG_M000_IG03: ;; offset=0013H C3 ret; Total bytes of code 20; Assembly listing for method Program:<<Main>$>g__DoXplatNaive|0_1(Vector128`1):Vector128`1; Emitting BLENDED_CODE for X64 CPU with AVX - Windows; Tier-1 compilation; optimized code; rsp based frame; partially interruptible; No PGO data; 0 inlinees with PGO data; 2 single block inlinees; 1 inlinees without PGO dataG_M000_IG01: ;; offset=0000H57pushrdi56pushrsi 4883EC48 subrsp,72 C5F877 vzeroupper 488BF1 movrsi,rcxG_M000_IG02: ;; offset=000CH C5F91002 vmovupdxmm0, xmmword ptr [rdx] C5F929442420 vmovapd xmmword ptr [rsp+20H],xmm0 33FF xoredi,ediG_M000_IG03: ;; offset=0018H 488D4C2420 learcx, bword ptr [rsp+20H] 4863D7 movsxdrdx,edi 480FBE0C11 movsxrcx, byte ptr [rcx+rdx] BA04000000 movedx,4 FF1538261A00 call[Scalar`1:ShiftRightLogical(byte,int):byte] 488D542430 leardx, bword ptr [rsp+30H] 4863CF movsxdrcx,edi 88040A mov byte ptr [rdx+rcx],al FFC7 incedi 83FF10 cmpedi,16 7CD6 jl SHORT G_M000_IG03G_M000_IG04: ;; offset=0042H C5F928442430 vmovapd xmm0, xmmword ptr [rsp+30H] C5F91106 vmovupd xmmword ptr [rsi],xmm0 488BC6 movrax,rsiG_M000_IG05: ;; offset=004FH 4883C448 addrsp,72 5E poprsi 5F poprdi C3 ret; Total bytes of code 86; Assembly listing for method Program:<<Main>$>g__DoXplat|0_2(Vector128`1):Vector128`1; Emitting BLENDED_CODE for X64 CPU with AVX - Windows; Tier-1 compilation; optimized code; rsp based frame; partially interruptible; No PGO dataG_M000_IG01: ;; offset=0000H C5F877 vzeroupperG_M000_IG02: ;; offset=0003H C5F91002 vmovupdxmm0, xmmword ptr [rdx] C5F972D004 vpsrld xmm0,xmm0,4 C5F91101 vmovupd xmmword ptr [rcx],xmm0 488BC1 movrax,rcxG_M000_IG03: ;; offset=0013H C3 ret; Total bytes of code 20

PS: didn't check Vector256 and the other shift-variants.

category:cq
theme:vector-codegen
skill-level:beginner
cost:small
impact:small

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions