Performance tips

You can follow a couple of good practices to speed up your XC=BASIC programs.

Tip #1: Use the right type

While floats allow a much wider range of values, it's way much slower to operate on them. Always use integers if you don't need the precision of floats.

Bytes are even faster, but offer a very small numeric range. Use them if you are sure that the value will always range between 0 and 255.

Tip #2: Use FAST variables

Since version 2.1, some variables can be placed on the zeropage for faster load/store operations. See DIM for details.

Tip #3: Do arithmetic only when necessary

Even the simplest addition or subtraction can take precious time, especially when used in loops. Make sure to eliminate all the arithmetic operations that are not necessary in runtime.

Wrong example:

rem ** draw a line on the bottom of the screen **

const SCREEN = 1024

for i! = 0 to 39
  poke SCREEN + 40 * 24 + i!, 99
next i!

Notice that the expression SCREEN + 40 * 24 is evaluated in every iteration although the result is always the same. You should rather do the math yourself:

rem ** draw a line on the bottom of the screen **

const BOTTOM_LINE_START = 1984

for i! = 0 to 39
  poke BOTTOM_LINE_START + i!, 99
next i!

Note: you may say that the compiler should be smart enough to recognize operations on constant values and evaluate them in compile time - and you'd be right. Maybe this kind of optimization will be implemented in a later version.

Tip #4: Use constants

Unlike variables, constants do not need to be accessed from memory when they're being evaluated therefore they're evaluated much faster.

Tip #5: Use INC and DEC


  inc a

instead of

  a = a + 1

is considerably faster.

Tip #6: Provoke fast array operations if possible

If the compiler detects that the array subscript of a byte type array is also a byte type, it will exploit the processor's fast indexed store and lookup operations, resulting to a much higher speed. Examples:

rem -- this is SLOW
dim x![100]
index = 50
print x![index]

rem -- this is FAST
dim x![100]
index! = 50
print x![index!]

Tip #7: use ON for branching

An ON … GOTO or ON … GOSUB construct is faster than its IF … THEN GOTO/GOSUB equivalent. It's especially useful when branching on a TRUE/FALSE condition, for example:

rem -- branching using IF ... THEN
rem -- assume x! is a zero or one (TRUE/FALSE) value

if x! = 0 then goto false_case else goto true_case

rem -- same as above but FASTER

on x! goto false_case, true_case

Tip #8 REPEAT ... UNTIL is faster than FOR ... NEXT

You can gain some speed boost using REPEAT … UNTIL instead of FOR … NEXT:

for i!=0 to 99
next i!

Equivalent but faster:

i! = 0
  inc i!
until i! = 100

Tip #9: Use LSHIFT() and RSHIFT()

It's much faster to multiply or divide by powers of two using bit shifting operations. Use LSHIFT() and RSHIFT() whenever you can.

Tip #10: Know the optimizer

XC=BASIC features a built-in optimizer that replaces commonly used program sequences with faster opcode sequences. To make good use of the optimizer, bear in mind the following program structures that can be optimized:

  • Value assignment of bytes and integers
  • Addition of bytes and integers
  • Subtraction of bytes and integers
  • Comparison of bytes, e. g. IF x! > 5 THEN …
  • IF, WHILE and UNTIL statements with byte type comparison as condition, e .g WHILE x! <= 255
  • Array access of byte type arrays with byte type index
  • Bitwise operators on bytes
  • POKE and PEEK (they're the fastest when using constant addresses)

The following are not optimized at all:

  • Operations on floating point types
  • I/O commands like PRINT, etc.
  • Convenience commands like TEXTAT