Skip to content
Logo
Prismio
Developers
ImplementedPrismio 0.1.0

LLVM C API bridge

A categorized reference to the LLVM 22 C API used by Prismio's native backend and the ir_* operations exposed to self-hosted code.

Last verified

Implemented. Available in the audited Prismio 0.1.0 compiler. Pre-1.0 syntax may still change.

src/ir/bridge.psm is the ABI visible to the self-hosted compiler. runtime/llvm-api-backend.c implements it with LLVM 22's C API. The Prismio side passes type keys, symbol names, source positions, and integer handles; the C side owns every LLVM reference and reports failures through the compiler diagnostic channel.

This page lists the LLVM API families the backend actually calls. The list is generated conceptually from the current backend source, not from the larger LLVM header.

Context, module, target, and lifetime

LLVM functionWhere Prismio uses it
LLVMContextCreate, LLVMContextDisposeOwn the isolated type/metadata universe for one backend lifecycle
LLVMModuleCreateWithNameInContext, LLVMDisposeModuleCreate and release the program module
LLVMCreateBuilderInContextCreate the instruction builder positioned by block helpers
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTripleSelect the host target or validate an explicit target
LLVMCreateTargetMachine, LLVMDisposeTargetMachineMaterialize target-specific code-generation settings
LLVMCreateTargetDataLayout, LLVMDisposeTargetDataQuery pointer width, sizes, offsets, and ABI alignment
LLVMCopyStringRepOfTargetData, LLVMGetDataLayoutStrCopy the canonical layout string onto the module
LLVMGetTargetInspect the target stamped on a parsed or linked module
LLVMABISizeOfType, LLVMABIAlignmentOfTypeAnswer AIF/backend layout questions using the selected target

check_llvm_version rejects an incompatible major line before building IR. ensure_context creates shared LLVM state lazily. ensure_all_targets initializes target support once; ir_target_select records the triple, layout, pointer width, and whether selection was explicit. ir_module_set_target writes the result to the active module.

Type construction and inspection

type_from_key uses the context integer constructors, LLVMDoubleTypeInContext, LLVMVoidTypeInContext, and the opaque pointer type. Aggregates use:

  • LLVMStructTypeInContext for built-in value aggregates;
  • LLVMStructCreateNamed and LLVMStructSetBody for nominal program types;
  • LLVMArrayType2 for fixed arrays and vtable storage; and
  • LLVMFunctionType for declarations, definitions, direct calls, and indirect calls.

The backend inspects types with LLVMTypeOf, LLVMGetTypeKind, LLVMGetIntTypeWidth, LLVMGetStructName, LLVMGetElementType, LLVMCountParamTypes, LLVMGetParamTypes, and LLVMGetReturnType. These checks support value coercion, declaration reuse, debug-type synthesis, and validation of runtime helpers.

Constants use LLVMConstInt, LLVMConstReal, LLVMConstNull, LLVMConstPointerNull, LLVMConstStringInContext, LLVMConstArray2, LLVMConstNamedStruct, LLVMConstExtractValue, and LLVMGetUndef. const_from_text is the bridge parser for numeric/null textual values; named temporaries never go through it.

Globals and functions

LLVM functionBridge responsibility
LLVMAddGlobal, LLVMGetNamedGlobalDefine or find program globals and interned string objects
LLVMSetInitializerAttach constant initializers
LLVMSetGlobalConstantMark immutable globals
LLVMSetLinkageSelect external or available-externally linkage
LLVMDeleteGlobalRemove replaced or temporary globals
LLVMAddFunction, LLVMGetNamedFunctionMaterialize program, runtime, generated-helper, and extern functions
LLVMGetParamName and store incoming parameters
LLVMDeleteFunction, ir_delete_function_bodyRemove speculative/stub definitions while preserving valid declarations

Parameter and call-site facts use LLVMGetEnumAttributeKindForName, LLVMCreateEnumAttribute, LLVMCreateStringAttribute, LLVMAddAttributeAtIndex, and LLVMAddCallSiteAttribute. Prismio currently uses attributes for proven uniqueness, non-capture/borrow behavior, allocator/deallocator relationships, and inline policy. The proof is made in semantic/AIF code; the bridge only encodes it.

Instruction builders

Memory and aggregate operations:

  • LLVMBuildAlloca, LLVMBuildLoad2, and LLVMBuildStore implement local slots and memory reads/writes.
  • LLVMBuildGEP2, LLVMBuildInBoundsGEP2, and LLVMBuildStructGEP2 address array, byte, field, list-header, and cold-record locations.
  • LLVMBuildMemCpy implements struct copy and proven whole-buffer copy paths.
  • LLVMBuildInsertValue and LLVMBuildExtractValue assemble/disassemble strings, slices, payload values, and other SSA aggregates.
  • LLVMBuildGlobalStringPtr creates C-compatible constant text when a stable global is sufficient.

Integer and bitwise operations use LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul, LLVMBuildSDiv, LLVMBuildSRem, LLVMBuildUDiv, LLVMBuildURem, LLVMBuildNeg, LLVMBuildAnd, LLVMBuildOr, LLVMBuildXor, LLVMBuildNot, LLVMBuildShl, LLVMBuildLShr, and LLVMBuildAShr.

Floating operations use LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul, LLVMBuildFDiv, and LLVMBuildFNeg. Comparisons use LLVMBuildICmp or LLVMBuildFCmp with the predicate selected by the ir_icmp_* or ir_fcmp_* wrapper.

Conversions use LLVMBuildZExt, LLVMBuildSExt, LLVMBuildTrunc, LLVMBuildSIToFP, LLVMBuildUIToFP, LLVMBuildFPToSI, LLVMBuildFPToUI, LLVMBuildIntToPtr, LLVMBuildPtrToInt, and LLVMBuildBitCast. LLVMBuildSelect supports branchless scalar choices and representation guards.

Calls use LLVMBuildCall2 with an explicit LLVMFunctionType. The bridge does not use the deprecated untyped call builder. Direct calls resolve a named function; trait objects and closure adapters can supply an indirect function pointer via ir_call_end_indirect.

Blocks, branches, and PHI nodes

LLVMAppendBasicBlockInContext creates blocks and LLVMPositionBuilderAtEnd changes the insertion point. LLVMGetInsertBlock and LLVMGetBasicBlockTerminator prevent emission after a terminator. Branches and exits use LLVMBuildBr, LLVMBuildCondBr, LLVMBuildSwitch, LLVMAddCase, LLVMBuildRet, LLVMBuildRetVoid, and LLVMBuildUnreachable.

Short-circuit expressions and other merged values use LLVMBuildPhi plus LLVMAddIncoming. Inspection and rewriting utilities use LLVMGetFirstBasicBlock, LLVMGetNextBasicBlock, LLVMDeleteBasicBlock, LLVMGetFirstInstruction, LLVMGetNextInstruction, LLVMGetInstructionOpcode, LLVMGetNumOperands, and LLVMGetOperand.

Metadata and alias analysis

The backend constructs TBAA nodes with LLVMMDStringInContext2, LLVMMDNodeInContext2, and LLVMGetMDKindIDInContext, then attaches them through LLVMSetMetadata. Scalar, struct-path, list-header, list-element, DataView, and scoped alias domains are separate so LLVM may move invariant header loads without assuming unrelated element stores alias them.

Scoped no-alias metadata uses LLVMTemporaryMDNode, LLVMMetadataReplaceAllUsesWith, and LLVMDisposeTemporaryMDNode while constructing recursive metadata graphs. Range metadata on validated list lengths helps LLVM prove loop bounds.

Verification, optimization, bitcode, and linking

LLVMVerifyModule is mandatory before output. LLVMPrintModuleToString supports textual .ll output and diagnostics. LLVMWriteBitcodeToMemoryBuffer produces bitcode.

LLVMCreatePassBuilderOptions, LLVMRunPasses, and LLVMDisposePassBuilderOptions run the selected optimization pipeline. Object emission uses LLVMTargetMachineEmitToFile.

ir_link_modules reads modules with LLVMCreateMemoryBufferWithContentsOfFile and LLVMParseIRInContext or bitcode parsing, checks triple/layout compatibility, and combines them with LLVMLinkModules2. All owned messages and buffers are disposed on success and failure.

ORC JIT

The run path uses LLVMOrcCreateLLJIT, obtains the main dylib, installs a dynamic-library search generator, adds the current module as a thread-safe module, and looks up main. Error paths use LLVMGetErrorMessage, LLVMDisposeErrorMessage, and LLVMConsumeError; no LLVM error object may be silently dropped.

Adding a bridge operation

Add the declaration to bridge.psm, the prototype to prismio_llvm.h, and the implementation to llvm-api-backend.c. Accept type keys and value handles rather than exposing LLVM addresses. Check for a terminated block, use type_from_key and resolve_value, intern any produced value, attach applicable debug/TBAA metadata, and test the operation in runtime/test_llvm_backend.c plus a source-level regression. A bridge function is complete only when the self-hosted compiler can reproduce itself with it.