I always assumed any decent runtime/compiler takes care of such optimisations, and usually leave such things to JDK in my Java code. Is that really not the case?
I always assumed any decent runtime/compiler takes care of such optimisations, and usually leave such things to JDK in my Java code. Is that really not the case?
Also possible if it were more idiomatic C# it would have optimized it better. RyuJIT does in fact do BCE and other loop optimizations. It's improving a lot every year too.
The optimization paths from C# though Roslyn and RyuJIT probably don't start with C# written like it were C. Maybe iterating over Spans and slices would have optimized to fewer instructions than raw dogging nested for loops.
> Incrementing vectors (26.08.2019)
You can try to understand some of it by doing some measurements and doing some napkin math using the hardware limits like internet bandwidth or IO read/write etc.
Finally they changed their approach to .NET, besides Midori, SFI that I mention on a sibling comment, certainly also due to Go and Rust competition.
Note how Azure nowadays does most of their open source contributions in Go and Rust, the rewrites that completly ignored .NET, while the team mentions lack of adoption on .NET related podcasts.
Silverlight comes to mind, Also the fever dream that was '.NET micro'. I might still have my NetDuino somewhere...
> the main target audience of C#/.NET has always been LOB CRUD app shops.
I do think this has changed over time. There's definitely been improvements to the overall ecosystem from game developers (Cysharp being the most prolific) via both libraries and feedback around the BCL/JIT/etc.
While C# the language has much more goodies than Java the language, Java the platform has had much better options than the CLR, because it has been mostly Microsoft and Mono (nowadays almost gone after the acquisition), whereas the Java ecosystem has a plethora of implementations, each one wiht their JIT and GC implementations, even AOT caches since almost three decades now.
Thankfully the outcome of Project Midori, and the whole Secure Future Initiative , has had the side effect of Microsoft becoming more serious about .NET performance, instead of always outsourcing performance workloads to C++ and COM.
It used to be based on MSVC, with the most expensive optimizations trimmed, things like loop hoisting, devirtualization, generally ones with long runtimes, or ones that required whole program visibility.
But otherwise it was competent, if you wrote code aware of these limitations, it could get very close to even C++, and even on naive code, it was always very competitive (with strange wildcards, that if you used raw pointers, which are an obscure C# feature, you could get code to be even faster, due to the compiler's heritage).
It also helped, that due to MS's nature; C# was meant to be used with MS frameworks, written by people who were aware of the compiler's quirks, which you could learn if you looked at these codebases.
Sure if yo measure against LLVM-compiled static languages, it falls short in certain scenarios, but it's been soldily in the pack of other GC languages like Java or Go, and always has been.
I believe the new enabling technology for better codegen is tiered compilation, which has only been around for a couple years.
There were other weird things like C++/CLI which was a full-fat MSVC fork used to compile C++ either into .NET IL or x86 code which could be embedded into .NET assemblies, but could still call into .NET code.
But what most people think of as .NET (Framework) was definitely using the old MSVC-based JIT
I, for one, would love to have a cross-platform, open source C++/CLI compiler, because there is no more convenient way to consume nontrivial C++ APIs (and buggy, poorly-specified COM APIs only documented by C++ example code) in .NET.
i.e. I think the x64 framework compiler was based on MSVC, but the x86 was a bit of a different beast. That was part of why they did RyuJit in the first place, to help unify the JITs between the large divergence in how they worked [0].
One big thing being, AFAIK the old 32 bit JIT would never use SSE2 outside of some block copy type stuff. They assumed a safe baseline for most other instructions and stuck with that (although, there can be good reasons for this, e.x. consistency with x87 behavior.)
Will also add that the old x64 compiler sometimes really did do some questionable stuff, i.e. when we flipped things to use it we never really saw a perf benefit even when dealing with larger datatypes/etc that should have seen a benefit from wider registers.
RyuJit definitely has fixed that, but... again, the past is a bit hazy.
[0] - https://devblogs.microsoft.com/dotnet/ryujit-the-next-genera...
https://github.com/dotnet/runtimelab/tree/feature/NativeAOT-...