{"id":14991146,"url":"https://github.com/acolite-d/llvm-tutorial-in-rust-using-inkwell","last_synced_at":"2025-04-12T03:25:50.457Z","repository":{"id":236812828,"uuid":"793194280","full_name":"acolite-d/llvm-tutorial-in-rust-using-inkwell","owner":"acolite-d","description":"An implementation of Kaleidoscope, the LLVM tutorial model language, written in Rust using Inkwell.","archived":false,"fork":false,"pushed_at":"2024-09-22T18:58:13.000Z","size":1058,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T23:05:09.884Z","etag":null,"topics":["compilers","llvm","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acolite-d.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2024-04-28T17:33:43.000Z","updated_at":"2025-03-13T12:31:55.000Z","dependencies_parsed_at":"2024-05-09T04:22:50.275Z","dependency_job_id":"706f4c7e-923c-4d2f-a27d-badb71d2335b","html_url":"https://github.com/acolite-d/llvm-tutorial-in-rust-using-inkwell","commit_stats":{"total_commits":50,"total_committers":2,"mean_commits":25.0,"dds":0.14,"last_synced_commit":"0e575d158eacfcc0a6110443994992ea551209a7"},"previous_names":["acolite-d/llvm-tutorial-in-rust","acolite-d/llvm-tutorial-in-rust-using-inkwell"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acolite-d%2Fllvm-tutorial-in-rust-using-inkwell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acolite-d%2Fllvm-tutorial-in-rust-using-inkwell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acolite-d%2Fllvm-tutorial-in-rust-using-inkwell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acolite-d%2Fllvm-tutorial-in-rust-using-inkwell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acolite-d","download_url":"https://codeload.github.com/acolite-d/llvm-tutorial-in-rust-using-inkwell/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248511296,"owners_count":21116385,"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","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":["compilers","llvm","rust"],"created_at":"2024-09-24T14:21:35.594Z","updated_at":"2025-04-12T03:25:50.435Z","avatar_url":"https://github.com/acolite-d.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A Rust Rewrite of the LLVM Tutorial, using Inkwell\nOriginal tutorial found here https://llvm.org/docs/tutorial/#kaleidoscope-implementing-a-language-with-llvm. Have rewritten everything up to Part 7. Code is more or less the same, but uses less global state, more modularity, more organization. There are also complete redesigns of certain aspects of the code, including an AST that does not rely on dynamic dispatch, and a robust command line interface that allows users to better visualize the process of compilation.\n\nThe code is material for these blog posts:\n- [Lexer/Parser](https://find.thedoorman.xyz/building-your-own-programming-language-learning-about-compiler-design-llvm-with-a-rust-rewrite-of-the-official-llvm-tutorial-part-1-lexer-parser/)\n- [IR Generation](https://find.thedoorman.xyz/building-your-own-programming-language-learning-about-compiler-design-llvm-with-a-rust-rewrite-of-the-official-llvm-tutorial-part-2-ir-generation/)\n- [Optimization Passes, JIT/AoT Compilation](https://find.thedoorman.xyz/building-your-own-programming-language-with-llvm-rust-part-3-optimization-compilation/)\n- [Language Extensions (if-then-else, for-loops, user-defined operators, mutable variables)](https://find.thedoorman.xyz/building-your-own-programming-language-with-llvm-rust-part-4-control-flow-user-defined-operators-mutability/)\n\n## Building\n\nIn order to build you will need the following:\n\n- Rust Compiler and toolchain, please use https://rustup.rs/ if not already installed.\n- Clang installed, for building shared IO libraries with C. The `build.rs` script can be adapted for GCC, MSVC, or others, but currently hard-coded to invoke `clang` and build a shared library to link against. See `src/clib/io.c`\n- LLVM, either built from source or installed via package manager. Code has been tested with version 17.0.6, but inkwell can support anywhere from version 4-18 at the moment. For users with a system with apt, I recommend using https://apt.llvm.org/, otherwise, follow directions here for building LLVM https://llvm.org/docs/UserGuides.html\n\n**Be sure the installation of LLVM is locatable within your PATH.**\n\nCode is setup as a typical Cargo project.\n\n- Use `cargo b/build` to build.\n- Use `cargo t/test` to run tests, a few are there for the frontend.\n- Use `cargo r/run` to run an interpreter session, JIT compiled. To pass arguments, use `cargo run -- ` followed by whatever flags you want to pass. To compile a file instead of starting REPL, pass a file as a positional argument.\n\n## How to Use\nProject has a command line interface (built via the clap crate).\n\n```sh\ncargo run -- --help\nUsage: kaleidrs [OPTIONS] [FILE]\n\nArguments:\n  [FILE]\n          A positional file containing Kaleidoscope code to compile to object/assembly, if not given, starts interpreter instead\n\nOptions:\n      --target \u003cTARGET\u003e\n        Specifies a non-native target to compile for, can be any one of the CPUs listed in \"llc --version\", or valid target triple\n\n  -O, --opt-level \u003cOPT_LEVEL\u003e\n          What optimization level to pass to LLVM\n          \n          [default: O2]\n\n          Possible values:\n          - O0: No optimization\n          - O1: Less optimization\n          - O2: Default optimization\n          - O3: Aggressive optimization\n\n  -p, --passes \u003cPASSES\u003e\n          Comma separated list of LLVM passes (use opt for a list, also see https://www.llvm.org/docs/Passes.html)\n          \n          [default: instcombine,reassociate,gvn,simplifycfg,mem2reg]\n\n  -o, --output \u003cOUTPUT\u003e\n          When compiling a file, specifies an output file to write to\n          \n          [default: a.out]\n\n  -S, --assembly\n          When compiling a file, specifies the output should be assembly instead of object file\n\n      --inspect-tree\n          When interpreting, prints out AST to stdout after every line entered into interpreter\n\n      --inspect-ir\n          When interpreting, prints out the LLVM intermediate representation after every line entered into interpreter\n\n      --inspect-asm\n          When interpreting, prints out assembly to stdout after every line entered into interpreter\n\n  -h, --help\n          Print help (see a summary with '-h')\n\n  -V, --version\n          Print version\n```\n\n## A Breakdown of the Features of Kaleidoscope\nAs per the LLVM tutorial, all aspects of language, all features, including the fleshed out ones found in the latter chapters, are implemented. For starters, observe this simple REPL session, where each line prints out IR that is JIT compiled and executed directly on the host CPU.\n\n```sh\nkaleidrs$ cargo run -- --inspect-ir\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s\n     Running `target/debug/kaleidrs --inspect-ir`\n\nReady \u003e\u003e 2+2;\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @__anonymous_expr() {\nentry:\n  ret double 4.000000e+00\n}\n\n\nJit compiled and evaluated to: 4\nReady \u003e\u003e (10 - 2) * 5;\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @__anonymous_expr() {\nentry:\n  ret double 4.000000e+01\n}\n\nJit compiled and evaluated to: 40\nReady \u003e\u003e def dub(num) num*2;\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @dub(double %num) {\nentry:\n  %multmp = fmul double %num, 2.000000e+00\n  ret double %multmp\n}\n\nReady \u003e\u003e dub(dub(4));\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @dub(double %num) {\nentry:\n  %multmp = fmul double %num, 2.000000e+00\n  ret double %multmp\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @dub(double 4.000000e+00)\n  %calltmp1 = call double @dub(double %calltmp)\n  ret double %calltmp1\n}\n\nJit compiled and evaluated to: 16\nReady \u003e\u003e \n```\n\n### External Function Declarations\nYou can declare C standard library functions in your program, as long as they only accept double parameters and return double values. \n\n```sh\nkaleidrs$ cargo run -- --inspect-ir\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s\n     Running `target/debug/kaleidrs --inspect-ir`\nReady \u003e\u003e extern sin(a);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndeclare double @sin(double)\n\nReady \u003e\u003e sin(45);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndeclare double @sin(double)\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @sin(double 4.500000e+01)\n  ret double 0x3FEB3A9A073D9B03\n}\n\nJit compiled and evaluated to: 0.8509035245341184\nReady \u003e\u003e extern log(n);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndeclare double @sin(double)\n\ndeclare double @log(double)\n\nReady \u003e\u003e log(22.3);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndeclare double @sin(double)\n\ndeclare double @log(double)\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @log(double 2.230000e+01)\n  ret double 0x4008D6318A5CDF56\n}\n\nJit compiled and evaluated to: 3.104586678466073\nReady \u003e\u003e \n```\n\nIn addition to those, there are two more functions that are compiled with the project that allow for some basic IO. These are found in `src/clib/io.c`. This code is compiled as a shared object and linked along with the Rust crate.\n\n```sh\nReady \u003e\u003e extern putchard(ascii_code);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndeclare double @putchard(double)\n\nReady \u003e\u003e putchard(97);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndeclare double @putchard(double)\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @putchard(double 9.700000e+01)\n  ret double %calltmp\n}\n\na\nJit compiled and evaluated to: 0\nReady \u003e\u003e \n```\n\n### Control Flow\nBasic control flow in form of if-then-else, for-loop expression, just like the original LLVM tutorial implementation.\n\n```sh\nReady \u003e\u003e def double_if_less_than(num bound) if num \u003c bound then num*2 else num;\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @double_if_less_than(double %num, double %bound) {\nentry:\n  %lttmp = fcmp olt double %num, %bound\n  %multmp = fmul double %num, 2.000000e+00\n  %iftmp = select i1 %lttmp, double %multmp, double %num\n  ret double %iftmp\n}\n\nReady \u003e\u003e double_if_less_than(25, 100);\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @double_if_less_than(double %num, double %bound) {\nentry:\n  %lttmp = fcmp olt double %num, %bound\n  %multmp = fmul double %num, 2.000000e+00\n  %iftmp = select i1 %lttmp, double %multmp, double %num\n  ret double %iftmp\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @double_if_less_than(double 2.500000e+01, double 1.000000e+02)\n  ret double %calltmp\n}\n\nJit compiled and evaluated to: 50\nReady \u003e\u003e double_if_less_than(700, 100);\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @double_if_less_than(double %num, double %bound) {\nentry:\n  %lttmp = fcmp olt double %num, %bound\n  %multmp = fmul double %num, 2.000000e+00\n  %iftmp = select i1 %lttmp, double %multmp, double %num\n  ret double %iftmp\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @double_if_less_than(double 7.000000e+02, double 1.000000e+02)\n  ret double %calltmp\n}\n\nJit compiled and evaluated to: 700\n\nReady \u003e\u003e for i = 0, i \u003c 5 in putchard(97+i);\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @double_if_less_than(double %num, double %bound) {\nentry:\n  %lttmp = fcmp olt double %num, %bound\n  %multmp = fmul double %num, 2.000000e+00\n  %iftmp = select i1 %lttmp, double %multmp, double %num\n  ret double %iftmp\n}\n\ndeclare double @putchard(double)\n\ndefine double @__anonymous_expr() {\nentry:\n  br label %loop\n\nloop:                                             ; preds = %loop, %entry\n  %i1 = phi double [ %nextvar, %loop ], [ 0.000000e+00, %entry ]\n  %addtmp = fadd double %i1, 9.700000e+01\n  %calltmp = call double @putchard(double %addtmp)\n  %lttmp = fcmp olt double %i1, 5.000000e+00\n  %nextvar = fadd double %i1, 1.000000e+00\n  br i1 %lttmp, label %loop, label %afterloop\n\nafterloop:                                        ; preds = %loop\n  ret double 0.000000e+00\n}\n\na\nb\nc\nd\ne\nf\nJit compiled and evaluated to: 0\nReady \u003e\u003e \n```\n\n### User-defined Operators\nUsing the \"unary\" and \"binary\" keywords, you can define your own logic upon operators in both unary and binary expressions. There are a set few operators you can implement your custom logic to. They are \"!\", \"|\", \"^\", \"\u0026\", and \":\". Please note that binary operators require a priority.\n\nBelow we implement our own bitwise negation (!) and OR (|) operators.\n\n```\nkaleidrs$ cargo r -- --inspect-ir\n   Compiling kaleidrs v0.1.0 (/home/jdorman/projects/langs-test/kaleidrs)\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.28s\n     Running `target/debug/kaleidrs --inspect-ir`\nReady \u003e\u003e def unary! (V) if V then 0 else 1;\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @\"unary!\"(double %V) {\nentry:\n  %ifcond = fcmp ueq double %V, 0.000000e+00\n  %. = select i1 %ifcond, double 1.000000e+00, double 0.000000e+00\n  ret double %.\n}\n\nReady \u003e\u003e !1;\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @\"unary!\"(double %V) {\nentry:\n  %ifcond = fcmp ueq double %V, 0.000000e+00\n  %. = select i1 %ifcond, double 1.000000e+00, double 0.000000e+00\n  ret double %.\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %unarytmp = call double @\"unary!\"(double 1.000000e+00)\n  ret double %unarytmp\n}\n\nJit compiled and evaluated to: 0\nReady \u003e\u003e !0;\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @\"unary!\"(double %V) {\nentry:\n  %ifcond = fcmp ueq double %V, 0.000000e+00\n  %. = select i1 %ifcond, double 1.000000e+00, double 0.000000e+00\n  ret double %.\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %unarytmp = call double @\"unary!\"(double 0.000000e+00)\n  ret double %unarytmp\n}\n\nJit compiled and evaluated to: 1\nReady \u003e\u003e \n```\n\n```\nkaleidrs$ cargo r -- --inspect-ir\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s\n     Running `target/debug/kaleidrs --inspect-ir`\nReady \u003e\u003e def binary| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0;\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @\"binary|\"(double %LHS, double %RHS) {\nentry:\n  %ifcond = fcmp ueq double %LHS, 0.000000e+00\n  %ifcond5 = fcmp ueq double %RHS, 0.000000e+00\n  %. = select i1 %ifcond5, double 0.000000e+00, double 1.000000e+00\n  %iftmp9 = select i1 %ifcond, double %., double 1.000000e+00\n  ret double %iftmp9\n}\n\nReady \u003e\u003e (1 | 0);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @\"binary|\"(double %LHS, double %RHS) {\nentry:\n  %ifcond = fcmp ueq double %LHS, 0.000000e+00\n  %ifcond5 = fcmp ueq double %RHS, 0.000000e+00\n  %0 = select i1 %ifcond, i1 %ifcond5, i1 false\n  %iftmp9 = select i1 %0, double 0.000000e+00, double 1.000000e+00\n  ret double %iftmp9\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @\"binary|\"(double 1.000000e+00, double 0.000000e+00)\n  ret double %calltmp\n}\n\nJit compiled and evaluated to: 1\nReady \u003e\u003e (0 | 0);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\ntarget datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128\"\n\ndefine double @\"binary|\"(double %LHS, double %RHS) {\nentry:\n  %ifcond = fcmp ueq double %LHS, 0.000000e+00\n  %ifcond5 = fcmp ueq double %RHS, 0.000000e+00\n  %0 = select i1 %ifcond, i1 %ifcond5, i1 false\n  %iftmp9 = select i1 %0, double 0.000000e+00, double 1.000000e+00\n  ret double %iftmp9\n}\n\ndefine double @__anonymous_expr() {\nentry:\n  %calltmp = call double @\"binary|\"(double 0.000000e+00, double 0.000000e+00)\n  ret double %calltmp\n}\n\nJit compiled and evaluated to: 0\nReady \u003e\u003e \n```\n\n### Mutable Variables\nAll variables are mutable, as per the original C++ implementation. User-defined variables also possible with \"var\" keyword. Supply a comma separated list of variables names and possible initializers. The absence of an initializer sets the value to 1.\n\n```\nReady \u003e\u003e var x = 3, y = 3, z in x = z;\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @__anonymous_expr() {\nentry:\n  ret double 1.000000e+00\n}\n\nJit compiled and evaluated to: 1\nReady \u003e\u003e   \n```\n\n### Other Cool Things You Can Do\nThe language itself is no different than the original tutorial implementation, but there is some additional tooling in form of a CLI that allow you to configure different parts of compilation to compare and contrast. One of the more interesting features is the ability to freely inspect the abstract syntax tree, IR, and final assembly code after every line entered in the REPL using the `--inspect-*` flags.\n\n```sh\nkaleidrs$ cargo run -- --inspect-tree --inspect-ir --inspect-asm\n   Compiling kaleidrs v0.1.0 (/home/jdorman/projects/langs-test/kaleidrs)\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.54s\n     Running `target/debug/kaleidrs --inspect-tree --inspect-ir --inspect-asm`\nReady \u003e\u003e def fibonacci(n) if n \u003c 3 then 1 else fibonacci(n-1)+fibonacci(n-2);\nAbstract Syntax Tree Representation:\nFunction {\n    proto: FunctionProto {\n        name: \"fibonacci\",\n        args: [\n            \"n\",\n        ],\n    },\n    body: IfExpr {\n        cond: BinaryExpr {\n            op: Lt,\n            left: VariableExpr(\n                \"n\",\n            ),\n            right: NumberExpr(\n                3.0,\n            ),\n        },\n        then_branch: NumberExpr(\n            1.0,\n        ),\n        else_branch: BinaryExpr {\n            op: Plus,\n            left: CallExpr {\n                callee: \"fibonacci\",\n                args: [\n                    BinaryExpr {\n                        op: Minus,\n                        left: VariableExpr(\n                            \"n\",\n                        ),\n                        right: NumberExpr(\n                            1.0,\n                        ),\n                    },\n                ],\n            },\n            right: CallExpr {\n                callee: \"fibonacci\",\n                args: [\n                    BinaryExpr {\n                        op: Minus,\n                        left: VariableExpr(\n                            \"n\",\n                        ),\n                        right: NumberExpr(\n                            2.0,\n                        ),\n                    },\n                ],\n            },\n        },\n    },\n}\n\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @fibonacci(double %n) {\nentry:\n  %lttmp = fcmp olt double %n, 3.000000e+00\n  br i1 %lttmp, label %ifcont, label %else\n\nelse:                                             ; preds = %entry\n  %subtmp = fadd double %n, -1.000000e+00\n  %calltmp = call double @fibonacci(double %subtmp)\n  %subtmp5 = fadd double %n, -2.000000e+00\n  %calltmp6 = call double @fibonacci(double %subtmp5)\n  %addtmp = fadd double %calltmp, %calltmp6\n  br label %ifcont\n\nifcont:                                           ; preds = %entry, %else\n  %iftmp = phi double [ %addtmp, %else ], [ 1.000000e+00, %entry ]\n  ret double %iftmp\n}\n\nAssembly Representation:\n        .text\n        .file   \"kaleidrs_module\"\n        .section        .rodata.cst8,\"aM\",@progbits,8\n        .p2align        3, 0x0\n.LCPI0_0:\n        .quad   0x3ff0000000000000\n.LCPI0_1:\n        .quad   0x4008000000000000\n.LCPI0_2:\n        .quad   0xbff0000000000000\n.LCPI0_3:\n        .quad   0xc000000000000000\n        .text\n        .globl  fibonacci\n        .p2align        4, 0x90\n        .type   fibonacci,@function\nfibonacci:\n        .cfi_startproc\n        movapd  %xmm0, %xmm1\n        movsd   .LCPI0_1(%rip), %xmm0\n        ucomisd %xmm1, %xmm0\n        jbe     .LBB0_2\n        movsd   .LCPI0_0(%rip), %xmm0\n        retq\n.LBB0_2:\n        subq    $24, %rsp\n        .cfi_def_cfa_offset 32\n        movsd   .LCPI0_2(%rip), %xmm0\n        addsd   %xmm1, %xmm0\n        movsd   %xmm1, 8(%rsp)\n        callq   fibonacci@PLT\n        movsd   %xmm0, 16(%rsp)\n        movsd   8(%rsp), %xmm0\n        addsd   .LCPI0_3(%rip), %xmm0\n        callq   fibonacci@PLT\n        addsd   16(%rsp), %xmm0\n        addq    $24, %rsp\n        .cfi_def_cfa_offset 8\n        retq\n.Lfunc_end0:\n        .size   fibonacci, .Lfunc_end0-fibonacci\n        .cfi_endproc\n\n        .section        \".note.GNU-stack\",\"\",@progbits\n```\n\nYou can also configure the LLVM optimization levels with the `-O{0,1,2,3}, --opt-level` flags, and even pass specific LLVM optimization passes using the `-p, --passes` flag. This is a great feature to use in tandem with the inspect flags to see how passes and levels affect the final product that is run on the CPU in the JIT interpreted session. Great for experimentation.\n\n```sh\nkaleidrs$ cargo run -- --inspect-ir --inspect-asm  --passes \"\"\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s\n     Running `target/debug/kaleidrs --inspect-ir --inspect-asm --passes ''`\nReady \u003e\u003e def fibonacci(n) if n \u003c 3 then 1 else fibonacci(n-1)+fibonacci(n-2);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @fibonacci(double %n) {\nentry:\n  %n1 = alloca double, align 8\n  store double %n, ptr %n1, align 8\n  %n2 = load double, ptr %n1, align 8\n  %lttmp = fcmp olt double %n2, 3.000000e+00\n  %booltmp = uitofp i1 %lttmp to double\n  %iftemp = fcmp oeq double %booltmp, 1.000000e+00\n  br i1 %iftemp, label %then, label %else\n\nthen:                                             ; preds = %entry\n  br label %ifcont\n\nelse:                                             ; preds = %entry\n  %n3 = load double, ptr %n1, align 8\n  %subtmp = fsub double %n3, 1.000000e+00\n  %calltmp = call double @fibonacci(double %subtmp)\n  %n4 = load double, ptr %n1, align 8\n  %subtmp5 = fsub double %n4, 2.000000e+00\n  %calltmp6 = call double @fibonacci(double %subtmp5)\n  %addtmp = fadd double %calltmp, %calltmp6\n  br label %ifcont\n\nifcont:                                           ; preds = %else, %then\n  %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ]\n  ret double %iftmp\n}\n\nAssembly Representation:\n        .text\n        .file   \"kaleidrs_module\"\n        .section        .rodata.cst8,\"aM\",@progbits,8\n        .p2align        3, 0x0\n.LCPI0_0:\n        .quad   0x3ff0000000000000\n.LCPI0_1:\n        .quad   0x4008000000000000\n.LCPI0_2:\n        .quad   0xbff0000000000000\n.LCPI0_3:\n        .quad   0xc000000000000000\n        .text\n        .globl  fibonacci\n        .p2align        4, 0x90\n        .type   fibonacci,@function\nfibonacci:\n        .cfi_startproc\n        subq    $24, %rsp\n        .cfi_def_cfa_offset 32\n        movapd  %xmm0, %xmm1\n        movsd   %xmm0, 8(%rsp)\n        cmpltsd .LCPI0_1(%rip), %xmm1\n        movsd   .LCPI0_0(%rip), %xmm0\n        andpd   %xmm0, %xmm1\n        ucomisd %xmm0, %xmm1\n        jne     .LBB0_1\n        jp      .LBB0_1\n        addq    $24, %rsp\n        .cfi_def_cfa_offset 8\n        retq\n.LBB0_1:\n        .cfi_def_cfa_offset 32\n        movsd   8(%rsp), %xmm0\n        addsd   .LCPI0_2(%rip), %xmm0\n        callq   fibonacci@PLT\n        movsd   %xmm0, 16(%rsp)\n        movsd   8(%rsp), %xmm0\n        addsd   .LCPI0_3(%rip), %xmm0\n        callq   fibonacci@PLT\n        addsd   16(%rsp), %xmm0\n        addq    $24, %rsp\n        .cfi_def_cfa_offset 8\n        retq\n.Lfunc_end0:\n        .size   fibonacci, .Lfunc_end0-fibonacci\n        .cfi_endproc\n\n        .section        \".note.GNU-stack\",\"\",@progbits\n\n\nReady \u003e\u003e ^C\nkaleidrs$ cargo run -- --inspect-ir --inspect-asm  --passes \"instcombine,reassociate,gvn,simplifycfg,mem2reg\"\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s\n     Running `target/debug/kaleidrs --inspect-ir --inspect-asm --passes instcombine,reassociate,gvn,simplifycfg,mem2reg`\nReady \u003e\u003e def fibonacci(n) if n \u003c 3 then 1 else fibonacci(n-1)+fibonacci(n-2);\nLLVM IR Representation:\n; ModuleID = 'kaleidrs_module'\nsource_filename = \"kaleidrs_module\"\n\ndefine double @fibonacci(double %n) {\nentry:\n  %lttmp = fcmp olt double %n, 3.000000e+00\n  br i1 %lttmp, label %ifcont, label %else\n\nelse:                                             ; preds = %entry\n  %subtmp = fadd double %n, -1.000000e+00\n  %calltmp = call double @fibonacci(double %subtmp)\n  %subtmp5 = fadd double %n, -2.000000e+00\n  %calltmp6 = call double @fibonacci(double %subtmp5)\n  %addtmp = fadd double %calltmp, %calltmp6\n  br label %ifcont\n\nifcont:                                           ; preds = %entry, %else\n  %iftmp = phi double [ %addtmp, %else ], [ 1.000000e+00, %entry ]\n  ret double %iftmp\n}\n\nAssembly Representation:\n        .text\n        .file   \"kaleidrs_module\"\n        .section        .rodata.cst8,\"aM\",@progbits,8\n        .p2align        3, 0x0\n.LCPI0_0:\n        .quad   0x3ff0000000000000\n.LCPI0_1:\n        .quad   0x4008000000000000\n.LCPI0_2:\n        .quad   0xbff0000000000000\n.LCPI0_3:\n        .quad   0xc000000000000000\n        .text\n        .globl  fibonacci\n        .p2align        4, 0x90\n        .type   fibonacci,@function\nfibonacci:\n        .cfi_startproc\n        movapd  %xmm0, %xmm1\n        movsd   .LCPI0_1(%rip), %xmm0\n        ucomisd %xmm1, %xmm0\n        jbe     .LBB0_2\n        movsd   .LCPI0_0(%rip), %xmm0\n        retq\n.LBB0_2:\n        subq    $24, %rsp\n        .cfi_def_cfa_offset 32\n        movsd   .LCPI0_2(%rip), %xmm0\n        addsd   %xmm1, %xmm0\n        movsd   %xmm1, 8(%rsp)\n        callq   fibonacci@PLT\n        movsd   %xmm0, 16(%rsp)\n        movsd   8(%rsp), %xmm0\n        addsd   .LCPI0_3(%rip), %xmm0\n        callq   fibonacci@PLT\n        addsd   16(%rsp), %xmm0\n        addq    $24, %rsp\n        .cfi_def_cfa_offset 8\n        retq\n.Lfunc_end0:\n        .size   fibonacci, .Lfunc_end0-fibonacci\n        .cfi_endproc\n\n        .section        \".note.GNU-stack\",\"\",@progbits\n\n\nReady \u003e\u003e \n```\n\nIn addition, the `--target` flag will allow you to cross compile to whatever CPU or target triple LLVM supports. You can then compare the same program compiled to different targets, and see optimizations take place over various CPU architectures. From ARM to RISC-V to WASM to SPARC and everything in between. Not just the native architecture your computer runs on.\n\n```\nkaleidrs$ cat test.ks\ndef fibonacci(n)\n    if n \u003c 3 then \n        1 \n    else \n        fibonacci(n-1) + fibonacci(n-2)\n;\n\nfibonacci(10);\nkaleidrs$ cargo run -- test.ks --target armv7a-none-eabi -S -o test.S\n   Compiling kaleidrs v0.1.0 (/home/jdorman/projects/langs-test/kaleidrs)\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.65s\n     Running `target/debug/kaleidrs test.ks --target armv7a-none-eabi -S -o test.S`\nkaleidrs$ cat test.S\n        .text\n        .syntax unified\n        .eabi_attribute 67, \"2.09\"\n        .eabi_attribute 6, 10\n        .eabi_attribute 7, 65\n        .eabi_attribute 8, 1\n        .eabi_attribute 9, 2\n        .fpu    vfpv3\n        .eabi_attribute 34, 1\n        .eabi_attribute 17, 1\n        .eabi_attribute 20, 1\n        .eabi_attribute 21, 0\n        .eabi_attribute 23, 3\n        .eabi_attribute 24, 1\n        .eabi_attribute 25, 1\n        .eabi_attribute 38, 1\n        .eabi_attribute 14, 0\n        .file   \"kaleidrs_module\"\n        .globl  fibonacci\n        .p2align        2\n        .type   fibonacci,%function\n        .code   32\nfibonacci:\n        .fnstart\n        push    {r11, lr}\n        vpush   {d8}\n        vmov.f64        d16, #3.000000e+00\n        vmov    d8, r0, r1\n        vcmp.f64        d8, d16\n        vmrs    APSR_nzcv, fpscr\n        bpl     .LBB0_2\n        vmov.f64        d16, #1.000000e+00\n        b       .LBB0_3\n.LBB0_2:\n        vmov.f64        d16, #-1.000000e+00\n        vadd.f64        d16, d8, d16\n        vmov    r0, r1, d16\n        bl      fibonacci\n        vmov.f64        d16, #-2.000000e+00\n        vadd.f64        d16, d8, d16\n        vmov    r2, r3, d16\n        vmov    d8, r0, r1\n        mov     r0, r2\n        mov     r1, r3\n        bl      fibonacci\n        vmov    d16, r0, r1\n        vadd.f64        d16, d8, d16\n.LBB0_3:\n        vmov    r0, r1, d16\n        vpop    {d8}\n        pop     {r11, pc}\n.Lfunc_end0:\n        .size   fibonacci, .Lfunc_end0-fibonacci\n        .fnend\n\n        .globl  __anonymous_expr\n        .p2align        2\n        .type   __anonymous_expr,%function\n        .code   32\n__anonymous_expr:\n        .fnstart\n        push    {r11, lr}\n        vmov.f64        d16, #1.000000e+01\n        vmov    r0, r1, d16\n        bl      fibonacci\n        pop     {r11, pc}\n.Lfunc_end1:\n        .size   __anonymous_expr, .Lfunc_end1-__anonymous_expr\n        .fnend\n\n        .section        \".note.GNU-stack\",\"\",%progbits\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facolite-d%2Fllvm-tutorial-in-rust-using-inkwell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facolite-d%2Fllvm-tutorial-in-rust-using-inkwell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facolite-d%2Fllvm-tutorial-in-rust-using-inkwell/lists"}