Hello
I've just discovered that tcc¹ is able to compile the C code generated by Gambit. In simple cases the compiled object files work just flawlessly (albeit ~3 times slower than when compiled with gcc in a fixnum-loop microbenchmark, but that's ok). When I compile one of my bigger modules (which takes 3 seconds for compilation from Scheme to C and 17 seconds to compile from C to binary with gcc 4.1.2, and only 1 second to compile from C to binary with tcc 0.9.23), it's doing wrong calculations (I'm doing signal processing, with tcc it just outputs zeroes all the time).
The way I've used tcc in the above tests was by just linking tcc into the PATH as gcc (mkdir ~/bin; ln -s /usr/bin/tcc ~/bin/gcc; PATH="~/bin:$PATH"; start gsc interactively and use compile-file (through chjmodule) as usual). Should I take a different approach? Or should I start debugging problems / send bug reports with code when compiled with tcc?
Having 5 times faster compile times would help development in those cases where using the interpreter isn't possible (because it is too slow or because the modules are including FFI code), albeit it's not a high priority. (Alternatively I might possibly speed up gcc by not using single-host and no -O flag. How can I achieve those settings from inside gsc (when using |compile-file|), btw?)
Christian.
Afficher les réponses par date
On 27-Jul-07, at 5:28 PM, Christian Jaeger wrote:
Hello
I've just discovered that tcc¹ is able to compile the C code generated by Gambit.
Great! I have toyed with TCC (not in the context of Gambit) and I think it is a neat tiny and fast C compiler.
In simple cases the compiled object files work just flawlessly (albeit ~3 times slower than when compiled with gcc in a fixnum-loop microbenchmark, but that's ok). When I compile one of my bigger modules (which takes 3 seconds for compilation from Scheme to C and 17 seconds to compile from C to binary with gcc 4.1.2, and only 1 second to compile from C to binary with tcc 0.9.23), it's doing wrong calculations (I'm doing signal processing, with tcc it just outputs zeroes all the time).
Are you sure TCC implements floating point?
The way I've used tcc in the above tests was by just linking tcc into the PATH as gcc (mkdir ~/bin; ln -s /usr/bin/tcc ~/bin/gcc; PATH="~/bin:$PATH";
Another way would be to tweak the file ~~/bin/gsc-cc-o which is called by gsc to compile the generated source code to the .o1 file.
start gsc interactively and use compile-file (through chjmodule) as usual). Should I take a different approach? Or should I start debugging problems / send bug reports with code when compiled with tcc?
Having 5 times faster compile times would help development in those cases where using the interpreter isn't possible (because it is too slow or because the modules are including FFI code), albeit it's not a high priority. (Alternatively I might possibly speed up gcc by not using single-host and no -O flag. How can I achieve those settings from inside gsc (when using |compile-file|), btw?)
You have to change ~~/bin/gsc-cc-o so that no options are passed to gcc, and then you pass the C compiler options you want as the third option of compile-file:
(compile-file "foo.scm" '() "-O0")
The arguments of compile-file are:
(compile-file <filename> [<options> [<cc-options> [<ld-options>]]])
I'll add this to the documentation...
Marc
Marc Feeley wrote:
Are you sure TCC implements floating point?
Well, this code works:
(define (functor:vector-* length make ref vset!) (lambda (v fact) (let* ((len (length v)) (out (make len))) (let lp ((i 0)) (if (< i len) (begin (let () (declare (flonum) (not safe)) (vset! out i (* fact (ref v i)))) (lp (inc i))))) out)))
(define f64vector-* (functor:vector-* f64vector-length make-f64vector f64vector-ref f64vector-set!))
(define f32vector-* (functor:vector-* f32vector-length make-f32vector f32vector-ref f32vector-set!))
(TEST ;;(<- syntax from unreleased cj-test module)
(f64vector-* '#f64(1.2 3.2 0.4) 2.3123123124213153251253)
#f64(2.7747747749055782 7.3993993997482095 .9249249249685262)
(f32vector-* '#f32(1.2 3.2 0.4) 2.3123123124213153251253)
#f32(2.7747747898101807 7.399399280548096 .924924910068512) )
There is one "mul" opcode in the disassembly:
... 2868: dd d9 fstp %st(1) 286a: dd 45 b8 fldl 0xffffffb8(%ebp) 286d: dc 4d b0 fmull 0xffffffb0(%ebp) 2870: dd 55 a8 fstl 0xffffffa8(%ebp) 2873: dd d9 fstp %st(1) 2875: 8b 45 d4 mov 0xffffffd4(%ebp),%eax 2878: 83 c0 10 add $0x10,%eax ...
I'm surprised that there's only one occurrence of an opcode containing "mul" in it's name, when both 32 and 64 bit operations are being performed. But I don't really know x86 assembly.
I'll look into my problematic code more closely, it may actually be the included foreign C code (written by me and others) which is at fault.
Christian.
I started composing this before Marc replied, but still it may be of use.
The current instructions in the documentation for how to build a standalone executable are wrong; here are some new instructions for that and some comments on how to speed up compiles of scheme code (at the expense of some performance). These notes aren't specifically directed at you, Christian, but I wrote them a week or so ago for another purpose, and they seem vaguely relevant to your request.
If there are several scheme and c files, follow the instructions on how to compile them from scheme to c and then use gsc -link to get the *_.c file. Here we assume there is only one scheme file called all.scm. Pretty much the easiest way to build a stand-alone executable is
[brad:~/Desktop/gambit-anagram] lucier% gsc -link all.scm [brad:~/Desktop/gambit-anagram] lucier% gcc -I/usr/local/Gambit-C/ current/include/ -D___SINGLE_HOST -fstrict-aliasing -fwrapv -O1 -c all.c [brad:~/Desktop/gambit-anagram] lucier% gcc -I/usr/local/Gambit-C/ current/include/ -D___SINGLE_HOST -fstrict-aliasing -fwrapv -O1 -c all_.c [brad:~/Desktop/gambit-anagram] lucier% gcc -o all all.o all_.o -L/ usr/local/Gambit-C/current/lib -lgambc -ldl -lm
Here I assume that gambit was installed in the usual place /usr/local/ Gambit-C/current; if this was changed using --prefix= in the configure command then change these. You need -fstrict-aliasing and - fwrapv for correctness when compiling with gcc. -O1 is a good default compilation option. If you want to give up a bit more speed for possibly much faster compilation, then add the option - D___OPTIMIZE_SPACE. Other ways to make the compilation go faster is to omit the -O1 and the -D___SINGLE_HOST, but I don't recommend this.
The library options "-lgambc -ldl -lm" change from system to system; sometimes they include "-lutil" and other libraries.
MARC: THERE SHOULD BE COMMANDS CALLED SOMETHING LIKE "gambit- compile" AND "gambit-link" THAT (a) COMPILE .c FILES AND (b) LINKS THEM TOGETHER WITH THE CORRECT OPTIONS AND LIBRARIES.
MARC: THERE SHOULD BE SOMETHING LIKE
./configure --simple-gcc-options
THAT JUST HAS THE FEW OPTIONS GIVEN ABOVE FOR GAMBIT. Not everyone wants to spend the compile time, and several times now there have been cryptic comments on this mail list about how to get rid of the default gcc options, even without --enable-gcc-opts.
If you do
% gsc file.scm
to make a dynamically loadable file, then it's compiled using /usr/ local/Gambit-C/current/gsc-cc-o (in general, it's `which gsc-cc-o`). As Marc said, you can edit that file (copying the original somewhere else beforehand if you like) before compiling. On my MacOS X machine, it's
[brad:Arrays/srfi3/Binf-2] lucier% cat `which gsc-cc-o` #! /bin/sh GSC_CC_O_ARG1=$1 shift GSC_CC_O_ARG2=$1 shift GSC_CC_O_ARG3=$1 shift gcc -mcpu=7450 -D___OPTIMIZE_SPACE -no-cpp-precomp -Wall -W -Wno- unused -O1 -fno-math-errno -fschedule-insns2 -fno-trapping-math - fno-strict-aliasing -fwrapv -fexpensive-optimizations -fforce-addr - fpeephole2 -falign-jumps -falign-functions -fno-function-cse -ftree- copyrename -ftree-fre -ftree-dce -fregmove -fgcse-las -freorder- functions -fcaller-saves -fno-if-conversion2 -foptimize-sibling- calls -fcse-skip-blocks -funit-at-a-time -finline-functions -fomit- frame-pointer -fPIC -fno-common -bundle -flat_namespace -undefined suppress -I${GSC_CC_O_ARG1}include -D___DYNAMIC -D___SINGLE_HOST -o ${GSC_CC_O_ARG2} $* ${GSC_CC_O_ARG3}
As you can see, I configured Gambit with
env CC='gcc -mcpu=7450 -D___OPTIMIZE_SPACE' ./configure --enable- single-host
The "-fwhatever" optimization options to gcc can be omitted except for the two I listed above. So you can reduce the set of options to
gcc -no-cpp-precomp -fno-strict-aliasing -fwrapv -fPIC -fno-common - bundle -flat_namespace -undefined suppress -I${GSC_CC_O_ARG1} include -D___DYNAMIC -o ${GSC_CC_O_ARG2} $* ${GSC_CC_O_ARG3}
You need another "-f" option for dynamically loaded libraries, "- fPIC". You also need "-D___DYNAMIC" for dynamically loaded libraries.
I don't know what the other options are, but I know they aren't optimization options, and they change from system to system. After you strip out the options you don't want then you can add back in what you may want, like
gcc -O1 -D___OPTIMIZE_SPACE -no-cpp-precomp -fno-strict-aliasing - fwrapv -fPIC -fno-common -bundle -flat_namespace -undefined suppress -I${GSC_CC_O_ARG1}include -D___DYNAMIC -o ${GSC_CC_O_ARG2} $* ${GSC_CC_O_ARG3}
which offers about the best trade-off for execution speed and compile time for slow machines (or rapid development).
Brad