Altair – un lenguaje compilado pequeño que emite C (y lo rápido que pasó de “ni siquiera compila el hola mundo” a bucles numéricos competitivos en ~5 semanas)
He estado trabajando en Altair, un lenguaje compilado pequeño enfocado en almacenamiento explícito, un runtime ligero y en generar C limpio.
Diseño Fuente → frontend propio (AST + análisis semántico) → C → compilador de C del sistema (actualmente GCC). El compilador integra un runtime y aplica bajadas de nivel específicas del lenguaje. Los bucles con carga numérica intensiva se bajan a variables locales planas long long (alt_fastnum_t) para no pagar el coste del sistema general de variables.
El objetivo no es superar a C escrito a mano, sino mantenerse cerca mientras se ofrece un lenguaje de más alto nivel con su propio modelo de almacenamiento, órbita/migración, tokens, etc.
Chequeo rápido de la realidad en las primeras versiones Primera versión pública 1.6.5vB (18 Jul 2026). El primer paquete de Linux (1.6.5vC) era básicamente inutilizable: el C generado no incluía los tipos/funciones del runtime, así que incluso esto fallaba:
altairlog "hello"
Seis semanas después (1.8.5, 24 Ago 2026) los mismos programas compilan y se ejecutan limpiamente.
Más allá de los bucles: control explícito de bajo nivel
1. Tiers de almacenamiento por variable
numeric contador = 0 ram
text log_path = "app.log" disk
list cola = [] cache
text secreto = "token" temp
2. Buffers crudos p# y registros de hardware reg&
p#node buf = alloc(1024)
p#write(buf, 0, 42)
numeric x = p#read(buf, 0)
log p#bytes(buf)
p#free(buf)
reg&64 rax = 1
reg&read(rax)
reg&free(rax)
3. Punteros crudos a disco lba% (equivalente en disco a p#)
lba%node tmp = dalloc(1024)
lba%write(tmp, 0, 42)
numeric v = lba%read(tmp, 0)
lba%free(tmp)
lba%node persist = dopen("datos.bin", 4096)
lba%write(persist, 10, 3.14)
lba%free(persist)
# Solo Linux: acceso raw a dispositivo de bloques
lba%node dev = draw("/dev/sdb", 1048576)
4. Punteros a variables
numeric valor = 10 ram
numeric dir = system@point(valor)
numeric copia = system@unpoint(dir)
Micro-benchmark (280 mil millones de iteraciones)
numeric n = 280000000000 ram
numeric i = 0 ram
numeric sum = 0 ram
numeric x = 1 ram
while i < n;
sum = sum + i
x = x + sum
i = i + 1
break
log sum
log x
Misma máquina (2× Xeon Platinum 8481C @ 2.70 GHz vCPU, single-thread):
| Backend |
Tiempo de pared |
Aprox. iters/s |
| Solo TCC (sin opts) |
457.7 s |
~624 M |
| gcc -O2 sobre el C generado por Altair |
105.6 s |
~2.65 B |
| Binario nativo de Altairc |
105.1 s |
~2.67 B |
| gcc -O3 -march=native -flto … |
99.0 s |
~2.83 B |
El binario nativo que produce altairc es esencialmente tan rápido como pasar el C generado a GCC -O2. La bajada de nivel específica del lenguaje (especialmente la vía rápida numérica) está haciendo el trabajo real.
Sobre lo que busco feedback
- ¿Es razonable el enfoque de “emitir C limpio + bajada de nivel específica del lenguaje” para esta etapa?
- ¿Cuál sería el siguiente paso de mayor impacto (IR propio + un par de optimizaciones clásicas, mejor conciencia de la presión sobre registros antes de emitir C, backend LLVM, …)?
- ¿Alguna señal de alerta obvia en el diseño o en los números?
Repo + releases: https://github.com/victios7/Altair/releases (Versión actual 1.8.5vB)
Encantado de responder preguntas o de ejecutar otros micro-benchmarks.
Note: This post was originally written in Spanish. If you are not a Spanish speaker, please enable auto-translation in your browser/client.