qbecc command - modernc.org/qbecc - Go Packages

9 min read Original article ↗

Command qbecc is a C compiler based on QBE.

Note: qbecc uses the host C compiler to find system include files and for linking executables.

Performance

	goos: linux
	goarch: amd64
	pkg: modernc.org/qbecc/lib
	cpu: AMD Ryzen 9 3900X 12-Core Processor
	HostCC: gcc (Debian 12.2.0-14+deb12u1) 12.2.0
	ccgo: v4.30.1

                                 arg   HostCC_O2   HostCC_O1       QBECC   HostCC_O0        CCGO      GOABI0
 -----------------------------------------------------------------------------------------------------------
                       cert:aes.c-24       1.000       0.882       2.085       2.210       1.174       2.240
                 cert:almabench.c-24       1.000       1.004       1.135       1.274       2.572       3.250
               cert:binarytrees.c-24       1.000       1.079       1.192       1.347       2.375       2.836
                    cert:bisect.c-24       1.000       1.027       1.166       1.651       1.274       1.290
                     cert:chomp.c-24       1.000       1.046       1.085       1.432       1.032       1.414
                  cert:fannkuch.c-24       1.000       1.086       1.125       2.598       1.353       1.135
                       cert:fft.c-24       1.000       0.840       1.250       0.567       1.030       1.495
                     cert:fftsp.c-24       1.000       0.954       1.069       1.066       1.130       1.652
                      cert:fftw.c-24       1.000       0.947       1.107       3.061       1.223       1.152
                       cert:fib.c-24       1.000       2.372       3.449       4.188       3.128       4.168
                    cert:integr.c-24       1.000       3.620       3.635       4.118       4.281       4.036
               cert:knucleotide.c-24       1.000       1.051       1.109       1.413       1.502       1.571
                     cert:lists.c-24       1.000       1.052       1.022       2.469       0.986       0.987
                cert:mandelbrot.c-24       1.000       1.031       1.057       2.070       1.235       1.073
                     cert:nbody.c-24       1.000       0.859       0.884       1.827       2.020       2.369
                    cert:nsieve.c-24       1.000       0.778       1.009       1.765       0.798       1.416
                cert:nsievebits.c-24       1.000       1.025       1.333       3.118       1.225       1.388
                    cert:perlin.c-24       1.000       1.159       1.881       2.934       3.566       5.907
                     cert:qsort.c-24       1.000       1.030       1.330       1.687       1.431       1.901
                      cert:sha1.c-24       1.000       0.681       0.898       1.662       0.972       1.103
                      cert:sha3.c-24       1.000       1.065      10.971       5.672       2.454      11.487
                 cert:siphash24.c-24       1.000       1.338       2.399       3.832       1.575       2.451
                  cert:spectral.c-24       1.000       2.141       4.485       3.128       2.160       4.578
                     cert:vmach.c-24       1.000       1.100       1.387       1.530       1.166       1.628
                 qjs:array_for.js-24       1.000       1.592       8.018       3.477       5.819       9.941
              qjs:array_for_in.js-24       1.000       1.418       3.451       2.989       5.043       7.655
              qjs:array_for_of.js-24       1.000       1.094       4.591       2.626       5.978       9.473
    qjs:array_hole_length_decr.js-24       1.000       1.249       3.905       2.829       4.931       8.229
         qjs:array_length_decr.js-24       1.000       1.307       4.568       3.099       6.220      10.095
                 qjs:array_pop.js-24       1.000       1.067       5.510       2.926       6.973       9.854
         qjs:array_prop_create.js-24       1.000       1.428       5.595       3.094       5.138       9.177
                qjs:array_push.js-24       1.000       1.045       5.219       2.533       5.835       8.183
                qjs:array_read.js-24       1.000       1.121       5.638       3.247       6.071       8.038
               qjs:array_slice.js-24       1.000       1.073       3.660       3.219       6.645       9.287
               qjs:array_write.js-24       1.000       1.348       5.876       4.415       5.500      10.061
                  qjs:date_now.js-24       1.000       1.042       6.136       2.294      13.442      15.454
                qjs:date_parse.js-24       1.000       1.127       2.326       1.913       3.426       4.603
             qjs:empty_do_loop.js-24       1.000       1.768      10.820       4.233       7.776      12.752
           qjs:empty_down_loop.js-24       1.000       1.384       8.034       2.796       4.855       8.728
          qjs:empty_down_loop2.js-24       1.000       1.463       5.592       3.116       6.165      11.935
                qjs:empty_loop.js-24       1.000       1.340       7.299       2.770       3.912       7.914
               qjs:factorial10.js-24       1.000       1.343       9.140       2.998       8.059      11.261
               qjs:float_arith.js-24       1.000       1.670       6.977       2.894       4.721       7.841
       qjs:float_toExponential.js-24       1.000       1.200       3.493       2.494       3.445       5.895
             qjs:float_toFixed.js-24       1.000       1.267       3.984       2.685       3.683       6.448
         qjs:float_toPrecision.js-24       1.000       1.192       3.504       2.529       3.462       5.823
            qjs:float_toString.js-24       1.000       1.148       2.533       2.198       2.382       4.005
           qjs:float_to_string.js-24       1.000       1.106       2.128       2.113       2.043       3.591
                 qjs:func_call.js-24       1.000       1.265      10.144       2.776       8.242      12.422
         qjs:func_closure_call.js-24       1.000       1.164       9.566       2.605       8.004      11.328
           qjs:global_destruct.js-24       1.000       1.349       3.914       3.583       5.853       8.804
    qjs:global_destruct_strict.js-24       1.000       1.352       3.901       3.491       5.888       8.823
          qjs:global_func_call.js-24       1.000       1.391       9.117       3.111       8.316      11.733
               qjs:global_read.js-24       1.000       1.780       7.338       5.170       8.606      12.701
              qjs:global_write.js-24       1.000       1.225       4.170       3.037       5.154       8.240
       qjs:global_write_strict.js-24       1.000       1.244       4.148       3.152       5.252       8.397
                 qjs:int_arith.js-24       1.000       1.785       9.957       3.607       5.921      10.668
              qjs:int_toString.js-24       1.000       1.436       4.627       2.431       5.228       8.268
             qjs:int_to_string.js-24       1.000       1.428       5.016       2.565       5.279       8.551
            qjs:int_to_string2.js-24       1.000       1.267       2.576       2.017       3.407       6.086
            qjs:local_destruct.js-24       1.000       1.229       2.652       2.697       3.563       5.810
                qjs:map_delete.js-24       1.000       1.117       4.293       2.524       5.182       7.328
            qjs:map_set_bigint.js-24       1.000       1.120       6.081       3.058       6.917      10.191
               qjs:map_set_int.js-24       1.000       1.193       5.618       3.035       5.956       9.499
            qjs:map_set_string.js-24       1.000       1.198       4.506       2.632       5.159       7.919
                  qjs:math_min.js-24       1.000       1.114       8.219       3.328       7.750      11.327
                qjs:prop_clone.js-24       1.000       1.199       2.637       2.684       3.412       5.698
               qjs:prop_create.js-24       1.000       1.306       3.236       2.905       3.338       5.691
               qjs:prop_delete.js-24       1.000       1.227       2.918       2.671       3.603       6.160
                 qjs:prop_read.js-24       1.000       1.714       7.461       4.695       7.131      11.011
               qjs:prop_update.js-24       1.000       1.313       4.835       3.473       6.423      10.008
                qjs:prop_write.js-24       1.000       0.869       4.259       3.505       5.801       7.708
              qjs:regexp_ascii.js-24       1.000       1.155       2.506       2.303       2.973       4.645
              qjs:regexp_utf16.js-24       1.000       1.158       2.544       2.375       3.100       4.839
             qjs:string_build1.js-24       1.000       1.420       3.749       2.178       3.258       6.093
            qjs:string_build1x.js-24       1.000       1.383       3.625       2.178       3.252       5.939
             qjs:string_build2.js-24       1.000       1.353       3.448       2.368       4.473       7.630
            qjs:string_build2c.js-24       1.000       1.420       3.642       2.159       2.804       5.380
             qjs:string_build3.js-24       1.000       1.214       2.997       2.190       4.271       6.885
             qjs:string_build4.js-24       1.000       1.348       3.475       2.259       4.447       7.776
       qjs:string_build_large1.js-24       1.000       1.070       2.326       1.895       2.928       5.129
       qjs:string_build_large2.js-24       1.000       1.152       2.570       2.050       3.922       6.108
           qjs:string_to_float.js-24       1.000       1.053       2.878       2.438       2.817       4.521
             qjs:string_to_int.js-24       1.000       1.154       2.975       2.136       3.130       5.466
          qjs:typed_array_read.js-24       1.000       0.990       4.924       2.666       5.663       7.011
         qjs:typed_array_write.js-24       1.000       1.315       4.842       3.080       4.842       8.038
           qjs:weak_map_delete.js-24       1.000       1.184       3.466       2.573       4.656       6.428
              qjs:weak_map_set.js-24       1.000       1.118       4.420       2.917       5.828       8.421
                           sqlite-24       1.000       1.138       1.828       1.817       3.110       4.287
 -----------------------------------------------------------------------------------------------------------
                             geomean       1.000       1.220       3.331       2.561       3.571       5.406
                                       HostCC_O2   HostCC_O1       QBECC   HostCC_O0        CCGO      GOABI0

Hardening

  • There are 1000+ individual C test cases in use.
  • Fuzzing by CSmith.
  • Memory correctness check by Valgrind.

C Standards Support

Supports most features of C99 and some from later standards.

Mainstream C Compiler Compatibility

  • C object files follow the standard target ABI and should link with object files produced by other compilers.
  • Intrinsics are not supported and are not planned.
  • Only some C language extensions are supported, but this can be extended in some cases.
  • Only some built-ins are supported, but this can be extended easily in most cases.
  • Producing position-independent code/shared libraries is not supported, but it is planned, if feasible.
  • Supporting inline assembler in C files is not planned. However, object files produced by qbecc can be linked with separately assembled `.s` files.

Supported C Targets

linux/amd64      Passes all tests

Supported Go ABI0 Targets

linux/amd64      Passes all tests

Go ABI0 targets can currently link only to libc, which is provided by modernc.org/libc. The generated assembler code is CGo-free and correctly handles Go's movable stacks. Support for linking to other Go packages produced by qbecc is planned, but work on this linker feature has not yet started.

Change Log

2025-10-03: Dropped linux/arm64 support, see issue #5.

CC Compatible Flags

These flags are recognized. Some are passed to the host C compiler for configuration, some are used by qbecc, and many others are ignored. Passing a flag not listed in this documentation results in an error.

-D name[=value]: Define macro

Defines `name` as a macro. `-D name` is equivalent to `#define name 1`, and `-D name=value` is equivalent to `#define name value`.

-E: Preprocess only

Stop after the preprocessing stage; do not run the main compilation stage.

-I <dir>: Include directory

Add `dir` to the list of directories to be searched for header files.

-L <dir>: Library directory

Add `dir` to the list of directories to be searched for libraries with `-l`.

-MF <file>: Preprocessor directive

Writes dependency rules to a file, but excludes system headers. Ignored.

-MMD: Preprocessor directive

Generates dependency rules but excludes system headers. Ignored.

-O<level>: Optimization

Selects the optimization level.

-S: Keep assembler code

Stop after compilation; do not assemble.

-U name: Undefine macro

Cancels any previous definition of `name`.

-W*: Configure warnings

Flags starting with `-W`, used to configure warnings, are recognized but ignored.

-ansi: Use ANSI C

Select the ANSI C language standard.

Compile or assemble the source files but do not link. Ignored with `--goabi0`.

-fno-asm: Disable asm keyword

Do not recognize `asm`, `inline`, or `typeof` as keywords.

-f*: Other compiler flags

All other flags starting with `-f` are ignored.

-g: Debugging info

Produce debugging information.

-idirafter <dir>: Include directory

Add `dir` to the end of the system header search path.

-iquote <dir>: Quote include directory

Add `dir` to the search path for `#include "file.h"`.

-isystem <dir>: System include directory

Add `dir` to the start of the system header search path.

Link with the specified library.

-o <file>: Output file name

Place the primary output in `<file>`. If `<file>` has a `.s` or `.go` extension, `--goabi0` is implied.

-pedantic: ISO C warnings

Issue all warnings demanded by strict ISO C. Ignored.

-rdynamic: Linker flag

Pass the `-export-dynamic` flag to the ELF linker. Ignored.

-shared: Produce a shared object

Note: Shared objects created by qbecc are not standard shared libraries. They are used as an intermediate step for producing Go ABI0 assembler and require that all inputs were compiled with `--keep-ssa`.

-std=<value>: Select C standard

Select the C standard to use (e.g., `-std=c99`).

-w: Disable warnings

Inhibit all warning messages.

Qbecc Specific Flags

These flags are used only by qbecc.

--abi0wrap <importPath>: Generate ABI0 wrappers

This flag invokes a helper tool for interoperability with ccgo/v4 generated code. When this flag is present, all other flags and arguments are ignored. The tool generates `abi0_goos_goarch.go` and `.s` files in the current directory. The assembler wrappers are created for functions in the Go package `<importPath>` that have the ccgo/v4 signature:

func X.*(tls *libc.TLS, ...).

This tool currently supports wrapping the ccgo-produced modernc.org/libc.

--cc=<string>: Select host C compiler

Specify the C compiler to use for system header discovery and linking.

--dump-ssa: Output SSA

Output SSA to stderr.

--extended-errors: Turn on multi-line errors

Without this flag, only the first line of an error is reported.

--goabi0: Target Go assembler

Produce Go ABI0 assembler code (`.s` file) and the corresponding Go declarations (`.go` file). Passing `-o foo.s` or `-o foo.go` will produce both `foo.s` and `foo.go`.

Note: When using `--goabi0`, the input files must be ELF object files previously created by qbecc with the `--keep-ssa` flag, not C source files.

--goarch <string>: Target GOARCH

Select the Go target architecture for cross-compiling. Planned.

--goos <string>: Target GOOS

Select the Go target OS for cross-compiling. Planned.

--keep-ssa: Store the IR in output files

Preserve the intermediate representation (IR) in object/executable files so they can be later used with `--goabi0`.

--package-name <string>: Set Go package name

Set the Go package name when linking with `--goabi0`. Defaults to "main".

The string is injected into the SSA verbatim.

--target <string>: QBE target

The argument must be a valid QBE target for cross-compiling (e.g., `amd64_sysv`). Planned. Defaults to the appropriate target for the current OS/architecture.

--unsigned-enums: GCC compatible enum signedness

The signedness of enum types is implementation-defined. This flag helps compile non-portable C code that depends on GCC-specific enum rules.

QBECCFLAGS

This environment variable passes a comma-separated list of options. For example:

QBECCFLAGS=--keep-ssa qbecc main.c

is equivalent to:

qbecc main.c --keep-ssa

Example: Single C File Command

$ pwd
/home/jnml/src/modernc.org/qbecc
$ go install
$ cd _examples/mandelbrot/
/home/jnml/src/modernc.org/qbecc/_examples/mandelbrot
$ ls
main.c
$ gcc main.c && ./a.out
--- ASCII Mandelbrot Set ---
<...output...>
$ rm a.out ; qbecc --keep-ssa main.c && ./a.out
<...same output...>
$ qbecc -o main.go a.out && go run .
<...same output...>

Example: Multi-File C Command

$ pwd
/home/jnml/src/modernc.org/qbecc
$ go install
$ cd _examples/mandelbrot2/
/home/jnml/src/modernc.org/qbecc/_examples/mandelbrot2
$ ls
main.c mandelbrot.c
$ gcc -c *.c && gcc *.o && ./a.out
--- ASCII Mandelbrot Set ---
<...output...>
$ rm *.o && qbecc --keep-ssa -c *.c && qbecc -o main.go *.o && go run .
<...same output...>

Example: Consuming a C Library

$ pwd
/home/jnml/src/modernc.org/qbecc
$ go install
$ cd _examples/mandelbrot3/
$ ls
main.go mandelbrot.c
$ cat main.go
package main

import "modernc.org/libc"

func main() {
	tls := libc.NewTLS()
	Ymandelbrot(tls)
}
$ qbecc --keep-ssa -c mandelbrot.c && qbecc -o mandelbrot.go mandelbrot.o && ls
main.go  mandelbrot.c  mandelbrot.go  mandelbrot.o  mandelbrot.s
$ go run .
--- ASCII Mandelbrot Set ---
<...output...>