Game developers make a number of assumptions about how the compiler works. SN Systems has implemented “Check CFC” (Compile Flow Consistency) to help ensure their assumptions hold true for the PlayStation®4 (PS4) compiler. This has been contributed to the open source LLVM compiler community.
Using intermediate assembly files
Assumption:
“Compiling straight to an object file is the same as compiling to an assembly file then assembling.”
Assembly files are often used in game development for detailed work. The code in example 1 demonstrates an issue found when using an intermediate assembly file. The Check CFC tool shows that the compiler used a long instruction encoding when compiling directly to object files. However, a shorter and more efficient encoding was generated when an intermediate assembly file was used. This does not look like much, but extra code can affect behavior and the difference can be distracting when trying to focus on game performance.
int foo(int a)
{
return ++a;
}
Example 1: source code
$ clang -c increment.c
Check CFC, checking: dash_s_no_change
Code difference detected with -S
--- /tmp/tmpusdb4b.o
+++ /tmp/tmprdm_gk.o
@@ -6,6 +6,6 @@
0000000000000000 <foo>:
0: 89 7c 24 fc mov %edi,-0x4(%rsp)
4: 8b 7c 24 fc mov -0x4(%rsp),%edi
- 8: 81 c7 01 00 00 00 add $0x1,%edi
- e: 89 7c 24 fc mov %edi,-0x4(%rsp)
- 12: 89 f8 mov %edi,%eax
+ 8: 83 c7 01 add $0x1,%edi
+ b: 89 7c 24 fc mov %edi,-0x4(%rsp)
+ f: 89 f8 mov %edi,%eax
*** Diff truncated ***
Example 1: Output from Check CFC testing tool
Debug info generation
Assumption:
“Generating debug information does not have side effects on generated code.”
Game developers need to debug the exact same code that they release. In example 2, there is a difference in the generated machine code when compiled with and without the “–g” (debug) option. A mov instruction was not removed by the compiler when “–g” was enabled. Again, this may look like a very minor difference; however, these little issues can cause developers headaches when debugging problems in their game code.
struct Foo
{
bool bar();
bool operator==(Foo &baz) { return (this == &baz); }
};
Foo *wibble;
bool Foo::bar() { return (*this == *wibble); }
int main() {}
Example 2: source code
$ clang -c -O2 test.cpp
Check CFC, checking: dash_g_no_change
Code difference detected with -g
--- /tmp/tmpk4rtvb.o
+++ /tmp/tmpc8erml.o
@@ -5,6 +5,6 @@
0000000000000000 <_ZN3Foo3barEv>:
0: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax
- 7: 48 39 38 cmp %rdi,(%rax)
- a: 0f 94 c0 sete %al
- d: c3 retq
+ 7: 48 8b 00 mov (%rax),%rax
+ a: 48 39 f8 cmp %rdi,%rax
+ d: 0f 94 c0 sete %al
*** Diff truncated ***
Example 2: Output from Check CFC testing tool
“Check CFC” – Testing Compile Flow Consistency
SN Systems developed the “Check CFC” tool to find issues like the examples above. “Check CFC” masquerades as the compiler, running the real compiler in multiple ways that a developer would expect to generate the same machine code. It checks that the generated code in each object file is identical. If a difference is found, it shows the affected machine code to help us track the bug down.
These examples were real bugs discovered in the LLVM compiler by “Check CFC” and promptly fixed by the LLVM open-source community.
Summary
The PS4 compiler is based on the LLVM project. SN Systems work with the hundreds of people across the globe in the open-source community to improve the quality of the compiler. Game code has unique characteristics compared to other software markets and game developers have different workflows to other software developers, so we develop tools to test the compiler in ways that are important in game development.
This “Check CFC” tool has been contributed to the LLVM compiler project and is available here (http://llvm.org/svn/llvm-project/cfe/trunk/utils/check_cfc/). Contributing the checker to the LLVM community helps ensure new bugs of this nature are captured and fixed early, before users of the compiler ever get hold of it.
Back to top