Concrete is a simple programming language specifically crafted for creating highly scalable systems that are reliable, efficient, and easy to maintain.
Inline assembly technically works, but it’s very awkward to write. The syntax is painful, editor support is atrocious, and “default” assemblers lack lots of ergonomy. It’s just not a good experience when you’re writing large quantities of it.
What I’m aiming at is more of a high-level assembler, with a mix of manual and automatic register allocation, for-loops, if-statements, ergonomic macros, etc. It’ll still be architecture-specific, but the idea is too offload a good chunk of boilerplate and visual noise to the compiler.
Take this code for example (weird implementation, just for demonstration):
example::count_digits:
mov ecx, 1
cmp rdi, 10
jb .LBB0_3
movabs rsi, -3689348814741910323
.LBB0_2:
inc rcx
mov rax, rdi
mul rsi
shr rdx, 3
cmp rdi, 99
mov rdi, rdx
ja .LBB0_2
.LBB0_3:
mov rax, rcx
ret
to this
def count_digits = asm x86_64(n: u64) {
if (n < 10) return 1;
let digits = 1;
let rsi = -3689348814741910323;
do {
digits++;
rax = n;
mul(rsi);
shr(rdx, 3);
rdi = rdx;
} while rdi >= 10;
digits
}
The latter count_lines is a simple function I can call directly from the rest of my code. The instruction set may be part of the type signature, so I’m protected from accidentally writing e.g. rv64 assembly in an rv32 block.
Note the mix of explicit and automatic register usage. There are just many times where I don’t care which exact register I use for my loop counter, or a temporary variable. With LSP support, I’ll still be able to highlight which register the compiler chose (display on hover, or inlay hint), and maybe offer syntax to override it."
This is cool: https://lobste.rs/s/mnqqdu/what_are_you_doing_this_weekend#c_81rej9 "Any architecture, although I’m currently focussing on RISC-V.
Inline assembly technically works, but it’s very awkward to write. The syntax is painful, editor support is atrocious, and “default” assemblers lack lots of ergonomy. It’s just not a good experience when you’re writing large quantities of it.
What I’m aiming at is more of a high-level assembler, with a mix of manual and automatic register allocation, for-loops, if-statements, ergonomic macros, etc. It’ll still be architecture-specific, but the idea is too offload a good chunk of boilerplate and visual noise to the compiler.
Take this code for example (weird implementation, just for demonstration):
example::count_digits: mov ecx, 1 cmp rdi, 10 jb .LBB0_3 movabs rsi, -3689348814741910323 .LBB0_2: inc rcx mov rax, rdi mul rsi shr rdx, 3 cmp rdi, 99 mov rdi, rdx ja .LBB0_2 .LBB0_3: mov rax, rcx ret to this
def count_digits = asm x86_64(n: u64) { if (n < 10) return 1; let digits = 1; let rsi = -3689348814741910323; do { digits++; rax = n; mul(rsi); shr(rdx, 3); rdi = rdx; } while rdi >= 10; digits }
The latter count_lines is a simple function I can call directly from the rest of my code. The instruction set may be part of the type signature, so I’m protected from accidentally writing e.g. rv64 assembly in an rv32 block.
Note the mix of explicit and automatic register usage. There are just many times where I don’t care which exact register I use for my loop counter, or a temporary variable. With LSP support, I’ll still be able to highlight which register the compiler chose (display on hover, or inlay hint), and maybe offer syntax to override it."