It also adds very little complexity to the compiler itself so it's a nice win.
1,695 karma · joined August 9, 2015
It also adds very little complexity to the compiler itself so it's a nice win.
Non-photorealistic rendering is actually a whole (fascinating) academic field in itself.
Since you have conflicting goals (temporal coherence, spatial coherence, "flatness", relatively constant stroke/feature size, ...) it's full of interesting tradeoffs and techniques.
Even simple things like beautiful real-time stylized outlining can be really hard if you are picky about the result.
The author even goes through an explicit example.
One reason for that is that it's easy to get rid of it, and guess what, we have a bunch of compiler flags just for that.
That absolutely does not mean that "UB is bad, period".
In fact you praise Rust but only safe Rust has no UB.
Actually, if they do end up putting more and more knowledge about the type system invariants in the optimizer, the rules for UB in unsafe code are going to be more complicated than C (think type-based aliasing on steroids).
Don't get me wrong, it's good design to nicely package these in unsafe code, but if your language can craft pointers and load/store from them, your spec will have to have UB (or boundcheck all loads and stores).
If I had to ask for one language feature for game-related code, it would be a compiler backend targeting the various shader "ISAs". It should be relatively easy since the exposed architecture by the APIs are quite high level.
It would be useful, if only to make sharing data layout between the GPU & CPU less annoying (padding float4 slots by hand, sigh ...), as well as constants and other stuff.
Especially as modern rendering techniques are more and more compute shader heavy (tiled/clustered shading etc) we could definitely use some nicer high level language features in there instead of the usual preprocessor contraptions.
HW video decoding, display protocol driving, 3D, ... Is there any open hw initiative on that front that I'm not aware of ?
The constraints for generic digital logic soup are comparatively "simple" : make wires as short and neat as possible and then check the (simulated) physical timing characteristics.
Analog is more artistic since any noise or crosstalk degrades the signal irreversibly (for low noise stuff) and any wire is a transmission line (for high speed stuff).
Actually even for digital I'm sure you still have to do manual layout for the most critical pieces of high-performance designs (say a register file on a nvidia gpu).
After all, if the gc is not freeing the memory then it must know a reachable path to it so the blame should be easy to assign.
Does ruby not have any good heap profiling tool ?
If you really care about load time you can decode the image directly in a tiled layout in software but that's more annoying.
You do cut yourself of from the more advanced optimizations simply for man-hour reasons. I'm guessing it's a trade off they are willing to make.
I have to say that I really dislike the kind of large pattern matching they added for the hash table clear. C compilers do that as well for e.g. memset/copy or bit rotate instructions.
IME it's really brittle and would be more beneficial as some kind of a lint ("you could replace this bunch of code by a call to clear()").
It makes the code simpler and won't inexplicably slow down next time someone does a tautological refactoring.
If anything, Spectre class attacks really showed how hard it is to properly sandbox arbitrary programs.
Yes, the CPUs are complex, but the attacks happen on a high conceptual level, level at which the CPU is fairly simple. It's not like they rely on an obscure detail or bug.
No one (publicly) figured those out for 2 decades when the involved ideas (speculation, cache timings) are well known, common and did not change.
This indicates that for something with such a large surface as the various web standards, where both the spec and the implementations are changing all the time, there is very little hope.
It's a very important thing that users trust their browser and won't hesitate a second to enter an unknown URL. They see "going to a webpage" as the equivalent to looking at a poster in the street, not eating candy provided by a random stranger.
Eroding this trust would ruin it for everyone, even well behaved static websites without javascript.
Maybe it's time to reconsider giving the same execution rights to gmail and unknown web pages ?
Such an approach would preclude putting any variable in a register if there is any not-provably-valid pointer store anywhere in the program.
Feel free to try, but I guarantee you that for most non trivial optimization it's going to be easy to find a piece of code that is UB today and where the optimization is observably different from the reference compilation.
Basically, the intent of the proposal is understandable but it does not make sense as written.
The spec does not explain how to compile C code, it gives you a set of rules so that you could in theory take some piece of C source and a full execution trace and verify whether that trace was a conforming execution for that C code.
You take the example of the negative shift again, and it is addressed in the post you respond to : it's a perfectly fine proposal to demote negative shifts from UB to something less permissive to the compiler.
However, if you do so, of course, you have to frame what behaviors are accepted for a program doing such a negative shifts, just as you did in your post !
So let's say : arbitrary (but consistent) values are fine, termination is fine. That's great because it means we can still compile a shift to a CPU shift and there's no UB anymore. Ok.
Same goes for signed overflow.
However this is a case by case process, and you will absolutely not be able to ascribe meaning this way to many forms of UB. For example, as the GP said, storing through an invalid pointer.
If you want to compile a pointer store to a store instruction without runtime checks, then possible observable behavior include : other variable changing values, function call not returning to their calling context, and even of course running a full ROP chain exploit !
It's no surprise that in that case the specs says that the set of allowed observable behaviors is anything.
- allowed to assume that the negative shift does not happen (what it says now)
- the value of each dynamic negative shift is unspecified but it must have a well defined value, however the same shift operation in the source code could return a different output given the same inputs dynamically (eg in a different loop iteration or function call)
- each source code shift is a well defined (unspecified on negative inputs) function
- all shifts in the program are a well defined (unspecified) function
So, for example, the last (least surprising) version means that you have to compile every shift to the target CPU's shift and that you also have to use the target's behavior when you constant fold a shift at compile time.
I absolutely agree that once wrapped up there are good reasons to use a language-level interface instead of asm for most things.
TBH I find assembly kernels generally more readable as long as one keep a few comments in there to explicit register allocation.
All other things being equal, I guess it's a plus to conform to the letter of the standard, except they are not.
It's much more productive to pick a few practical compilers/architectures as your target and allow yourself to work within the assumptions they provide you.
I'm sure some people will disagree but I'd much rather enable no-strict-aliasing and be on my way than trying to figure out if I actually abide by the convoluted standard rule, since, after all, it does not mandate the existence of this option.
In practice you can play a lot of tricks to avoid the overhead.
One example would be NaN-tagging. Another would be to speculatively store the array elements "unboxed" as long as they all have the same type and fallback to pointers when the array actually becomes heterogeneous.
I'm not up to date on what today's javascript JIT do for storage optimizations but when you add in sparse arrays etc, I'm sure it's quite involved.
I don't think most artist in a studio would be happy with a tablet interface, except maybe if it's a Cintiq.
You're right though that GPU schedulers are more advanced that plain round robin since they work around stalls and issue insns from multiple thread / cycle when the backend can take it.
I have no experience with KNC/KNL, but I wish I did :-)
In fact it's often mentioned that the reason GPUs are fast is that they have "a lot of dumb cores". It's true, but that's somewhat unrelated to the SIMD width.
One of the big reason why you can get away with dumb cores is that since you have so many independent threads (actual threads with independent PC), you can go with super-wide SMT (up to say 64 instead of 2 for intel HT).
This way you keep a deep pipeline full cheaply (by issuing from each thread in turn), while a CPU has to scramble and spend power/area to do so (branch pred., OoO, ...). Well, I guess the huge register files are not quite cheap but still.
The barrel processor style is to me a way more defining characteristic of GPU vs CPU design than the SIMD capabilities.
Then of course, wide SIMD on top of that is good for flops.
On the other hand, although the ISA is public, I'm guessing the whole boot-process & platform will become more and more closed as apple moves towards custom chips all the way down.
Is there any chance you can still run linux on mac hardware in 5 years ?
Not much to look at yet but interesting notes & comments in there.
I love how one of HotSpot's main author's java style is so unceremonious and bare bones.
It's so frustrating to read what the GPU is actually capable of (for example in the intel PRMs) and to know that there is absolutely no way to get the driver's compiler to do the right thing in a reliable way.
I mean imagine if icc was the only x86 compiler.
A reasonable alternative would be to implement OpenGL on top of Metal for compatibility but this is a lot of work.
If they had developed a good powerful code search (custom semantic engine for most used languages, complex queries, exact/fuzzy matches for syntax, use of history, etc) they could have become the primary way you interact with code you don't know yet.
As it stands now it's simply more efficient to clone and use plain old grep, it's really sad.
I know very little about ruby specifically but IME for this kind of dynamic language you get most of the initial gains by :
- removing (by analysis or speculation) dynamic dispatch
- unboxing / avoiding allocations in the easy cases
Once you've done that, you can generate pretty dumb assembly and still come out way ahead of your interpreter (and avoid very costly optimization / instruction selection / regalloc / scheduling).
Most of what llvm / gcc do only make sense when you've got your code down close to whatever you would actually write in C.