next_inactive up previous
Up: SAC-Homepage

Sac2c Compiler FAQ

This FAQ is meant to assist people who intend to or have already downloaded a version of sac2c. It covers basic information on different versions of sac2c as well as solutions to more sophisticated problems that may arise during installation / usage of sac2c.

If you encounter any problems that are not yet covered here, please do not hesitate to contact us directly or to join our mailing list.


1 General Questions on Sac2c

1.1 Which versions of sac2c are available?

It's first official version sac2c0.7 was released (as pre-alpha 8-) on 16th November 1998. Up to now this is the most recent version.

1.2 What does sac2c0.7 comprise?

sac2c0.7 includes support for the following features:
  • specification of dimension & shape independent algorithms on arrays,
  • availability of all array primitives from SAC as intrinsic functions,
  • user-controlled choice between intrinsic and library-defined versions of all array primitives,
  • multiple return values for user-defined functions,
  • overloading of primitive as well as user-defined functions,
  • code optimization on the SAC level based on the lack of side effects,
  • optimization of nested applications of library-defined array primitives (With-Loop-Folding),
  • rudimentary tracing facilities,
  • rudimentary profiling facilities,
  • non-global, module/class focussed name spaces,
  • interface to several (declarative) languages like C, Fortran, Pascal etc. through the module/ class system,
  • "automatic" import and linkage of SAC modules and non-SAC modules/ classes,
  • separate compilation of SAC modules,
  • support for classes written in SAC itself,
  • global objects(states) and a call by reference mechanism,
  • some very rudimental I/O functions are provided through C-written classes,
  • compilation to non-sequential code for shared memory architectures based on POSIX-threads.

1.3 What is intended for the next release?

Features to be included in the next release:

  • support for empty arrays,
  • support for polymorphic types,
  • better support for type-inference-based partial evaluation,
  • extended I/O libraries including an Interface to X11,
  • compilation to non-sequential code on scalable shared memory architectures and/or distributed memory architectures.

1.4 What are the long term plans?

Features to be included in later releases:

  • higher order functions,
  • generation of dimension independent target code,
  • non uniform data structures like records or nested lists,
  • incorporation of pattern matching.

2 Downloading sac2c

2.1 What kinds of distributions are available?

There is a binary distribution of the pre-alpha sac2c compiler version 0.7 available. Besides the compiler itself it contains the complete sources of the actual standard library.

2.2 What are the basic requirements for running sac2c?

  • sac2c only runs in UNIX environments!
  • At the time being, the usage of sac2c requires at least the GNU make-utility (gmake/make) to be available on your system! Preferably, the GNU C-compiler (gcc) should be available, too.

2.3 For which platforms is a binary distribution available?

The platforms supported right now are
  • Solaris 2.x (Sparc), and
  • Linux (x86).

If it happens to be the case that your particular UNIX platform is none of the above, please contact us by email:

2.4 Where can I download it?

Try the Download Section of the SAC-Hompage.

2.5 Where to find sac2c for local users at the CS department of Kiel University?

The up-to-date version of sac2c for Solaris (Sparc) may be found at /home/sacbase/bin/sac2c. Just set your environment variable $SACBASE to /home/sacbase and have fun.

3 Installing sac2c

3.1 How to install sac2c?

After downloading the binary distribution you should:
  • gunzip the downloaded file,
  • untar it, and
  • run the shell-script "install_sac".
If everything works fine this will
  • ask where to place different parts of the distribution,
  • move the parts accordingly,
  • unpack them using tar and the GNU make-utility (gmake/make), and
  • compile the standard-library using the GNU C-compiler (gcc) and the freshly installed SAC compiler (sac2c)!

3.2 Something went wrong while I was running "install_sac". Am I lost now?

In most cases "install_sac" should work without any problems. However, if something goes wrong, adjusting "install_sac" to your particular system and re-running might help. Don't worry, "install_sac" may well be called repeatedly.

3.3 When compiling the stdlib I get messages like ".<file>.d : No such file or directory"

These are due to an implicit dependency generation mechanism we installed via make, so you can ignore them.

Whenever you compile a sac file <name>.sac using one of our GNU-make templates, it will first generate a dependency file named .<name>.d which contains the dependencies of that sac-file. Therefore, if you compile a sac file the very first time, make will complain that it does not yet exist. However, any successive make will find that file and simply re-make it without any "error-messages".

3.4 When compiling the stdlib I get messages complaining about the absence of a function/symbol "P_tmpdir"

Some LINUX versions tend to require different defines in order to be ANSI / POSIX compliant. Therefore, a few symbols sometimes are not available. However, if your compiler complains about a missing function/symbol "P_tmpdir", you should proceed as follows:
  • Remove "-ansi" from the CCFLAGS definition in $SACBASE/stdlib/Makefiles/Makefile.Config.
  • Try again...
  • If that does not work out, proceed as follows:
    • Look for the needed define in your "/usr/include/stdio.h".
    • Determine the required defines to get the missing prototype.
    • Make the required defines available by adding a definition for "CCFLAGS" in the Makefile of the directory where the error/warning appears. IMPORTANT: make sure, that this definition precedes the import of Makefile_template.stdlib!!

3.5 When compiling the stdlib I get messages complaining about the absence of a prototype for "tempnam"

Some LINUX versions tend to require different defines in order to be ANSI / POSIX compliant. Therefore, a few symbols sometimes are not available. However, if your compiler complains about a missing prototype for "tempnam", you should proceed as follows:
  • Remove "-ansi" from the CCFLAGS definition in $SACBASE/stdlib/Makefiles/Makefile.Config.
  • Try again...
  • If that does not work out, proceed as follows:
    • Look for the needed declaration in your "/usr/include/stdio.h".
    • Determine the required defines to get the missing prototype.
    • Make the required defines available by adding a definition for "CCFLAGS" in the Makefile of the directory where the error/warning appears. IMPORTANT: make sure, that this definition precedes the import of Makefile_template.stdlib!!

3.6 When compiling the stdlib I get messages complaining about the absence of a prototype for "putenv"

Some LINUX versions tend to require different defines in order to be ANSI / POSIX compliant. Therefore, a few symbols sometimes are not available. However, if your compiler complains about a missing prototype for "putenv", you should proceed as follows:
  • Remove "-ansi" from the CCFLAGS definition in $SACBASE/stdlib/Makefiles/Makefile.Config.
  • Try again...
  • If that does not work out, proceed as follows:
    • Look for the needed declaration in your "/usr/include/stdlib.h".
    • Determine the required defines to get the missing prototype.
    • Make the required defines available by adding a definition for "CCFLAGS" in the Makefile of the directory where the error/warning appears. IMPORTANT: make sure, that this definition precedes the import of Makefile_template.stdlib!!

3.7 What can I do if I do not have gcc available?

Proceed as described in [*]. When being asked "Do you want to compile the standard library right now?" answer with "no"! This enables you to patch two files:

First, you have to "tell" sac2c that it should use another C-compiler and what kinds of options are available for that C-compiler. This can be done by adjusting the file "sac2crc" in "$SACBASE/runtime". In most cases, you will only have to adjust the definitions of CC, CCFLAGS, CPP_STDIN, and CPP_FILE. For more details see [*].

Second, you should patch the Makefile that is responsible for the compilation of the standard library. The file to be changed is "Makefile.Config" in "$SACBASE/stdlib/Makefiles". You simply have to adjust the definitions of CC and CCFLAGS!

Finally, you should try to compile the standard library as proposed by install_sac!

3.8 Do I have to adjust the sac2c compiler to my particular system?

If some system call made from sac2c goes wrong, e.g. the sac2c generated C-compiler call, you have to adjust your sac2c configuration file in $SACBASE/runtime/sac2crc. From this, sac2c deduces how to generate the intended system calls.

Anyway, patching the sac2crc file may effect the performance of the generated code.

Most entries of sac2crc are self explanatory, e.g. CC, CCFLAGS, or MKDIR. Not so straightforward are the "OPT_*" entries. They "translate" sac2c options into option settings for the C-compiler defined by CC.

The CPP_STDIN and CPP_FILE entries are needed for running the C preprocessor on a program from stdin or a file, respectively.

STDLIB_DECPATH and STDLIB_LIBPATH are used for implicitly pre-setting the search paths for the declaration and implementation files of modules and classes. Therefore, in most cases, you probably only want to extend them - if you want to modify them at all.

The SYSTEM_LIBPATH is more crucial. It is needed for telling the C compiler where to find include files and libraries used by external modules, such as many modules/classes from the standard library.

Finally, the CACHE* entries are used for giving the sac2c compiler informations about the cache your particular platform is equipped with. This allows for optimizing the code generated from with-loops with respect to their cache behaviour (blocking, alignment, etc.), and for generating code for multi-threaded execution. In version 0.7 this information is only used for the latter.

3.9 How can I use more than just one particular system without changing sac2crc?

The file sac2crc allows you to specify more than one target. For example, the standard sac2crc file that comes with the distribution besides the default target defines many other targets, e.g. a target "par" or a target "suncc". As you can see for "suncc" these can even inherit settings from other targets. In this case, all unspecified settings are taken from the "ancestors".

When compiling for another target machine you simply call sac2c with the option "-target <name>".

3.10 Do I always have to modify the installation wide sac2crc file?

No, sac2c will also look for a file called .sac2crc in your home directory. Here, you may define your own private targets including a private default target. Settings in your private configuration file always override those from the public configuration file in $SACBASE/runtime.

4 Running sac2c

4.1 Getting started

4.1.1 Do I need to set up some environment variables?

The only environment variable that is mandatory for running sac2c is $SACBASE. It should point to the directory, where the standard library and the sac2c runtime library are placed (cf. install_sac).

Though it is not necessary to specify any other environment variables you may find it useful to set up some other environment variables used by sac2c:

  • $SAC_PATH helps the compiler to find the given source file
  • $SAC_DEC_PATH helps the compiler to find module/class declaration files
  • $SAC_LIBRARY_PATH helps the compiler to find the respective implementation (.o) files

4.1.2 When calling sac2c, I always get an error message

4.2 Running the first examples

4.2.1 Where can I find the Reference Manual?

The bad news is: Sorry, but there is none available yet.

The good news is: Most syntax you will probably already know: it's simply C! A description of the complete syntax of SAC, as well as some papers that describe the SAC specific features to some more detail can be found on the SAC homepage in the section on Research and in the other Documentation.

For any further questions, don't hesitate to ask us directly by sending an email to

4.2.2 How can I find out about the compiler options?

Simply call "sac2c -h". This will list you all sac2c options available.

4.2.3 What can I do if the compiler breaks (with a SEGFAULT)?

First, you should send an email to It should contain:
  • the program you were trying to compile
  • the compiler options you used
  • the system you are working on, and
  • the build - notice you get when calling sac2c -h, e.g., "BUILD: Mon Nov 2 17:51:46 MET 1998 by sacbase on blitz".
After sending us an email, you could try to compile your program with some optimizations turned off, because those tend to be a bit "shaky" sometimes. So calling "sac2c -noopt ..." often helps. If it does so, you might try to turn off only some optimization, e.g., "sac2c -noLIR -noWLF -noINL ...". Although this might have a very bad influence on your runtimes, it at least may give you the opportunity to work on...

4.2.4 What can I do if the compiled program breaks (with a SEGFAULT)?

In most cases this is due to an indexing error! To verify that you may call "sac2c -dcheck_boundary ..." which will include some runtime code for checking index validity.

Another problem might be the lack of enough memory in your system. To verify this problem use "sac2c -dcheck_malloc ..." it will make sure that all memory requests will either be satisfied by the operating system or lead to an appropriate error message.

If none of these apply, proceed as described in [*].

4.2.5 Is there any makefile support for compiling SAC programs?

Yes! A set of "generic" Makefiles is provided in $(SACBASE)/stdlib/Makefiles/Makefile.*. In most situations the usage of one of the template Makefiles: $(SACBASE)/stdlib/Makefiles/Makefile_template.* will help. For some example usages see the Makefiles that comes with the demo-files, or the Makefiles within the stdlib (e.g. $(SACBASE)/stdlib/Makefile).

4.3 Benchmarking

4.3.1 What can I do if the programs tend to be slow?

There are several things you could do:
  • First, you should make sure, that your C-compiler runs on utmost optimization level. Normally, starting sac2c using "-O3" should effect this. However, if the configuration file "sac2crc" is not set up correctly (cf. [*]) this may not work properly. To check what is going on, call "sac2c -dcccall ...". This will generate a file ".sac2c" in your actual directory which contains the C-compiler call.
  • Second, inlining for some optimizations is very important since most of the optimizations (among them With-Loop-Folding!) are only "intra-functional", i.e., their scope is limited to a single function body! ATTENTION: in contrast to other languages, e.g. SISAL, functions are NOT inlined implicitly. Instead, each function that is meant to be inlined has to be annotated by preceding it's definition with the keyword "inline"!
  • Some optimizations are configurable. For example, all arrays with fewer than a pre-specified number of elements are substituted by scalar variables ("array elimination"). This number can be changed by using "sac2c -minarray <your number> ...". For more details on these configuration options call "sac2c -h".
  • To get utmost performance you should make sure that your sac2c configuration file sac2crc is adjusted to your target hardware. For detailed information on how to customize the sac2crc-file see [*].

4.3.2 How can I find out why a particular program is slow?

Basically, there are two ways of finding out what is going on:
  • You can inspect your program after it has been optimized by running the compiler with "sac2c -bo ...", or "sac2c -bs ..." . All further optimizations rely on your C compiler.
  • You can use the profiling facility "sac2c -profile [afilw] ..." which will allow you to inspect where your runtime is spend. For more details see "sac2c -h".

4.3.3 Are the primitive array operations, e.g. + on arrays, built in?

Yes! You may even choose between a built-in (intrinsic) version and a library-defined one. If you call sac2c without any further option, none of the built-in primitives will be available. So if you want to use them you have to either import them by using "import Array:all;" or use the sac2c option "-intrinsic [a+-*/ptdcr]" which will make the built-in versions available.

Depending on the program context, both decisions may have advantages. Since the library version is defined by With-Loops With-Loop-Folding may apply and thus improve the runtime by avoiding intermediate array structures. In situations where With-Loop-Folding does not apply, on avarage the intrinsic versions are advantageous since their code is optimized to their particular purpose.

4.3.4 Is there any makefile support for benchmarking?

Yes! A specific makefile template for benchmarking is provided in $(SACBASE)/stdlib/Makefiles/Makefile_template.bench! For more info on using the makefile template see [*].

4.4 Tracing Executions

4.4.1 When tracing the memory usage I sometimes get strange numbers! Where do they come from?

Tracing operates on a local scope only! Whenever a library function is called, all memory operations that happen while that function is executed, is traced iff that module/class was compiled with tracing turned on!! If you want to check for a potential memory leak, better use the built-in heap diagnostics ("-check h").

5 Generating multi threaded code with sac2c

5.1 Do I have to write special code for multi threaded execution?

No, not at all. The sac2c compiler will do everything required for you.

5.2 How can I tell sac2c to generate multi threaded code?

There are two alternative ways: either you specify the exact number of threads to be used right when compiling your program or you just give an upper bound and postpone the specification of the exact number until actually running your application. These are the corresponding compiler switches for sac2c:
  • -mtstatic <n>
    sac2c compiles your program for execution with <n> threads.
  • -mtdynamic <n>
    sac2c compiles your program for execution with at most <n> threads.

5.3 How can I dynamically specify the number of threads?

If you have compiled your SAC program with the -mtdynamic option, you must specify the actual number of threads to be used when running the executable. This is done by starting it with the additional option -mt <n>. If you fail to do so, your executable will stop immediately and display an error message.

5.4 Do I have to link my program with a special thread library?

As the implementation of multi-threaded execution in SAC relies on POSIX threads, your program has to be linked with the corresponding library. However, don't worry, sac2c will do everything for you provided that it is correctly customized, i.e. the configuration entry CCMTLINK is set correctly for your target system (see question [*]).

5.5 Can I run my multi threaded program sequentially?

Provided that it is compiled with the -mtdynamic <n> option, you can simply run your program with -mt 1. Just note that you get some administrative overhead due to multi-threading although you definitely won't benefit from it. However, when evaluating benchmarks we discovered that this overhead is usually neglectible.

5.6 Can I run multi threaded programs on a uniprocessor?

Yes, you can. The mapping between threads and processors is rather loosely and completely managed by the underlying operating system. So, you may well test your multi-threaded application right on your uniprocessor desktop machine. However, wallclock execution times are likely to grow enormously with the number of threads. This is caused by very frequent context switches in the cpu.

5.7 Can I run a program on a multiprocessor with more threads than processors?

Yes, of course you can. The problem is just the same as with running a multi-threaded program on a uniprocessor. As soon as the number of threads used exceeds the number of processors actually available, frequent context switches between competing threads will have a very negative impact on the runtime performance of your program.

5.8 Why drops the performance although I use less threads than I do have processors?

Well, do you have exclusive access to the machine used? If not, check for other processes running in the system. These virtually ``steal'' processors from your system. So, at any given time, the number of processors actually available to you might be less than the number of processors physically existing. Usually, you achieve the utmost performance if the number of threads you use plus the number of other active processes in your system does not exceed the number of existing processors.

6 Interfacing with C

6.1 How can I write part of my application in C?

The SAC module system anables you to do so by writing so-called external modules. Similar to ``pure'' SAC modules their interface is defined by a module declaration file xyz.dec, but the implementation is provided by a C implemented archive file xyz.a. The additional key word external in the module declaration tells the SAC compiler to expect xyz.a rather than the SAC library xyz.lib.

6.2 Is there any documentation about interfacing SAC to C?

The only comprehensive source of information about this topic is Clemens' Diploma thesis which unfortunately is available in German only (see SAC homepage). Apart from this, some aspects are addressed in these FAQs.

Another approach is to write an external module declaration, to write a rudimentary SAC program which imports this module and uses its functions, and compile the whole with the sac2c option '-c' which stops after creating the respective C file. Now you can see what your function declarations have been compiled to and how the use of pragmas effects the compilation. Don't be afraid; this sounds nastier than it actually turns out to be.

6.3 How can I implement an implicit type in C?

Any implicit type imported from an external module is compiled to type void* by the SAC compiler. So, any pointer type is just fine. However, if you use an implicit type in an external module, sac2c takes care of the meory management of the respective data structures. Therefore, sac2c requires means to remove and to copy such data objects. For this purpose, it expects the external module implicitly to provide two additional functions not mentioned in the module declaration:
  • impltype copy_impltype( impltype)
  • void free_impltype( impltype)
Sometimes, it is more convenient to name these functions differently from the default, e.g. to use just the standard C function free(). For this case, alternative function names (but not signatures) may be specified using the pragmas copyfun and freefun.

6.4 How can I implement an explicit type in C?

This, of course, is limited to types available in SAC, i.e., int, float, double, and char are simply implemented by their respective C counterparts; bool in SAC is implemented by the type int in C. SAC Arrays are implemented as pointers to the respective base type in C.

6.5 How can I implement a function in C?

First, you have to introduce all types needed in the signature of the function, possibly by additional implicit types. Then, you just need to make sure that the function actually behaves as declared in the signature, i.e.
  • the parameters are read, but not destructively modified as would be possible in the case of any pointer type;
  • all result values are actually created, there is no aliasing between return values or return values and arguments;
  • the result values are exclusively determined by the arguments;
  • the function is free of side-effects.
To put it differently: the function must be a function in the sense of functional programming rather than a function in the sense of C or other imperative languages.

6.6 What about the pragma linkname?

Sometimes it is quite useful to use a function name within SAC which is different from the name used in the resulting C code, e.g. you may want to use overloading within SAC also for C-implemented functions or your C function has a given name that is not allowed as identifier within SAC. For these purposes, the linksign pragma allows you to specifify a completely different function name to be used for linking. This feature even enables you to overload operators like + or == by functions implemented in C.

6.7 How to implement functions with several return values in C?

Unlike C, SAC supports functions with any number of return values. These may easily be implemented by a C function from an external module. The first return value becomes the only return value of the C function; all remaining return values are added at the beginning of the function's parameter list, each being referenced once more, e.g. the SAC function

int, int[], bool, char fun( float a, double[] b)

may be implemented by the C function

int fun( int **, int *, char *, float a, double *b).

However, this might not always suit your needs, particularly if the signature of your C function is already given. In such cases, the pragma linksign (see [*]) allows you to adjust the function's signature to your specific needs.

6.8 What about the pragma refcounting?

Provided that your external functions are implemented w.r.t. to the limitations explained in [*], SAC does all the memory management for you. However, sometimes it is useful to do the memory management within an external function definition, e.g. you may wish to reuse a given argument as return value if you know that there are no further references to this data object outside your function. For this case, the pragma refcounting allows you to specify those return values and arguments for which you want to do the reference counting and memory management on your own. These parameters are just specified by their number when reading the function declaration from left to right starting with 0 for the first return value and at least with 1 for the first argument.

Please be carefully: once you do the memory management on your own, you have to do it exactly in the way that sac2c expects it to be. This, obviously, requires some knowledge about sac2c internals!

However, to get an impression of how this stuff works, have a look into the C implementation of the SAC standard module List which may be found in your installation in the directory $SACBASE/stdlib/modules/structures/src/List. Please note that for each parameter for which your function does the memory management on its own, an additional parameter of type int* is inserted which is a pointer to the respective reference counter.

6.9 What is the pragma linksign good for?

The pragma linksign allows you to use a signature in the C implementation of a function that is completely different from that used within SAC. First, you may permute the return values and arguments of the function. For each return value and each formal parameter in the function declaration you must specify the respective position in the C signature. Here, the same enumeration scheme applies as used for the pragma refcounting.

However, beyond simple permutations you may also map one return value to the same position as one formal parameter of the same type. In this way, C functions that destructively update one of their arguments may be used from SAC in a way that does not conflict with the functional semantics of SAC. If the respective type already is a pointer type, this type is used, otherwise the scalar type is referenced once in order to allow the update. Be careful, if you combine this feature with doing the memory management on your own (see [*])!

For example:

int, float[] fun( int a, double[] b)
#pragma linksign [2,0,2,1]

is transformed into

float *fun( double *b, int *a).

next_inactive up previous
Up: SAC-Homepage
Stephan Herhut 2007-08-21