Apple’s Bitcode Telegraphs Future CPU Plans
medium.com
medium.com
My most radical speculation is an iPhone A-series chip with an additional low power ARM core especially to support Watch apps without burning too much "host" device battery.
The one place I've seen little-endian actually be a help is that it tends to catch "forgot to malloc strlen PLUS ONE for the terminating NUL byte" bugs that go undetected for much longer on big-endian machines. Making such an error means the NUL gets written just past the end of the malloc, which may be the first byte of the next word in the heap, which (on many implementations of malloc) holds the length of the next item in the heap, which is typically a non-huge integer. Thus, on big-endian machines, you're overwriting a zero (high order byte of a non-huge integer) with a zero, so no harm done, and the bug is masked. On little-endian machines, though, you're very likely clobbering malloc's idea of the size of the next item, and eventually it will notice that its internal data structures have been corrupted and complain. I learned this lesson after we'd been shipping crash-free FrameMaker for years on 68000 and Sparc, and then ported to the short-lived Sun386i.
Actually, it is possible that that was nothing more than an accident. We use Arabic numerals, and Arabic languages are written right-to-left. Then there are languages like German where digits are read in reverse, so "42" is read as "two-and-forty".
The german thing is just weird until you get used to it, with french I constantly go, wait, crap this is over 70, whats the deal again. I blame the wine consumption.
The cardinal number systems for most major languages lead with larger terms (as in English). I don't think there's anything deep about this, it's probably an accident. And there are languages which lead with smaller terms, such as Malagasy (the national language of Madagascar).
The ordering of digits in Arabic is not obviously relevant, per se, since spoken English ("one hundred twenty one") matches the order of the Arabic numbers, too.
I think it is relevant. It is possible that Western mathematics copied the Arabic notation (with right-to-left numbers), without also copying the correct way to read it (also right-to-left). For a similar situation in language, think of accents and the many different ways you can pronounce the same word.
"For a similar situation in language, think of accents and the many different ways you can pronounce the same word."
Could you be more specific as to what you mean?
Technically, I'd drop the "th of" and just say/write "11 September 2001".
It took me a while to figure this out because actually it's quite rare to speak a date including a year without reading it - most spontaneously-spoken dates are this year (so the year is implied) and for a read dates, I'd probably say whatever was written.
The clincher was how I'd say my birth date, which would be of the form above.
I'm not claiming to be the definitive British English speaker, though! ;)
...and as another poster commented, it might depend on context - for example, "September 11" is often used in British English because it refers to an American event.
Any other dates will likely be in the same order as written. For instance, the rhyme for bonfire night is 'remember remember, the fifth of November'. I believe that many in the US also talk about the fourth of July, rather than July fourth, so it's not like English has the hard-and-fast rule you were proposing.
I think we should all take a moment to admire the francophone Swiss for boldly dropping much of the madness that is french counting. (Yes, I am looking at you, quatre-vingt-dix-neuf!)
For example, you can write out e as 2.7182...
However, if we were to flip this notation, ...2817.2, it isn't clear where to begin writing the number, if we read(and write) from left to write. With the regular representation, you write out the 'major' parts of the number first and then give out as many details as you want. You have the beginning of your string in mind. With a reversed system, you don't have the beginning but the end of the string in mind.
Anyway, it doesn't matter what you think is 'more natural.' Computing in binary probably feels less natural to you, but nobody is going to stop making binary computers because of that.
Little endian is more natural for data structures. The least significant bit goes in the byte with the least address, and the most significant bit goes in the byte with the greatest address, so you never have to remember which way you're going, which is particularly nice when working with bitvectors and bit fields.
"Left" and "right" can go either way, depending on which kind of diagram you draw, even on big-endian machines, so those words always end up ambiguous. Stick to bit significance and address order and everything is unambiguous and naturally inclined to little endian.
I'm not sure what you mean by the bit shifting case. The 8 char ASCII sting compare is a neat trick with limited applicability these days.
This article covers the practical tradeoffs of little and big-endianness well: https://fgiesen.wordpress.com/2014/10/25/little-endian-vs-bi...
The tl;dr is that little-endian was a smart performance optimization in the early microprocessor days when nearly all arithmetic was effectively bignum arithmetic (because the ALUs were only 4 or 8 bits wide), but that doesn't really matter now, so we're stuck with little-endian despite big-endian having some small developer productivity benefits.
The thing is, little-endian won pretty much everywhere outside of network protocols, so almost all of the common data formats store words in little-endian format as a performance optimization. By going big-endian, you'd be both forced to eat a byte-swapping performance hit on every load or store to these formats, and you'd break a tremendous amount of software that assumes it is running on a little-endian architecture. Dealing with those headaches would absolutely not be worth the trouble for the almost insignificant benefit of slightly easier to read hex dumps, or the slightly more useful benefit of string comparison via memcmp that could be better performed by dedicated SIMD instructions anyway.
there's your problem, you're living on earth. try living in the cloud. :) (network byte order)
4.x > V ∀ x from 0..∞
There's ABI specific pieces that are still not abstracted in the bitcode like struct packing rules.
Much of this article is simply inaccurate speculation.
There are things you can do if the ABI's are the same, such as optimize for microarches, but they otherwise have literally no idea what they are talking about.
Bitcode is meant for repeated optimization of the same IR.
That is, it would make sense to start from a well-optimized AOT compiled version of bitcode, then JIT the bitcode at runtime and try to come up with something better once you have profiling feedback.
I expect this is the plan, given that it's what everyone else who is serious about LLVM does.
It would not make any sense to start from bitcode and try to generate code for different architectures.
LLVM is a low level virtual machine for a reason.
There has been work on things like virtual ISA's using LLVM (see http://llvm.org/pubs/2003-10-01-LLVA.html), but the result of this research was, IMHO, that it's not currently a worthwhile endeavor. You also can do things like restrict bitcode in ways that make it portable (like, for example, PNaCL), but this is closer to the LLVA work than anything else (It's essentially a portability layer) It actually still requires porting, just porting to the single portability layer.
That can be important information. For example, the translator might not figure out where data embedded in the code (for example a jump table) ends, and, consequently, continue translating from a point mid-way into a multi-byte instruction.
Translating code that generates code (as done in JIT engines or to speed up image processing kernels) also is a challenge; the best one realistically can do is to translate the existing code as-is and then call the translator at run time to do the translation. If that works, the 'call the translator' step may kill any performance that was won by generating code.
Of course, self-modifying code is a challenge, too.
Due to the concerns above, IMO Bitcode is less about compatibility and more about app thinning. It's pretty easy to go from Bitcode to 4 different variants of ARM; but another entirely to go from Bitcode to x86 and ARM. Currently, developers have to ship binaries compiled for multiple architectures, which increases app sizes. I suspect Apple is just building a workflow that creates a device-specific version of each app, and having developers compile to Bitcode simplifies app submission.
https://developer.apple.com/library/prerelease/ios/documenta...
Going further, I think a team could get interesting results combining this with design-by-contract, typed assembly, and certified compilation. Much like verification condition generators, the compilation process would keep a set of conditions that should be true regardless of what form the code is in. By the time it gets to the lower level, those conditions & the data types can be used in the final compile to real architecture. It would preserve a context for doing safe/secure optimizations, transforms, and integration without the original source.
In the future, when your app crashes on customer's machines and doesn't on yours, how are you going to debug much less explain this to apple and have them fix the issue for you?
This is especially scary when you consider the turnaround time of ~2 weeks before your new build becomes available in the app store for you to test.
With software like that, Apple could become independent of any particular software architecture.
(TAOS dates from the 90's and is hard to google, but is mentioned in some papers. And yes, the JIT translator could do that even on 90's machines.)
The native byte code was 64bit, though iirc the first implementation used a 32bit address. The result was you could ship an application once and when it came time to move architectures all you had to do is one command to retranslate the byte code.
Very neat. I'm not sure why this approach hasn't been used more often.
EDIT: Looks like they're going exactly the AS/400 route.
AS/400 had some really cool technology built into it.
It does free them up in the future, they can make bigger hardware changes and just have to supply a bitstream player for the older code. I have a difficult time envisioning the architecture changes that make tons of sense to Apple right now though, other than like swapping video on their ARM chips and stuff like that. Running iOS apps on the desktop might make a ton of sense for some of them or some sort of tweener between the iPad and Mac book.
I have seen the binary translation in action: it was required when POWER6 machines came out. On a POWER5 machine, I remember it taking around 20 minutes for an application that was around 20 MB zipped, but for software licensing reasons not all of the server models exposed the full performance of the processor, so that might not be representative. And at any rate, like the OP said, it's a one time thing, and then the translated version is kept.
I suspect Bitcode is more about helping developers ship a single binary that works across 7 or 8 devices with slightly different ISAs. App thinning is a big push for Apple right now because app sizes are getting out of control with the number of variants that developers are required to compile to. Developers compile to Bitcode, then upload to Apple, who then compiles multiple versions of the machine code, using the App Store to download the correct bundle for the device.
Resources are a big part of it too, of course. A typical iOS app these days has three copies of every image, for 1x, 2x, and 3x resolutions. Dropping that down to one copy on the device is helpful. Of course this doesn't require any of this bitcode stuff, although neither does thinning the executable.
Not with the languages they use :)
Neither C, nor C++, nor swift, can be made portable to new architectures through bitcode.
At least, not without language-level changes to each of them.
For example, for C and C++, sizeof is a constant expression, so you can't easily just do something like "defer evaluation to runtime". Plus ifdefs, struct layout, etc.
ANDF tried to solve these problems many years back. It may have even been "mostly possible" with c89. But today's languages, not so much.
(Even things like PNaCL and emscripten and what have you have restrictions on what C++ they allow)
What prevents things like sizeof(T) or alignof(T) from being representable in the LLVM IR in a form that says, "defer to final translation" (to the target architecture)? Does substitution of platform-dependent types, for example, i64 for size_t on x86_64, happen prior to generating the LLVM IR? It would seem useful for me for LLVM IR to retain some platform-dependent types like size_t or intptr_t (deferring until final translation from bitcode to machine code), but maybe that would inhibit certain optimizations.
I can see an issue with template instantiation in C++: for example, if a template uses SFINAE to specialize a template for types of certain sizes, that needs to be evaluated purely at the C++->LLVM stage of compilation.
What is the compile time part of C do you mean? sizeof(T) is evaluated at compile time of course, but it would still produce pseudocode like:
if (4 < 16) { // sizeof(T) replaced with 4
// do something
} else {
// do something else
}
Of course, an optimizer would likely constant-fold that conditional expression to remove the branch entirely, but
I'm having a difficult time seeing how one could perform different behavior at compile time with sizeof(T) in C.https://scaryreasoner.wordpress.com/2009/02/28/checking-size...
There are many ways to make it perform different behavior at compile time (though admittedly, most are abuse). The above should compile error, but if you push sizeof evaluation, will not.
#define BUILD_BUG_ON(condition) extern int build_bug_on[!!(condition)-1]In LLVM world, Clang is performing most of the ABI lowering.
For C and C++, the answer is "yes", and "it must happen this way", because struct layout/etc will depend on it. Not to mention what you want is at some level, impossible in the LLVM IR. LLVM types are not C/C++ types. This leaves you with no type system capable to do the kind of thing you want to do :)
One minor caveat: ~16 years ago, in C99, C got variable-length arrays (VLAs). If you use the sizeof operator on a VLA, it is evaluated at runtime.
Of course that doesn't change your argument; I just wanted to mention it for completeness' sake.
http://gcc.gnu.org/ml/gcc/2004-12/msg00888.html https://gcc.gnu.org/ml/gcc/2007-11/msg00460.html
https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
I'm far from an expert, but from what I've seen and heard, gimple is pretty good for what it does. In other words, the author of the article is wrong to say that LLVM learned from a painful lesson in this area.
Now, whether Apple will do something like this is or not is anyones guess, but its nice to dream of the possibilities. :)
Doesn't make sense. What's the difference between "10-15 ARM processors" and 4-8-12 Intel based cores?
I mean apart from the fact that we aren't going back to multi-processor architectures, since there's no benefit from that compared to cores (latency, etc).