Skip to content

dasLLVM: derive JIT extern function types from a das signature - #3550

Merged
borisbat merged 1 commit into
masterfrom
aleksisch/jit-macro-definitions
Jul 23, 2026
Merged

dasLLVM: derive JIT extern function types from a das signature#3550
borisbat merged 1 commit into
masterfrom
aleksisch/jit-macro-definitions

Conversation

@aleksisch

Copy link
Copy Markdown
Collaborator

What

Registering a C++ runtime helper with the LLVM JIT backend used to require hand-spelling its LLVM function type — LLVMFunctionType(RET, fixed_array<LLVMTypeRef>(g_prim_t.LLVMVoidPtrType(), t_int64, ...)) — with a C-signature comment above each. ~38 of these lived in llvm_jit_common.das: verbose, duplicated (comment vs code), and a wrong arg count / scalar width silently miscompiles the JIT.

This derives the type from a das signature instead.

API

New module modules/dasLLVM/daslib/llvm_dsl.das (compile-time DSL helpers for the backend):

  • jit_fn_type(signature) — a [call_macro] that builds the extern's LLVMFunctionType from a das signature. signature is either an inline block $(args) : ret {} (preferred) or @@stub (a reference to a signature-carrier function). Both supported.

In llvm_jit_common.das:

  • jit_add_extern(name, typ, fnAddr, attrs [, argAttrs]) — declares one helper: LLVMAddFunctionWithType + global mapping + function attributes, plus optional per-argument attributes. argAttrs is a list of (argIndex, attribute) pairs (built with a comprehension for ranges, e.g. [for (i in range(0,3)); (i, nocapture)]), folding away every separate LLVMAddAttributeToFunctionArgument[Range] line.
  • jit_extern_type(t : Type) — the das-type → LLVM-type mapping.

Per site collapses from ~5 lines + a comment to one call:

// void jit_array_lock ( Array & array, Context * context, LineInfoArg * at )
jit_add_extern(FN_JIT_ARRAY_LOCK, jit_fn_type($(arr, ctx, at : void?) : void {}),
    get_jit_array_lock(), fixed_array(nounwind, willreturn), [for (i in range(0, 2)); (i, nocapture)])

Why it's safe (byte-identical IR)

The bundled LLVM is 22.1.5 with opaque pointers (mandatory) — every LLVMPointerType(*, 0) lowers to the same ptr. So the only load-bearing information in a signature is arg-count plus the non-pointer types (i32/i64/i1/float4/void), all of which the das signature spells. The emitted function types are identical to the hand-written ones. This is a readability refactor, not a behavior change.

Scope

All ~35 canonical extern registrations + the 3 special ones (jit_exception noreturn/cold, jit_handled_abi_check_report nounwind-only/empty-args, jit_init_extern) converted. Net -160 lines in llvm_jit_common.das. Not touched: the jit_simnode_interop/jit_free_simnode_interop pair (literal names, no attrs), and everything in llvm_jit.das / llvm_exe.das (per-user-function codegen, fileinfo, intrinsics, standalone/exe bootstrap).

Testing

  • Full JIT suite (run_tests_jit) green.
  • Interp vs -jit output identical across arrays / iterators / string-builder+str_cat / block-invoke / tables / generators.
  • Both jit_fn_type forms (block and @@) validated end-to-end.
  • Lint clean on both edited files.

No AOT emitter path touched, so no LLVM_JIT_CODEGEN_VERSION bump needed.

@aleksisch
aleksisch force-pushed the aleksisch/jit-macro-definitions branch 2 times, most recently from a57888e to 26f88d9 Compare July 23, 2026 11:29
@borisbat
borisbat requested a review from Copilot July 23, 2026 11:52
@aleksisch
aleksisch force-pushed the aleksisch/jit-macro-definitions branch from 26f88d9 to 807beaf Compare July 23, 2026 11:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors dasLLVM’s LLVM JIT extern registration to derive LLVM function/struct types from daScript signatures, reducing duplicated hand-written LLVM type spelling and lowering the risk of silent JIT miscompiles from mismatched arg counts or scalar widths.

Changes:

  • Added a new compile-time DSL module (llvm_dsl.das) providing jit_fn_type(...) and jit_struct_type(...) call macros.
  • Introduced jit_add_extern(...) helpers in llvm_jit_common.das to consolidate extern declaration, global mapping, and attribute application.
  • Updated llvm_jit_common.das to use signature-derived types for the canonical extern set and tuple-derived struct layouts.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
modules/dasLLVM/daslib/llvm_jit_common.das Replaces hand-spelled LLVM extern signatures with jit_fn_type + jit_add_extern, and uses jit_struct_type for several runtime-mirror structs.
modules/dasLLVM/daslib/llvm_dsl.das New compile-time call-macro helpers for building LLVM function/struct types from daScript signatures/types.
modules/dasLLVM/.das_module Registers llvm_dsl so it’s available as part of the dasLLVM module set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +7 to +9
require daslib/ast_boost
require daslib/macro_boost
require daslib/templates_boost

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply_qmacro comes from it

Comment on lines +552 to +559
// argAttr: (attribute, argument-indices) — e.g. (nocapture, [0, 1, 2, 3]) or (nocapture, [1]).
def public jit_add_extern(name : string; typ : LLVMTypeRef; fnAddr : void?; attrs : LLVMOpaqueAttributeRef? []; argAttr : tuple<LLVMOpaqueAttributeRef?; array<int>>) {
var f = jit_add_extern(name, typ, fnAddr, attrs)
for (i in argAttr._1) {
LLVMAddAttributeToFunctionArgument(f, uint(i), argAttr._0)
}
return f
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's known limitation. Let's not complicate unless it is needed.

In future possible solution is to add overload that will take array<(array, int)>, and current one will cimply redirect.

@aleksisch
aleksisch force-pushed the aleksisch/jit-macro-definitions branch 2 times, most recently from 31c0a8f to c4cbf06 Compare July 23, 2026 12:21
New module llvm_dsl with two compile-time helpers:
 - jit_fn_type(signature): derive an LLVM function type from a das
   signature — an inline $(args):ret{} block or @@Stub.
 - jit_struct_type(type<tuple<...>>): derive an LLVM struct type mirroring
   a C++ layout from a (named) tuple's element types.
Plus jit_add_extern in llvm_jit_common (add + global mapping + function
attrs + optional per-arg attrs as (attribute, indices)).

LLVM 22 uses opaque pointers, so every pointer lowers to `ptr` — the das
signature fully determines the type and the emitted IR is byte-identical
to the hand-written declarations. Struct forms cover only fixed-layout
mirrors; the element-typed data pointer in Array/Table is a no-op under
opaque pointers, and the explicit pad slots stay explicit tuple fields.

Converted:
 - llvm_jit_common: all ~38 extern registrations, the 7 build_jit_types
   struct types, table_header, and the Array/Table struct types.
 - llvm_jit: line_info, the 7 RTTI type builders (TypeInfo/VarInfo/
   StructInfo/EnumValueInfo/AnnotationArgumentInfo/AnnotationInfo/EnumInfo),
   and the fileinfo function types.

Behavior unchanged; JIT test suite green (11790 pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aleksisch
aleksisch force-pushed the aleksisch/jit-macro-definitions branch from c4cbf06 to a409dee Compare July 23, 2026 13:37
@borisbat
borisbat merged commit 7a38f89 into master Jul 23, 2026
33 checks passed
aleksisch added a commit that referenced this pull request Jul 23, 2026
Newer @ast-grep/cli deprecated the `sg` alias and prints a
"WARNING: `sg` is deprecated" banner into the captured --json output,
which corrupts the parse in cpp_grep_usage / cpp_find_symbol / cpp_outline
(the 21 'Failed to parse ast-grep output: invalid character =' failures in
run_utils_tests). Prefer the canonical `ast-grep` binary (ships in the same
package, emits clean JSON); keep `sg` as a fallback for older installs.

Repo-wide CI issue, present on master too (extended checks #3550).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants