qbecc command - modernc.org/qbecc - Go Packages

12 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 @ v0.1.17

	goos: linux
	goarch: amd64
	pkg: modernc.org/qbecc/lib
	cpu: AMD Ryzen 9 3900X 12-Core Processor
	HostCC: gcc (Debian 14.2.0-19) 14.2.0
	ccgo: v4.32.0

                                arg   HostCC_O2   HostCC_O1       QBECC   HostCC_O0        CCGO      GOABI0
-----------------------------------------------------------------------------------------------------------
                      cert:aes.c-24       1.000       0.876       2.236       2.276       1.092       2.220
                cert:almabench.c-24       1.000       1.020       1.282       1.429       2.712       3.552
              cert:binarytrees.c-24       1.000       1.097       1.205       1.312       2.336       2.844
                   cert:bisect.c-24       1.000       1.004       1.161       1.655       1.031       1.219
                    cert:chomp.c-24       1.000       1.082       1.109       1.468       1.002       1.415
                 cert:fannkuch.c-24       1.000       0.921       1.063       2.452       1.146       1.008
                      cert:fft.c-24       1.000       0.868       1.228       0.533       0.947       1.364
                    cert:fftsp.c-24       1.000       0.932       1.028       1.032       1.012       1.498
                     cert:fftw.c-24       1.000       1.006       1.276       3.820       1.368       1.355
                      cert:fib.c-24       1.000       2.495       3.495       4.234       3.010       4.179
                   cert:integr.c-24       1.000       3.361       3.254       3.731       3.355       3.592
              cert:knucleotide.c-24       1.000       1.048       1.051       1.344       1.412       1.445
                    cert:lists.c-24       1.000       0.972       0.955       2.085       0.887       0.917
               cert:mandelbrot.c-24       1.000       1.052       1.306       2.615       1.023       1.346
                    cert:nbody.c-24       1.000       1.268       1.469       3.170       3.228       3.934
                   cert:nsieve.c-24       1.000       0.754       0.919       1.826       0.710       0.967
               cert:nsievebits.c-24       1.000       1.061       1.269       3.015       1.132       1.344
                   cert:perlin.c-24       1.000       1.074       1.726       2.523       2.936       5.652
                    cert:qsort.c-24       1.000       0.971       1.256       1.699       1.393       1.899
                     cert:sha1.c-24       1.000       0.670       0.857       1.658       0.890       1.062
                     cert:sha3.c-24       1.000       1.055       1.968       5.832       2.229       2.157
                cert:siphash24.c-24       1.000       1.360       2.331       3.936       1.454       2.387
                 cert:spectral.c-24       1.000       2.106       4.335       2.924       2.026       4.385
                    cert:vmach.c-24       1.000       1.087       1.319       1.621       1.118       1.524
                qjs:array_for.js-24       1.000       0.873       6.000       1.855       2.689       5.100
             qjs:array_for_in.js-24       1.000       1.364       4.976       2.638       4.175       7.087
             qjs:array_for_of.js-24       1.000       1.160       6.912       3.027       5.539       9.656
   qjs:array_hole_length_decr.js-24       1.000       1.092       4.959       2.425       3.989       6.683
        qjs:array_length_decr.js-24       1.000       1.029       5.289       2.298       4.101       7.076
                qjs:array_pop.js-24       1.000       1.004       6.541       2.550       4.291       7.604
        qjs:array_prop_create.js-24       1.000       0.866       4.948       1.773       2.512       4.780
               qjs:array_push.js-24       1.000       1.246       7.380       2.622       4.229       7.821
               qjs:array_read.js-24       1.000       0.709       4.649       1.764       2.712       3.824
              qjs:array_slice.js-24       1.000       1.164       5.457       3.196       5.586       9.076
              qjs:array_write.js-24       1.000       0.735       4.106       2.073       2.674       4.871
                 qjs:date_now.js-24       1.000       0.862       5.977       1.847       7.219      10.438
               qjs:date_parse.js-24       1.000       1.089       2.903       1.949       3.002       4.380
            qjs:empty_do_loop.js-24       1.000       0.479       3.309       0.922       1.539       2.714
          qjs:empty_down_loop.js-24       1.000       0.458       3.306       0.812       1.175       2.378
         qjs:empty_down_loop2.js-24       1.000       0.861       4.486       1.658       2.836       6.105
               qjs:empty_loop.js-24       1.000       0.635       4.338       1.164       1.434       3.157
              qjs:factorial10.js-24       1.000       0.717       5.523       1.455       2.465       5.034
              qjs:float_arith.js-24       1.000       0.972       5.195       1.628       2.349       4.230
      qjs:float_toExponential.js-24       1.000       1.152       4.221       2.324       2.582       5.199
            qjs:float_toFixed.js-24       1.000       1.186       4.582       2.513       2.699       5.827
        qjs:float_toPrecision.js-24       1.000       1.103       4.077       2.197       2.399       4.799
           qjs:float_toString.js-24       1.000       1.124       3.572       2.146       1.886       3.678
          qjs:float_to_string.js-24       1.000       1.178       3.192       2.167       1.874       3.501
                qjs:func_call.js-24       1.000       0.896       6.347       1.600       2.487       5.884
        qjs:func_closure_call.js-24       1.000       0.937       8.050       2.056       3.061       7.429
          qjs:global_destruct.js-24       1.000       1.335       5.572       3.337       4.866       8.039
   qjs:global_destruct_strict.js-24       1.000       1.365       5.651       3.354       4.899       8.120
         qjs:global_func_call.js-24       1.000       0.906       6.871       2.042       3.336       6.735
              qjs:global_read.js-24       1.000       1.223       6.185       3.202       4.219       6.962
             qjs:global_write.js-24       1.000       1.013       5.027       2.565       3.620       6.508
      qjs:global_write_strict.js-24       1.000       1.045       5.132       2.590       3.700       6.653
                qjs:int_arith.js-24       1.000       0.569       3.661       1.091       1.527       3.022
             qjs:int_toString.js-24       1.000       1.300       5.280       2.317       3.514       7.302
            qjs:int_to_string.js-24       1.000       1.195       5.140       2.138       3.202       6.812
           qjs:int_to_string2.js-24       1.000       1.330       3.830       2.218       3.299       6.240
           qjs:local_destruct.js-24       1.000       1.239       3.951       2.825       3.237       5.811
               qjs:map_delete.js-24       1.000       1.183       5.695       2.567       3.690       7.068
           qjs:map_set_bigint.js-24       1.000       1.076       7.300       2.796       4.383       8.850
              qjs:map_set_int.js-24       1.000       1.096       6.238       2.414       3.551       7.507
           qjs:map_set_string.js-24       1.000       1.162       5.665       2.479       3.509       6.947
                 qjs:math_min.js-24       1.000       0.823       6.838       2.133       3.344       6.678
               qjs:prop_clone.js-24       1.000       1.304       3.930       2.864       3.025       5.511
              qjs:prop_create.js-24       1.000       1.064       3.809       2.382       2.308       4.324
              qjs:prop_delete.js-24       1.000       1.212       3.880       2.624       2.846       5.273
                qjs:prop_read.js-24       1.000       1.140       6.190       2.848       3.804       6.026
              qjs:prop_update.js-24       1.000       1.307       7.013       3.199       5.168       9.002
               qjs:prop_write.js-24       1.000       0.734       5.220       2.856       3.803       5.732
             qjs:regexp_ascii.js-24       1.000       1.183       3.368       2.324       2.496       4.488
             qjs:regexp_utf16.js-24       1.000       1.184       3.579       2.428       2.603       4.691
            qjs:string_build1.js-24       1.000       1.186       4.662       1.752       2.349       4.422
           qjs:string_build1x.js-24       1.000       1.203       4.657       1.749       2.318       4.444
            qjs:string_build2.js-24       1.000       1.167       4.214       2.000       3.501       6.394
           qjs:string_build2c.js-24       1.000       1.214       4.258       1.706       1.997       3.933
            qjs:string_build3.js-24       1.000       1.186       4.085       2.031       3.385       6.213
            qjs:string_build4.js-24       1.000       1.177       4.182       2.020       3.515       6.452
      qjs:string_build_large1.js-24       1.000       1.275       3.969       2.102       3.080       5.753
      qjs:string_build_large2.js-24       1.000       1.235       4.218       2.237       3.648       6.638
          qjs:string_to_float.js-24       1.000       1.075       4.514       2.260       2.297       4.179
            qjs:string_to_int.js-24       1.000       1.152       4.886       2.188       2.764       5.343
         qjs:typed_array_read.js-24       1.000       0.640       4.070       1.566       2.896       4.014
        qjs:typed_array_write.js-24       1.000       0.856       4.524       1.920       2.912       4.809
          qjs:weak_map_delete.js-24       1.000       1.155       4.609       2.406       3.205       5.708
             qjs:weak_map_set.js-24       1.000       1.208       6.439       2.880       4.440       8.267
                          sqlite-24       1.000       1.130       1.784       1.839       2.876       4.019
-----------------------------------------------------------------------------------------------------------
                            geomean       1.000       1.055       3.470       2.148       2.515       4.210
                                      HostCC_O2   HostCC_O1       QBECC   HostCC_O0        CCGO      GOABI0

	goos: linux
	goarch: arm64
	pkg: modernc.org/qbecc/lib
	cpu: ARM Cortex-A76 4-Core Processor
	HostCC: gcc (Debian 12.2.0-14+deb12u1) 12.2.0
	ccgo: v4.32.1

                                arg   HostCC_O2   HostCC_O1        CCGO       QBECC   HostCC_O0
-----------------------------------------------------------------------------------------------
                       cert:aes.c-4       1.000       0.905       1.178       3.873       2.395
                 cert:almabench.c-4       1.000       0.944       3.834       1.540       1.419
               cert:binarytrees.c-4       1.000       1.008       1.964       1.281       1.211
                    cert:bisect.c-4       1.000       0.973       1.081       1.187       1.320
                     cert:chomp.c-4       1.000       1.037       1.182       1.677       1.702
                  cert:fannkuch.c-4       1.000       0.913       1.344       1.612       3.047
                       cert:fft.c-4       1.000       1.011       1.246       1.084       1.427
                     cert:fftsp.c-4       1.000       0.943       2.142       1.414       2.383
                      cert:fftw.c-4       1.000       1.194       1.589       2.481       4.364
                       cert:fib.c-4       1.000       1.745       2.456       2.929       2.694
                    cert:integr.c-4       1.000       1.878       4.353       3.737       4.745
               cert:knucleotide.c-4       1.000       0.955       1.524       1.261       1.573
                     cert:lists.c-4       1.000       0.955       0.978       1.368       3.709
                cert:mandelbrot.c-4       1.000       1.085       1.136       1.272       2.262
                     cert:nbody.c-4       1.000       1.213       3.470       1.907       3.522
                    cert:nsieve.c-4       1.000       1.002       1.074       1.156       2.068
                cert:nsievebits.c-4       1.000       0.959       1.115       1.472       1.930
                    cert:perlin.c-4       1.000       1.008       5.879       3.867       4.073
                     cert:qsort.c-4       1.000       0.895       1.314       1.514       1.589
                      cert:sha1.c-4       1.000       0.621       1.156       2.131       1.579
                      cert:sha3.c-4       1.000       1.117       3.411       6.783       6.899
                 cert:siphash24.c-4       1.000       1.256       1.673       4.086       6.954
                  cert:spectral.c-4       1.000       1.389       1.601       2.874       3.235
                     cert:vmach.c-4       1.000       0.821       1.060       1.896       3.033
                 qjs:array_for.js-4       1.000       1.105       5.775      11.859       3.376
              qjs:array_for_in.js-4       1.000       1.301       5.556       6.648       2.925
              qjs:array_for_of.js-4       1.000       0.975       7.710      10.230       4.149
    qjs:array_hole_length_decr.js-4       1.000       1.042       5.505       9.245       3.878
         qjs:array_length_decr.js-4       1.000       1.072       6.345      10.309       3.553
                 qjs:array_pop.js-4       1.000       1.029       6.664       9.927       3.977
         qjs:array_prop_create.js-4       1.000       1.101       4.136       9.903       3.271
                qjs:array_push.js-4       1.000       0.956       5.820       9.570       3.625
                qjs:array_read.js-4       1.000       1.166       7.359      13.033       3.751
               qjs:array_slice.js-4       1.000       1.149       5.605       7.852       2.779
               qjs:array_write.js-4       1.000       1.062       4.919      10.136       3.083
                  qjs:date_now.js-4       1.000       0.913       7.200       9.029       3.310
                qjs:date_parse.js-4       1.000       0.982       3.631       3.933       2.231
             qjs:empty_do_loop.js-4       1.000       1.365       5.152      15.932       3.301
           qjs:empty_down_loop.js-4       1.000       1.154       3.297      13.235       2.910
          qjs:empty_down_loop2.js-4       1.000       1.151       5.325      10.969       3.530
                qjs:empty_loop.js-4       1.000       1.330       4.050      13.305       3.323
               qjs:factorial10.js-4       1.000       1.038       6.114      12.960       3.998
               qjs:float_arith.js-4       1.000       1.356       5.356      15.214       3.843
       qjs:float_toExponential.js-4       1.000       1.194       3.690       6.598       2.862
             qjs:float_toFixed.js-4       1.000       1.130       4.042       7.044       2.913
         qjs:float_toPrecision.js-4       1.000       1.258       3.754       7.788       3.093
            qjs:float_toString.js-4       1.000       1.174       3.423       5.934       3.213
           qjs:float_to_string.js-4       1.000       1.265       2.931       5.559       3.331
                 qjs:func_call.js-4       1.000       0.982       5.171      12.926       3.240
         qjs:func_closure_call.js-4       1.000       1.049       5.973      12.517       3.100
           qjs:global_destruct.js-4       1.000       1.084       6.254       8.870       4.201
    qjs:global_destruct_strict.js-4       1.000       1.161       6.883       8.681       4.203
          qjs:global_func_call.js-4       1.000       0.875       5.748      10.896       3.670
               qjs:global_read.js-4       1.000       0.992       8.123      12.754       5.538
              qjs:global_write.js-4       1.000       1.135       6.279      12.197       4.709
       qjs:global_write_strict.js-4       1.000       1.105       5.659      11.459       4.471
                 qjs:int_arith.js-4       1.000       1.082       4.241      11.872       3.453
              qjs:int_toString.js-4       1.000       1.282       6.525       7.818       3.087
             qjs:int_to_string.js-4       1.000       1.165       5.154       7.313       2.781
            qjs:int_to_string2.js-4       1.000       1.365       5.797       5.890       2.537
            qjs:local_destruct.js-4       1.000       1.139       4.480       6.102       3.222
                qjs:map_delete.js-4       1.000       1.027       5.131       7.611       3.123
            qjs:map_set_bigint.js-4       1.000       1.033       6.126      10.075       4.188
               qjs:map_set_int.js-4       1.000       0.971       5.329       8.297       3.276
            qjs:map_set_string.js-4       1.000       1.059       4.711       6.912       3.000
                  qjs:math_min.js-4       1.000       0.929       6.643      11.750       4.279
                qjs:prop_clone.js-4       1.000       1.084       3.444       5.778       3.237
               qjs:prop_create.js-4       1.000       1.108       3.753       6.121       3.432
               qjs:prop_delete.js-4       1.000       1.063       4.156       6.321       3.210
                 qjs:prop_read.js-4       1.000       1.038       7.356      12.467       4.824
               qjs:prop_update.js-4       1.000       0.978       6.787      10.402       3.986
                qjs:prop_write.js-4       1.000       0.899       5.948      10.696       3.910
              qjs:regexp_ascii.js-4       1.000       1.005       3.603       4.759       2.382
              qjs:regexp_utf16.js-4       1.000       1.051       3.316       5.288       2.389
             qjs:string_build1.js-4       1.000       1.346       3.537       9.163       3.226
            qjs:string_build1x.js-4       1.000       1.337       3.782       9.646       3.438
             qjs:string_build2.js-4       1.000       1.026       4.596       6.090       2.452
            qjs:string_build2c.js-4       1.000       1.335       3.145       7.398       2.991
             qjs:string_build3.js-4       1.000       1.065       5.047       5.422       2.380
             qjs:string_build4.js-4       1.000       1.118       6.065       6.420       2.774
       qjs:string_build_large1.js-4       1.000       1.191       4.322       5.179       2.394
       qjs:string_build_large2.js-4       1.000       1.239       4.944       5.550       2.518
           qjs:string_to_float.js-4       1.000       1.027       2.769       6.784       2.891
             qjs:string_to_int.js-4       1.000       1.172       3.506       6.912       2.749
          qjs:typed_array_read.js-4       1.000       1.157       8.164      11.840       3.364
         qjs:typed_array_write.js-4       1.000       1.151       4.733      10.031       2.730
           qjs:weak_map_delete.js-4       1.000       1.015       4.461       6.350       3.090
              qjs:weak_map_set.js-4       1.000       0.898       5.313       7.795       3.150
                           sqlite-4       1.000       1.154       2.867       2.320       2.363
-----------------------------------------------------------------------------------------------
                            geomean       1.000       1.088       3.716       5.690       3.048
                                      HostCC_O2   HostCC_O1        CCGO       QBECC   HostCC_O0

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
linux/arm64      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

  • 2026-01-12: Re-enabled linux/arm64 support.
  • 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...>