22
\$\begingroup\$

On average, how often is assembly used in modern game code?

Specifically on platforms that already have good C++ compilers, like x86, PPC, or ARM--because I assume games on embedded systems make extensive use of assembly.

\$\endgroup\$
10
  • 4
    \$\begingroup\$ C++ doesn't compile to assembly - it compiles to machine code. Assembly language is a way of directly specifying exactly what machine code you want to be generated. \$\endgroup\$
    – Kylotan
    Jul 10, 2012 at 2:32
  • 6
    \$\begingroup\$ C++ is (generally) not actually compiled to assembly, it is compiled directly to machine code. The question is probably referring to how much hand-written assembly is linked in to a project or written as inline assembly. \$\endgroup\$
    – user1430
    Jul 10, 2012 at 2:33
  • 1
    \$\begingroup\$ Regardless, I don't think there is a practical, useful answer to this question. It basically depends on a like of factors, many of which are subjective (i.e., the opinions of the authors of the code). \$\endgroup\$
    – user1430
    Jul 10, 2012 at 2:33
  • 1
    \$\begingroup\$ Not so much writing assembly is important these days, with some exceptions like SPU programming, but being able to read it is important for analysing crash dumps \$\endgroup\$ Jul 10, 2012 at 7:13
  • 4
    \$\begingroup\$ @Legion - you can cause the compiler/IDE to emit assembly, but that does not mean that the compiler produces assembly as part of a normal compilation process. It is not necessary for it to do so and consequently, most do not. \$\endgroup\$
    – user1430
    Jul 10, 2012 at 17:24

4 Answers 4

29
\$\begingroup\$

The answer depends a bit on what you mean by "game", and on "used". I'll assume "used" means "written during the course of the specific game project".

In my experience and anecdotal data from people I've talked to:

  • in browser based games? None.
  • in typical PC games? None. (But you might see some in low level libraries.)
  • in iOS and Android games? None.
  • "AAA" PC games and console games? Maybe a little, perhaps 0.05% of the code base. (With a bit more in the libraries.)

Knowledge of assembly language is not expected for work in the games industry, but depending on the type of games you make, it might come in advantageous.

There used to be an argument that the compiler does a better job at optimising C code than a human would with hand-written assembly. Usually that's true, sometimes it's false. But these days a combination of ever-growing CPU complexity and the need to scale 'out' (ie. to separate processors) means that optimisation efforts are usually spent elsewhere.

In recent years the only time I've seen assembly in game code was __asm int 3 statements to force breakpoints, and my only personal use of assembly was in looking at the disassembly of a function to diagnose unusual crash bugs.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ What about SSE instructions? \$\endgroup\$
    – Legion
    Jul 10, 2012 at 3:18
  • 4
    \$\begingroup\$ @Legion, people usually write SSE code using either intrinsics, or math libraries that wrap the SSE stuff, or in a specialized mini-language designed specifically to compile to SSE, such as ispc. Writing assembly directly is still pretty rare. \$\endgroup\$ Jul 10, 2012 at 4:00
  • 1
    \$\begingroup\$ Regarding iOS Games: If I remember correctly, the 3D/Math library Oolong used some inline ARM assembly. That is no longer needed since Apple released the Accelerate framework. \$\endgroup\$ Jul 10, 2012 at 7:04
  • \$\begingroup\$ Agreed with Nathan - SSE and similar instruction-specific optimisations usually exist within libraries (since they are usually the only places where the total benefit gained is worth the effort put in). \$\endgroup\$
    – Kylotan
    Jul 10, 2012 at 12:32
26
\$\begingroup\$

The bulk of high performance code in modern console games is written using a sort of middle ground between assembly and C++: compiler intrinsics. These constructs look and parse like C++ functions, but are actually translated into single machine instructions. So, for example, my "clamp each value of vector V to be >= a and <= b" function looks like

// for each v.x, ensure v.x >= a.x && v.x <= b.x
inline __m128 ClampSIMD( const __m128 &v, const __m128 & a, const __m128 & b )
{
    return _mm_max_ps( a, _mm_min_ps( v, b ) );
}

In functions like these I'm still thinking in terms of the specific machine instructions, but I have the convenience of writing them in C so that I don't need to worry about register coloring and scheduling and load ops and other boring details.

You still need to be aware of what instructions the CPU supports, especially because modern compilers are terrible at vectorizing code, compared to how well a smart human can do the job. Also sometimes subtle details of how you arrange your code can have huge implications for performance that aren't obvious without understanding what the machine is doing.

Although we may not code in assembly, we still debug in assembly a lot. Optimizing compilers aggressively reorganize code in ways that debuggers can't keep up with, so often when debugging a "release mode" build the best thing to do is pop open the disassembler and trace through the code that way. This GDC talk on "Forensic Debugging" of crashes illustrates many of the whys and hows of debugging at that level.

\$\endgroup\$
3
  • 3
    \$\begingroup\$ +1 simply because Crashworks is well known on SO as being "that guy who writes really low-level optimized code for games" - if anyone knows about this topic, it's him. \$\endgroup\$ Jul 10, 2012 at 7:28
  • \$\begingroup\$ @BlueRaja-DannyPflughoeft "Well known"? I'm flattered! =) An amusing coincidence, in light of Nathan Reed's comments, is that I learned many of my low-level optimization skills at Naughty Dog. \$\endgroup\$
    – Crashworks
    Jul 10, 2012 at 7:32
  • \$\begingroup\$ Elsewhere I have also heard the importance of assembly in debugging. So I'm going to learn it. Thanks for the insight and links. \$\endgroup\$
    – Legion
    Jul 10, 2012 at 20:08
7
\$\begingroup\$

The problems that used to require hand rolled assembly are getting fewer in number. What you "might" gain in speed you lose in readability and the ability to debug. It should also be done only as one of the very last optimisation steps on sections of code as in most cases speed problems aren't something that can't be made better with assembly. These days CPU's have gotten much faster while memory speeds have not, often it's more important to control how data flows through the CPU than anything else.

With modern compilers they also find it hard to optimise around assembly code as they have to deal with whatever registers you've touched and they can't usually re-order instructions in your hand crafted code. To reduce the need for assembly, there is also now intrinsics which help to get access to low level concepts, but in a way that is compiler friendly and allow them to work with you rather than against.

With that said, the SPU on the PS3 is one area where people are still having to use assembly to get the most out of the processor, with manual instruction pipelining for example as explained here.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Even on PS3, people usually don't quite program in bare assembly. There is a tool that lets you write code in assembly-like syntax, where you specify the machine instructions, but it does the register allocation, instruction scheduling and loop pipelining for you. Well, maybe Naughty Dog really does do it all by hand, but even most PS3 SPU developers don't in my experience. :) \$\endgroup\$ Jul 10, 2012 at 4:04
  • 1
    \$\begingroup\$ @NathanReed In the PS2 days, manual loop pipelining was actually part of Naughty Dog's programmer interview. \$\endgroup\$
    – Crashworks
    Jul 10, 2012 at 5:06
-1
\$\begingroup\$

The fact is that we live in a multi platform world, and parts of our game code have to be tailored to the local platform - well not have to, but there are benefits if we take advantage of local hardware stuff!

This is not about games or game logic, it's about hardware locality for optimal performance of the code upon which game logic hinges, we can indeed wrap code sections, for example using macros, such that there is one source code, which executes well on the platform it was built against.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .