Firm Logo

Coding Conventions

This document summarizes libFirm coding style conventions.

Indentation and formatting

Example
ir_node *maybe_create(int a, int b)
{
    ir_node *z = NULL;
    if (a + b < 10) {
        z = create_node(a, b);
    } else {
        do_something();
    }
    return z;
}
  • function and variable names are all in lowercase; words are separated with an underscore _

  • the star from pointer declarations is put next to the name to be declared (Wrong: ir_node* foo; Right: ir_node *foo;)

  • opening curly braces for functions start on a new line

  • opening curly braces for if, while, etc. start on the same line!

  • in a call there is no space between the function name and the braces for the arguments

  • there is a space between builtin keywords (if, while, switch, for) and the following opening braces.

  • return is not a function call. So no braces around the return value

  • Try to keep lines shorter than 80 characters (breaking this rule is tolerated)

  • Don’t break message strings between 2 lines. (so you can grep for messages in the source)

Indentation

  • Indentation at the beginning of the line is done with tabs.

  • Indentation to match certain points in the previous line is done with spaces (see next part)

Indentation Example (using <T> to show tabs)
void func(void)
{
<T>if (bla < 20 && foobar_bar(long_variable_name) || another_long_thingy
<T>    && this_was_a_long_condition) {
<T><T>print();
<T><T>foobar(a, b, more_long_stuff_here,
<T><T>       and_this_is + another * (longish - argument);
<T>}
}

This style allows different people to set tab to different sizes and still get nice layout. Most firm developers tend to set tab to 4 spaces though.

  • Case labels should not get extra indentation. Correct example:

switch (foo) {
case BLA_ENUM_VAL:
    FooBar();
    break;
default:
    break;
}

Documentation

  • All functions in the public API (= stuff in the headers in libfirm/include) must have at least a short doxygen documentation

  • Documentation for functions should be put in the header (except of course static functions which are only in the C file)

  • Each file must have an @brief doxygen comment describing the intention/purpose of the file (except public headers with a detailed description in a @defgroup)

  • Each file must have an @author doxygen comment so that we can easily see who has written what code.

C99

While alot of firm code has been written for C89, we do use C99 now. Use it:

  • Use the bool type from stdbool.h .

  • Move declarations as close as possible to their first assignment.

  • But as we don’t want to force our users to use C99 we keep the public API free of C99. So no bool type in the public headers.

Bad
void bad_example(ir_node *arg0, int swap_directions)
{
        int arity;
        int i;
        ir_node *n, *left, *right;

        arity = get_irn_arity(arg0);
        for (i = 0; i < arity; ++i) {
                n = get_irn_n(arg0, i);
                left = get_binop_left(n);
                right = get_binop_right(n);
                if (swap_directions) {
                        ir_node *tmp = left;
                        left = right;
                        right = tmp;
                }
                do_something(left, right);
        }
}
Good
void good_example(ir_node *arg0, bool swap_directions)
{
        for (int i = 0, arity = get_irn_arity(arg0); i < arity; ++i) {
                ir_node *n     = get_irn_n(arg0, i);
                ir_node *left  = get_binop_left(n);
                ir_node *right = get_binop_right(n);
                if (swap_directions) {
                        ir_node *tmp = left;
                        left = right;
                        right = tmp;
                }
                do_something(left, right);
        }
        /* even better in this case: foreach_irn_in(arg0, i, n) { ... } */
}

Tips & Tricks

  • Subclassing

  • Allocate memory with the macros from xmalloc.h to be more robust against type errors.

  • Use the const modifier freely, even for non-pointers. It makes program understanding easier if you can immediately see that a variable is only assigned once.

Tools

AStyle

You can use astyle to enforce some of the rules above with the following options (needs astyle 2.00):

--indent=tab=4
--style=stroustrup
--indent-cases
--indent-col1-comments
--pad-header
--pad-oper
--keep-one-line-statements
--align-pointer=name

Whitespace Check

A simple python script to check at least the tab/whitespace rules:

#!/usr/bin/env python
import sys
import re

file_list = sys.argv[1:]

for filename in file_list:
    file = open(filename, "r")
    num  = 1
    lastline = None
    for line in file.readlines():
        # Tab characters are only allowed as very first characters on a line!
        if re.search("[^\t]\t", line):
            print "%s:%d:  tabulator not at beginning of line" % (filename, num)
        if re.search(" +$", line):
            print "%s:%d:  trailing whitespace" % (filename, num)
        num += 1
        lastline = line
    if lastline != None and lastline[-1:] != '\n':
        print "%s:%d: No newline at end of file" % (filename, num)

Emacs

The following style spec appears to make Emacs obey the coding conventions:

(c-add-style "firm"
            '("stroustrup"
              (case-label . 0)
              (statement-case-intro . +)
              (statement-case-open . +)
              (indent-tabs-mode . t)
              (c-basic-offset   . 4)
              (tab-width . 4)) nil)