3 ms·
Absolutely yes, for many different reasons: 1. If you program in any compiled language, being able to read assembly is critical to figuring out what the compi
by DarkShikari 15y ago
Absolutely yes, for many different reasons:
1. If you program in any compiled language, being able to read assembly is critical to figuring out what the compiler is doing with your code. A quick glance over the assembly can often reveal why the code is slower than expected, often including suboptimalities in your higher-level code such as unexpected aliasing.
2. If you program in a C-like language, parsing the output of gdb is impossible (beyond the bare basics) without knowing assembly.
3. SIMD assembly can give performance improvements of 10-20x or even higher for many types of real-world code. Skill at using SIMD is in incredibly high demand at the moment, especially on ARM (with NEON). If you are writing code where performance is critical, you should always consider how to optimize with SIMD. If you don't, you're effectively throwing away >90% of the capabilities of your CPU.
4. If you understand the capabilities of the machine you're optimizing for, you can better write code (in a low-level language like C) to take advantage of it. Examples of this include the ability on ARM to do conditional instructions effectively for free, or the ability on x86 to do reg3 = (reg1+(reg2<<{0,1,2,3})+<const>) in one instruction.
Learning assembly is quite easy; for example, last Google Code-In we had a student (age 17) who started knowing not a single iota of anything about assembly and, within a week, was writing literally thousands of lines of SIMD code and passing stringent code reviews.
- psykotic 15y ago> SIMD assembly can give performance improvements of 10-20x or even higher for many types of real-world code. Using SIMD intrinsics is often preferable. For set-in-stone inner loops, the extra performance you can wring out by hand-writing in assembly may be worth it, especially on compilers with shitty support for intrinsics. For SIMD-based leaf functions that are going to be inlined in many contexts, intrinsics have the advantage since the compiler can schedule and register allocate the instructions piecewise rather than treating them as an indivisible block with hard-wired registers (GCC-style clobber lists are supposed to help the compiler do that with inline assembly, but it sucks in practice). My opinion is that every programmer should learn enough assembly to fluently read the code generated by their compiler, but most of them should not be writing it. Debugging is the number one pay-off, but keeping tabs on what the compiler's optimizer does with your C code is a close second. There was a good illustration of this last week on Hacker News. Someone submitted a StackOverflow thread where they were competitively coding a fast fixed-size sort based on sorting networks. The tentative winner at the time was using some god awful hand-cooked branchless code for min/max that was completely defeating the compiler's attempts at generating the simple and optimal cmp r0, r1; mov r2, r1; cmovg r1, r0; cmovg r0, r2 instruction sequence. That would have instantly obvious if they had the habit of reading their compiler's assembly. The result is that they were leaving a ~3x performance gain on the floor.
- deleted 15y ago[deleted]
- DarkShikari 15y agoIntrinsics tend to be incredibly difficult to read (and write) compared to hand-written assembly. For practical purposes, it's write-only code, and C simply doesn't provide the syntactical niceties necessary to easily write assembly code. Inlining SIMD functions is typically not possible in most applications unless you're compiling a dozen versions, one for each possible CPU, since different CPUs will use different SIMD functions that are optimized for their performance characteristics. Nevermind the fact that intrinsics generally give atrocious performance compared to properly-written code, as your average 3-year-old can probably allocate registers better than gcc.
- psykotic 15y agoIntrinsics are about the same level of readability in my experience. Although it's annoying that compilers tend to pile on prefixes to the instruction mnemonics and thereby make everything longer. If that's a big problem for you, just use your own short-hand macro wrappers. > Inlining SIMD functions is typically not possible in most applications unless you're compiling a dozen versions, one for each possible CPU, since different CPUs will use different SIMD functions that are optimized for their performance characteristics. I mainly care about games when it comes to high-performance programming, so this is not an issue for me. Consoles are obviously fixed platforms, and on PC any game is likely to have high enough performance requirements across the board that you can compile your executable against a SSE3 min-spec target without excluding users because of that. > Nevermind the fact that intrinsics generally give atrocious performance, as your average 3-year-old can probably allocate registers better than gcc. I'm glad we agree that GCC is a pile of shit (and not just in this respect). MSVC's performance with intrinsics has also gone up and down with versions but by now it's pretty solid.
- DarkShikari 15y agoI mainly care about games when it comes to high-performance programming, so this is not an issue for me. Consoles are obviously fixed platforms, and on PC any game is likely to have high enough GPU requirements that you can compile your executable against a SSE3 min-spec target without excluding users. The instruction set available is often not the most relevant thing. In many cases, the optimal code will differ wildly between CPUs regardless of the available instruction sets. Let's look at some quick examples of performance characteristics: Athlon 64: Slow SSE2 unit, MMX is often faster than SSE2 for many functions. Phenom: Very fast SSE2 unit, but missing SSSE3 support, so can't take use the same optimized functions in many cases as the Core 2 and above. Significantly higher instruction latency than Core 2, so needs significantly more pipelining. Core 2 Conroe: SSE shuffle operations (punpck, etc) are excruciatingly slow: 4/2 for shuffles that use both arguments as input data (e.g. punpckldq), 2/2 for those that use only one argument (e.g. pshufb). Cacheline-split loads are extraordinarily painful (equivalent to an L1 cache miss, or ~14 cycles). Core 2 Penryn: Same as Conroe, but shuffles are fast now (1/1 for everything basically). Nehalem: Cacheline-split loads are cheap now (2 cycles), and shuffles have doubled throughput compared to Penryn (1/0.5). This doesn't even get into the more instruction-specific messiness, like how some CPUs like movddup and movhlps on integer data while others don't. It's not uncommon to have 3 or 4 assembly functions just to cover the latest CPUs -- not even counting old ones. Fortunately for our sanity, these are usually templated from a single function, with small changes to the relevant areas created via macros.
- deleted 15y ago[deleted]
- colinb 15y agoHelp me out here please. I've done plenty of assembly programming on other architectures, 6502 to MIPS, and many in between, but I've never needed to learn x86. Now, when I poke around, I find that it has a huge instruction set, with a variety of funky features, SSE, MMX and so on. I suspect that most of what I read about is now dead technology, supported by current chips for the sake of backward compatibility. So, let's assume I understand the concepts of assembler. I'm not afraid of stack frames, or interrupts. How do I learn a moderately current subset of x86 instructions? thanks c