TRaX Programming Guidelines

In order to ensure compatibility with our compiler toolchain, and to enforce efficient coding practice, you must follow these guidelines when programming TRaX. Make sure you familiarize yourself with trax.hpp, which contains many useful and necessary functions for programming TRaX.

Function argument passing

Always pass variables by reference. Passing variables by reference eliminates the need to push arguments on to the stack (copy them), and will significantly reduce the pressure on the threads' local scratchpad memory, and will save a lot of work. The compiler requires you to do this. If you do not desire for the called function to be able to change the variable passed in, which is normal pass-by-value behavior, simply pass the argument as const reference. For example, here is the signature for a simple sphere's ray intersection function, from assignment 1:

inline bool Sphere::intersects(const Ray& ray)

Function inlining

You should declare any function that is reasonable to do so as inline. This saves some work in the setting up and tearing down of stack frames that the compiler would normally have to do.

Dynamic Memory

TRaX does not support dynamic memory allocation (new, malloc, etc...). Dynamic memory allocation is extremely slow and can cause severe performance degradation, especially in the inner loops of your code. For example, dynamically allocating a ray can take as much time as fully tracing several rays. Be warned that your code will compile if you try to use new or malloc, but it won't pass TRaX's assembler, since there will be a call to an undefined symbol (new or malloc).

Float Data

TRaX does not support the double data type. Your code must not contain any doubles, implicitly or explicitly. This may be hard to get used to at first, since the compiler treats floating point literals as doubles by default. For example, the literal (1.3) is actually treated as a double. Furthermore, if you use any integer literals that will get automatically cast to a float, such as:

float a = 5;
The literal 5 will be treated as a double, instead explicitly specify that all values that may be used in floating point computation are float instead of double by putting 'f' after the literal, such as this:
float a = 5.f;
if (a > 0.f) //...

Global Variables

The TRaX compiler does not support global object variables. It can support primitive globals that don't have to be constructed (int, float, etc), but in general, stay away from global variables.

Virtual Functions

The TRaX compiler does not support virtual functions (and thus, no inheritance). This is another example of a restriction that will end up being a good thing. Calculating virtual function addresses is much more costly than calling the function directly.

Debugging

It is recommended that you use the CPU compiled version of code for debugging first, since it will run much faster than the simulator. Once you are convinced your code is correct, then try to run it on the simulator. TRaX does not support printing string or text data, however, you can print single integer or float values with trax_printi and trax_printf. If you want to print string data (using stdio.h), put it inside of a #if compiler directive that checks if TRAX has been defined to 1. For example:

#if TRAX
   // do a simpler print here using trax_printi or trax_printf
#else
   printf("using stdio's printf only if TRAX is not defined as 1");
#endif
This will print in the CPU version of your code, but not in the TRaX version. Use this to help debug while running the CPU version of your code.