{"id":31579210,"url":"https://github.com/petitstrawberry/jit-assembler","last_synced_at":"2025-10-13T18:43:25.387Z","repository":{"id":316391277,"uuid":"1063149624","full_name":"petitstrawberry/jit-assembler","owner":"petitstrawberry","description":"A multi-architecture JIT assembler library for Rust.","archived":false,"fork":false,"pushed_at":"2025-10-02T02:24:03.000Z","size":324,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2025-10-09T12:10:02.281Z","etag":null,"topics":["assembler","jit","jit-assembler","riscv","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/petitstrawberry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-24T08:28:39.000Z","updated_at":"2025-10-06T14:33:28.000Z","dependencies_parsed_at":"2025-09-24T11:37:30.315Z","dependency_job_id":null,"html_url":"https://github.com/petitstrawberry/jit-assembler","commit_stats":null,"previous_names":["petitstrawberry/jit-assembler"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/petitstrawberry/jit-assembler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petitstrawberry%2Fjit-assembler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petitstrawberry%2Fjit-assembler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petitstrawberry%2Fjit-assembler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petitstrawberry%2Fjit-assembler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/petitstrawberry","download_url":"https://codeload.github.com/petitstrawberry/jit-assembler/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/petitstrawberry%2Fjit-assembler/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279016600,"owners_count":26085852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembler","jit","jit-assembler","riscv","rust"],"created_at":"2025-10-05T20:48:04.403Z","updated_at":"2025-10-13T18:43:25.382Z","avatar_url":"https://github.com/petitstrawberry.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jit-assembler\n\nA multi-architecture JIT assembler library for runtime code generation that works on any host architecture.\n\n## Features\n\n- **Multi-architecture support**: Generate machine code for different target architectures\n- **Host-independent**: Runs on any host architecture (x86_64, ARM64, etc.) to generate target code\n- **No-std compatible**: Works in both `std` and `no_std` environments\n- **Type-safe**: Leverages Rust's type system for safe instruction generation\n- **Dual API**: Both macro-based DSL and builder pattern for different use cases\n- **IDE-friendly**: Full autocomplete and type checking support\n- **JIT execution**: Direct execution of assembled code as functions (std-only)\n- **Register usage tracking**: Analyze register usage patterns for optimization and ABI compliance (`register-tracking` feature)\n\n## Supported Architectures\n\n- **RISC-V 64-bit** (`riscv` feature, enabled by default)\n- **AArch64** (`aarch64` feature, enabled by default) - Basic arithmetic and logical operations\n- **x86-64** (`x86_64` feature) - Coming soon\n\n## Usage\n\nAdd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\njit-assembler = \"0.1\"\n```\n\n### Basic Usage\n\n```rust\nuse jit_assembler::riscv::{reg, csr, Riscv64InstructionBuilder};\nuse jit_assembler::riscv64_asm;\n\n// Macro style (concise and assembly-like)\nlet instructions = riscv64_asm! {\n    csrrw(reg::RA, csr::MSTATUS, reg::SP);   // CSR read-write using aliases\n    csrr(reg::T0, csr::MSTATUS);             // CSR read (alias)\n    addi(reg::A0, reg::ZERO, 100);           // Add immediate using aliases\n    add(reg::A1, reg::A0, reg::SP);          // Register add with aliases\n    beq(reg::A0, reg::A1, 8);                // Branch if equal\n    jal(reg::RA, 0x1000);                    // Jump and link\n    ret();                                   // Return (alias for jalr x0, x1, 0)\n};\n\n// Method chaining style (recommended for programmatic use)\nlet mut builder = Riscv64InstructionBuilder::new();\nlet instructions2 = builder\n    .csrrw(reg::RA, csr::MSTATUS, reg::SP)   // CSR read-write using aliases\n    .addi(reg::A0, reg::ZERO, 100)           // Add immediate with aliases\n    .add(reg::A1, reg::A0, reg::SP)          // Register add using aliases\n    .beq(reg::A0, reg::A1, 8)                // Branch if equal\n    .jal(reg::RA, 0x1000)                    // Jump and link\n    .ret()                                   // Return instruction\n    .instructions();\n\n// Traditional style\nlet mut builder3 = Riscv64InstructionBuilder::new();\nbuilder3.csrrw(reg::RA, csr::MSTATUS, reg::SP);\nbuilder3.addi(reg::A0, reg::ZERO, 100);\nbuilder3.ret();\nlet instructions3 = builder3.instructions();\n\n// Convert instructions to bytes easily\nlet bytes = instructions.to_bytes();     // All instructions as one byte vector\nlet size = instructions.total_size();    // Total size in bytes\nlet count = instructions.len();          // Number of instructions\n\n// Iterate over instructions\nfor (i, instr) in instructions.iter().enumerate() {\n    println!(\"Instruction {}: {} -\u003e {:?}\", i, instr, instr.bytes());\n}\n\n// Or access by index\nlet first_instr = instructions[0];\n```\n\n### No-std Usage\n\nFor `no_std` environments, disable the default features:\n\n```toml\n[dependencies]\njit-assembler = { version = \"0.1\", default-features = false, features = [\"riscv\"] }\n# Or for AArch64 only:\n# jit-assembler = { version = \"0.1\", default-features = false, features = [\"aarch64\"] }\n# Or for both architectures without std:\n# jit-assembler = { version = \"0.1\", default-features = false, features = [\"riscv\", \"aarch64\"] }\n```\n\n## Architecture Support\n\n### RISC-V\n\nThe RISC-V backend supports:\n\n- **Base integer instruction set (RV64I)**:\n  - **Arithmetic**: `add`, `sub`, `addi`, `xor`, `or`, `and`, `slt`, `sltu`\n  - **Immediate arithmetic**: `andi`, `ori`, `xori`, `slti`, `sltiu`\n  - **Shifts**: `sll`, `srl`, `sra`, `slli`, `srli`, `srai`\n  - **Upper immediates**: `lui`, `auipc`\n- **M extension (Integer Multiplication and Division)**:\n  - **Multiply**: `mul`, `mulh`, `mulhsu`, `mulhu`\n  - **Divide**: `div`, `divu`, `rem`, `remu`\n- **Memory operations**:\n  - **Loads (signed)**: `ld`, `lw`, `lh`, `lb`\n  - **Loads (unsigned)**: `lbu`, `lhu`, `lwu`\n  - **Stores**: `sd`, `sw`, `sh`, `sb`\n- **Control flow**: `jal`, `jalr`, `beq`, `bne`, `blt`, `bge`, `bltu`, `bgeu`\n- **CSR instructions**: `csrrw`, `csrrs`, `csrrc`, `csrrwi`, `csrrsi`, `csrrci`\n- **CSR pseudo-instructions**: `csrr` (read), `csrw` (write), `csrs` (set), `csrc` (clear), `csrwi`, `csrsi`, `csrci`\n- **Privileged instructions**: `sret`, `mret`, `ecall`, `ebreak`, `wfi`\n- **Pseudo-instructions**: `ret`, `li`\n- **Register usage tracking**: Full tracking support for all instruction types (`register-tracking` feature)\n\n### AArch64\n\nThe AArch64 backend supports:\n\n- **Basic arithmetic operations**:\n  - **Register operations**: `add`, `sub`, `mul`, `udiv`, `sdiv`\n  - **Immediate operations**: `addi`, `subi`\n  - **Multiply-subtract operations**: `msub` (multiply-subtract for implementing remainder)\n- **Logical operations**:\n  - **Register operations**: `and`, `or`, `xor` (EOR)\n  - **Move operations**: `mov`\n- **Control flow**:\n  - **Return**: `ret`, `ret_reg`\n- **Extended operations**:\n  - **Immediate moves**: `mov_imm` (for larger constants)\n  - **Shift operations**: `shl` (left shift using multiply)\n- **Register conventions**: Following AAPCS64 (ARM ABI)\n  - **Argument/return registers**: X0-X7\n  - **Caller-saved temporaries**: X8-X18\n  - **Callee-saved registers**: X19-X28\n  - **Special registers**: X29 (FP), X30 (LR), X31 (SP/XZR)\n- **Register usage tracking**: Full tracking support (`register-tracking` feature)\n- **JIT compilation**: Direct function compilation and execution\n\n### Future Architectures\n\nSupport for additional architectures is planned:\n\n- x86-64: Intel/AMD 64-bit instruction set\n\n## Examples\n\n### JIT Compiler Integration\n\n```rust\nuse jit_assembler::riscv::{reg, csr, Riscv64InstructionBuilder};\nuse jit_assembler::riscv64_asm;\n\n// Simple function generator with macro\nfn generate_add_function(a: i16, b: i16) -\u003e Vec\u003cu8\u003e {\n    let instructions = riscv64_asm! {\n        addi(reg::A0, reg::ZERO, a);       // Load first operand into a0\n        addi(reg::A1, reg::ZERO, b);       // Load second operand into a1\n        add(reg::A0, reg::A0, reg::A1);    // Add them, result in a0\n        ret();                             // Return\n    };\n    \n    // Convert to bytes for execution\n    instructions.to_bytes()\n}\n\n// Builder pattern for complex logic\nfn generate_csr_routine() -\u003e Vec\u003cu8\u003e {\n    let mut builder = Riscv64InstructionBuilder::new();\n    \n    builder\n        .csrr(reg::T0, csr::MSTATUS)         // Read current status into t0\n        .addi(reg::T1, reg::T0, 1)           // Modify value in t1\n        .csrrw(reg::A0, csr::MSTATUS, reg::T1); // Write back, old value in a0\n    \n    // Convert to executable code\n    builder.instructions().to_bytes()\n}\n```\n\n### AArch64 Usage\n\n```rust\nuse jit_assembler::aarch64::{reg, Aarch64InstructionBuilder};\nuse jit_assembler::common::InstructionBuilder;\nuse jit_assembler::aarch64_asm;\n\n// Macro style (concise and assembly-like)\nfn generate_aarch64_add_function_macro() -\u003e Vec\u003cu8\u003e {\n    let instructions = aarch64_asm! {\n        add(reg::X0, reg::X0, reg::X1);  // Add first two arguments (X0 + X1 -\u003e X0)\n        ret();                           // Return\n    };\n    instructions\n}\n\n// Builder pattern style\nfn generate_aarch64_add_function() -\u003e Vec\u003cu8\u003e {\n    let mut builder = Aarch64InstructionBuilder::new();\n    \n    builder\n        .add(reg::X0, reg::X0, reg::X1)  // Add first two arguments (X0 + X1 -\u003e X0)\n        .ret();                          // Return\n    \n    builder.instructions().to_bytes()\n}\n\n// More complex AArch64 example with immediate values (macro style)\nfn generate_aarch64_calculation_macro() -\u003e Vec\u003cu8\u003e {\n    aarch64_asm! {\n        mov_imm(reg::X1, 42);            // Load immediate 42 into X1\n        mul(reg::X0, reg::X0, reg::X1);  // Multiply X0 by 42\n        addi(reg::X0, reg::X0, 100);     // Add 100 to result\n        ret();                           // Return\n    }\n}\n\n// More complex AArch64 example with immediate values (builder style)\nfn generate_aarch64_calculation() -\u003e Vec\u003cu8\u003e {\n    let mut builder = Aarch64InstructionBuilder::new();\n    \n    builder\n        .mov_imm(reg::X1, 42)            // Load immediate 42 into X1\n        .mul(reg::X0, reg::X0, reg::X1)  // Multiply X0 by 42\n        .addi(reg::X0, reg::X0, 100)     // Add 100 to result\n        .ret();                          // Return\n    \n    builder.instructions().to_bytes()\n}\n```\n\n### JIT Execution (std-only)\n\nCreate and execute functions directly at runtime:\n\n```rust\nuse jit_assembler::riscv64::{reg, Riscv64InstructionBuilder};\nuse jit_assembler::common::InstructionBuilder;\n\n// Create a JIT function that adds two numbers\nlet add_func = unsafe {\n    Riscv64InstructionBuilder::new()\n        .add(reg::A0, reg::A0, reg::A1) // Add first two arguments\n        .ret()                          // Return result\n        .function::\u003cfn(u64, u64) -\u003e u64\u003e()\n}.expect(\"Failed to create JIT function\");\n\n// Call the JIT function naturally - just like a regular function!\nlet result = add_func.call(10, 20);\nassert_eq!(result, 30);\n\n// Create a function that returns a constant\nlet constant_func = unsafe {\n    Riscv64InstructionBuilder::new()\n        .addi(reg::A0, reg::ZERO, 42)  // Load 42 into return register\n        .ret()                         // Return\n        .function::\u003cfn() -\u003e u64\u003e()\n}.expect(\"Failed to create JIT function\");\n\nlet result = constant_func.call();\nassert_eq!(result, 42);\n```\n\n**Note**: JIT execution requires the target architecture to match the host architecture. RISC-V code will only execute correctly on RISC-V systems.\n\n**Features**:\n- Type-safe function signatures\n- Automatic memory management with `jit-allocator2`\n- Natural function call syntax: `func.call()`, `func.call(arg)`, `func.call(arg1, arg2)`, etc. - just like regular functions!\n- Cross-platform executable memory allocation\n\n## Register Usage Tracking\n\nThe `register-tracking` feature enables comprehensive analysis of register usage patterns in your JIT-compiled code, helping with optimization and ABI compliance.\n\n### Enable Register Tracking\n\nAdd the feature to your `Cargo.toml`:\n\n```toml\n[dependencies]\njit-assembler = { version = \"0.1\", features = [\"register-tracking\"] }\n```\n\n### Usage Example\n\n```rust\nuse jit_assembler::riscv64::{reg, Riscv64InstructionBuilder};\nuse jit_assembler::common::InstructionBuilder;\n\nlet mut builder = Riscv64InstructionBuilder::new();\n\n// Build a function that uses various registers\nbuilder\n    .add(reg::T0, reg::T1, reg::T2)     // T0 written, T1+T2 read\n    .addi(reg::T3, reg::SP, 16)         // T3 written, SP read\n    .mul(reg::A0, reg::A1, reg::A2)     // A0 written, A1+A2 read\n    .ld(reg::S0, reg::T0, 8)            // S0 written, T0 read\n    .sd(reg::SP, reg::S1, -16);         // SP+S1 read\n\n// Analyze register usage\nlet usage = builder.register_usage();\n\nprintln!(\"=== Register Usage Analysis ===\");\nprintln!(\"Total registers used: {}\", usage.register_count());\nprintln!(\"Written registers: {:?}\", usage.written_registers());\nprintln!(\"Read registers: {:?}\", usage.read_registers());\n\n// ABI compliance analysis\nprintln!(\"Caller-saved (written): {:?}\", usage.caller_saved_written());\nprintln!(\"Callee-saved (written): {:?}\", usage.callee_saved_written());\nprintln!(\"Needs stack frame: {}\", usage.needs_stack_frame());\n\n// Detailed breakdown\nlet (caller, callee, special) = usage.count_by_abi_class();\nprintln!(\"ABI breakdown - Caller: {}, Callee: {}, Special: {}\", \n         caller, callee, special);\n```\n\n### Key Features\n\n- **Separate tracking**: Distinguishes between written (def) and read (use) registers\n- **ABI classification**: Automatically categorizes registers as caller-saved, callee-saved, or special-purpose\n- **Stack frame analysis**: Determines if function prologue/epilogue is needed based on callee-saved register usage\n- **Comprehensive coverage**: Tracks all RISC-V instruction types (R, I, S, B, U, J, CSR)\n- **No-std compatible**: Uses `hashbrown` for no-std environments\n\n### Register ABI Classification (RISC-V)\n\n- **Caller-saved**: T0-T6, A0-A7, RA - Can be freely used without preservation\n- **Callee-saved**: S0-S11, SP - Must be saved/restored if modified\n- **Special**: X0 (zero), GP, TP - Require careful handling\n\nThis information is invaluable for:\n- **Register allocation**: Choose optimal registers for variables\n- **ABI compliance**: Ensure proper calling convention adherence\n- **Performance optimization**: Minimize unnecessary register saves/restores\n- **Code analysis**: Understand register pressure and usage patterns\n\n## Merging Instruction Collections\n\nWhen building complex functions, you may need to combine multiple instruction sequences in arbitrary order. For example, you might want to build the main function body first, then add prologue and epilogue code after determining which registers need to be saved.\n\n### Basic Merging\n\n```rust\nuse jit_assembler::riscv64::{reg, Riscv64InstructionBuilder};\nuse jit_assembler::common::InstructionBuilder;\n\n// Build different parts separately\nlet mut prologue = Riscv64InstructionBuilder::new();\nprologue\n    .addi(reg::SP, reg::SP, -16)\n    .sd(reg::SP, reg::RA, 8);\n\nlet mut main_code = Riscv64InstructionBuilder::new();\nmain_code\n    .add(reg::A0, reg::A1, reg::A2)\n    .mul(reg::A0, reg::A0, reg::A3);\n\nlet mut epilogue = Riscv64InstructionBuilder::new();\nepilogue\n    .ld(reg::RA, reg::SP, 8)\n    .addi(reg::SP, reg::SP, 16)\n    .ret();\n\n// Combine them using + operator: prologue + main + epilogue\nlet combined = prologue.instructions() + main_code.instructions() + epilogue.instructions();\n\n// Or use method chaining\nlet mut combined = prologue.instructions();\ncombined += main_code.instructions();\ncombined += epilogue.instructions();\n\n// Convert to executable code\nlet bytes = combined.to_bytes();\n```\n\n### Merging with Register Tracking\n\nWhen the `register-tracking` feature is enabled, you can merge instruction collections while preserving register usage information:\n\n```rust\nuse jit_assembler::riscv64::{reg, Riscv64InstructionBuilder};\nuse jit_assembler::common::{InstructionBuilder, InstructionCollectionWithUsage};\n\n// Build code in separate builders\nlet mut prologue = Riscv64InstructionBuilder::new();\nprologue.sd(reg::SP, reg::S0, -8);  // Save S0\n\nlet mut main_code = Riscv64InstructionBuilder::new();\nmain_code.add(reg::S0, reg::A0, reg::A1);  // Use S0\n\nlet mut epilogue = Riscv64InstructionBuilder::new();\nepilogue.ld(reg::S0, reg::SP, -8);  // Restore S0\n\n// Create tracked collections\nlet prologue_tracked = InstructionCollectionWithUsage::new(\n    prologue.instructions(),\n    prologue.register_usage().clone()\n);\nlet main_tracked = InstructionCollectionWithUsage::new(\n    main_code.instructions(),\n    main_code.register_usage().clone()\n);\nlet epilogue_tracked = InstructionCollectionWithUsage::new(\n    epilogue.instructions(),\n    epilogue.register_usage().clone()\n);\n\n// Merge with register usage tracking\nlet combined = prologue_tracked + main_tracked + epilogue_tracked;\n\n// Access both instructions and register usage\nlet instructions = combined.instructions();\nlet usage = combined.register_usage();\n\nprintln!(\"Combined {} instructions\", instructions.len());\nprintln!(\"Register usage: {}\", usage);\n```\n\nSee `examples/instruction_collection_merge.rs` for a complete working example.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetitstrawberry%2Fjit-assembler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetitstrawberry%2Fjit-assembler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetitstrawberry%2Fjit-assembler/lists"}