From 9ad9aba8f77ae70c824febd9a890839218f7f598 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Tue, 8 Oct 2024 00:15:15 +0200 Subject: [PATCH 01/22] docs: add ALU design This document captures research done in #27. Signed-off-by: Wojciech Zmuda --- docs/ALU Design.md | 758 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 758 insertions(+) create mode 100644 docs/ALU Design.md diff --git a/docs/ALU Design.md b/docs/ALU Design.md new file mode 100644 index 0000000..10f7ebb --- /dev/null +++ b/docs/ALU Design.md @@ -0,0 +1,758 @@ +# ALU design + +This document describes the research done for +[#27 Design ALU](https://github.com/reilabs/llvm-to-cairo/issues/27). + +The first part, **Research**, describes selected features of LLVM IR, Rust and Cairo (both the +virtual machine and the programming language), that impact the way we must handle arithmetic and +logic operations. The second part, **Design**, specifies decisions made with regard to the shape of +the ALU component of the project. + +Most of the design decision are based on the outcomes of experiments described in the research part. +Some decisions are made arbitrarily. All decisions are subject to change, especially if more +information is gathered during the implementation phase. Nevertheless, we do not expect the final +shape of ALU to be much different from this design document. Should design changes occur, this +document will be updated. + +## Research + +ALU will have to target two concepts of LLVM IR: instructions and intrinsics. + +### Instructions + +An example of IR using the `add` instruction for arithmetic operations: + +```llvm +define i32 @add(i32 %a, i32 %b) { +entry: + %sum = add i32 %a, %b ; Add the two integers + ret i32 %sum ; Return the result +} +``` + +All the instructions we need to look for are already captured by our +[polyfill listing](https://www.notion.so/reilabs/LLVM-IR-Polyfills-10ed2f80c87480cb8694f581b726808c): +`add`, `sub`, `mul`, `udiv`, `sdiv`, `urem`, `srem`, `shl`, `lshr`, `ashr`, `and`, `or`, `xor`. + +#### Keywords + +An instruction is not just its opcode and operands, e.g. `$3 = add $1, $2`, but there are some +keywords modifying its behavior. An +[example for `add`](https://llvm.org/docs/LangRef.html#add-instruction): + +```llvm + = add , ; yields ty:result + = add nuw , ; yields ty:result + = add nsw , ; yields ty:result + = add nuw nsw , ; yields ty:result +``` + +- `` is type, e.g. `i32`, +- `nuw` - No Unsigned Wrap, +- `nsw` - No Signed Wrap. + +#### Poison + +In the example of `add`, if `nuw` or `nsw` keywords occur, they guarantee specific behavior, i.e. no +(un)signed overflow. However, if the operands cause the overflow, the instruction returns a poison, +which is an equivalent of a value indicating undefined behavior that can propagate throughout the +program. + +[According to the experiment](https://github.com/reilabs/llvm-to-cairo/issues/27#issuecomment-2397645979), +LLVM does not seem to emit such instructions from the Rust code, so the initial version of ALU will +not handle `nuw`, `nsw` or other keywords in any specific way. + +### Intrinsics + +The example above includes the following line: + +```llvm +%0 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %left, i64 %right), !dbg !17 +``` + +Unlike the previous example, this snippet does nto contain the `add` instruction. The adding +operation is done by an intrinsic named `llvm.uadd.with.overflow.i64`, which is called with the +`call` instruction. The intrinsic is defined in the LLVM codebase and its source code does not make +it into the `.ll` file produced out of the adding operation in Rust code. + +The LLVM Language Reference Manual has an extensive list of intrinsics. Here's the example of +[`llvm.uadd.with.overflow.`](https://llvm.org/docs/LangRef.html#llvm-uadd-with-overflow-intrinsics). + +### Data types + +This ALU will support only integers. Floating point numbers are out of scope of this document. + +#### Integers + +LLVM IR supports integers of arbitrary width. A general syntax for an integer type is `iN`, where +`N` can be anything from 1 to 2^32. Since LLVM does not have a dedicated type for boolean values, +`i1` is used instead. + +The Cairo VM internally operates on 252-bit-long field elements - `felt252`. On the higher level of +abstraction, the Cairo language supports +[integers of specific lengths](https://book.cairo-lang.org/ch02-02-data-types.html): 8 bit, 16 bit, +32 bit, 64 bit, 128 bit and 256 bit. Cairo also supports booleans. + +[Rust supports integers of width from 8 to 128 bit](https://doc.rust-lang.org/book/ch03-02-data-types.html) +with the same increment Cairo does, plus architecture-dependent `isize` and `usize`. Rust also +supports booleans. + +The Cairo VM does not have a classical registers of length constrained by the hardware. Therefore +there is no obvious indicator of how long `usize`/`isize` should be on that target. Since from the +LLVM point of view a pointer must have a finite size, this decision must be made based on some other +feature of the architecture. We have evaluated the following choices: + +- The Cairo language already has 32 bit `usize`, so we can follow this approach, making `usize` and + `isize` also 32 bit, +- The architecture's natural word size is 252 bit, being the length of the field element. It may be + reasonable to set `usize` and `isize` length to 252 bit, +- 256 bit is the next power-of-2 after 252. Having `usize` and `isize` 256 bit long leaves 4 extra + bits that may be used to keep some metadata. + +Ultimately the size of `usize` and `isize` has been decided to be 64 bits, which is neither of the +above possibilities. This length is a consequence of using the `aarch64-unknown-none-softfloat` +target triple. The choice of the triple determines the length of the pointer which in turn +determines the length of `usize`. This target triple is a temporary choice before a custom target +triple is proposed. It has been chosen for its soft float support and no host operating system. The +pointer length is just one of its parameters we accept on this stage of the project. + +Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 +bits. + +#### Pointers + +LLVM IR has only one generic pointer type - `ptr`, which works as a rough equivalent of the `void *` +in C. Type-specific pointers (e.g. equivalent of C's `int`) existed, but are now deprecated. +Therefore, we expect to see in the input IR only the generic `ptr` pointer. + +Not only Rust and the Cairo language support a generic pointer type, their support for pointer does +not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. Both +languages operates on strongly typed smart pointers, that handle, under the hood, their own memory. + +Based on these observations, ALU operations must be strongly typed, by the limitation of the +language it will be implemented in. When the input IR will be parsed, it generic pointer types must +be inferred from the context, to allow matching with the proper implementation. + +#### Vectors + +Neither the Cairo VM, Cairo language nor no-std Rust have support for vector operations. + +LLVM IR has vectors as first class citizens. However, +_[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#t-vector)_. +If Cairo target definition supplied to `rustc` will not suggest the existence of vector extension on +the target platform, we do not expect any vector intrinsics to appear in the IR. Therefore, vector +support is not planned in the initial phase of the project. + +#### Type conversion + +Cairo does not have Rust's `as` keyword, so it's not possible to do e.g. `let a = b as u32` given +`b` is a `u64`. + +An equivalent operation in Cairo is `let a: u32: b.try_into().unwrap();`. This approach has two +disadvantages: + +- it will panic if the value of `b` is larger than `0xFFFFFFFF`, +- there is no automatic wraparound as in the case of `as`. + +Should type conversion be necessary in the implementation of the operations, it will need to handle +the type conversion with `try_into()` and manual recover from errors: + +```rust +let result: u32 = match sum.try_into() { + Ok(val) => val, + Err(_) => { + // Handle the wraparound manually + } +}; +``` + +### Statefulness + +A real Arithmetic-Logic Unit in a CPU is a finite state machine. Some states, interesting from the +programmer's point of view, can be captured as contents of the CPU registers. Such state is e.g. the +next instruction (as pointed to by Program Counter or its equivalent), values of operands stored in +two general purpose registers or the result of the last operation stored in another GP register and +a flag register, where specific bits signal certain conditions (e.g. the result being zero or an +integer overflow). + +The LLVM-to-Cairo infrastructure needs to deliver pieces of code translating generic LLVM arithmetic +operations to their counterparts specific to the Cairo VM architecture. This translation will be +done on the code level, during one of the LLVM-to-Cairo pipeline stages. Namely, this will be not +runtime translation, but rather a compilation time one. Therefore, there is no global state to be +managed during that time. + +Additionally, it has been noticed +[in one of the experiments](https://github.com/reilabs/llvm-to-cairo/issues/27#issuecomment-2391893640), +that LLVM IR follows the same principle of not managing the internal state of arithmetic operations. +This is either done by + +- returning a tuple containing both the operation result and the state information: + +```llvm +%0 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %left, i64 %right), !dbg !17 +%_3.0 = extractvalue { i64, i1 } %0, 0, !dbg !17 +%_3.1 = extractvalue { i64, i1 } %0, 1, !dbg !17 +br i1 %_3.1, label %panic, label %bb1, !dbg !17 +``` + +- by demanding that input data is correct and producing undefined behavior otherwise, +- by emitting poison values, if producing a correct value is not possible. + +Based on these observations, we decide to deliver the ALU as a collection of stateless arithmetic +operations. + +### Tests + +Cairo has an +[integrated test framework](https://book.cairo-lang.org/ch10-01-how-to-write-tests.html), similar to +the one offered by Rust. Our ALU implementation will then come with a test suite to verify that we +implement the desired behavior, e.g. to make sure we indicate overflow on obvious situations like +`0xFFFFFFFF + 1` for a `u32` add. + +## Design + +### Overview + +The ALU will be implemented as a source code written in +[Cairo](https://book.cairo-lang.org/title-page.html). During the +[LLVM-to-Cairo compilation pipeline](https://www.notion.so/reilabs/System-Architecture-113d2f80c874802b8480d997347933a2?pvs=4) +it will be translated to `FlatLowered` objects. Then, on the linking phase, arithmetic operations +from `FLIR` objects created from the input LLVM IR will be linked with their Cairo implementations. + +As discussed in the relevant section of the Research part, each operation will be an independent, +stateless block of code composed of a single Cairo +[function](https://book.cairo-lang.org/ch02-03-functions.html), which is an equivalent concept of a +function in any other procedural programming language. + +Each function will follow the semantics of its LLVM IR counterpart. This requires: + +- accepting the same number of arguments, of the same type and in the same order as the original + operation's operands, +- returning the same number or values, of the same type and in the same order as the original + operation. + +Each function will follow the naming scheme described in the relevant section below. + +### Naming convention + +#### Instruction polyfills + +Name template: `__llvm___`. In case the instruction works with both operands of +the same data type, the template degrades to `__llvm___`. + +In the example of `inst i32 %a, %b`, the polyfill would be named `__llvm_inst_i32_i32`. + +If `` is `i1`, it is translated into `bool`. For an example instruction `inst i1 %a, %b`, the +polyfill would be named `__llvm_inst_bool_bool`. + +In case the instruction works with pointer type, the generic LLVM keyword `ptr` is translated to +`p`. For an example instruction `inst ptr %a, i8 %b`, where `%a` is a pointer to the value of +the same type as `%b`, the polyfill would be named `__llvm_inst_pi8_i8`. + +#### Intrinsic polyfills + +Name template: `____`, where type `` indicates every +argument accepted by the intrinsic. + +In the example of `llvm.uadd.with.overflow.i64(i64 %left, i64 %right)`, the polyfill would be named +`__llvm_uadd_with_overflow_i64_i64`. + +All other naming rules defined for instructions also apply to intrinsics. + +### Operations + +The list below specifies all implementations of arithmetic operations that will be provided by ALU. +The list is divided to two parts: + +- implementations emulating LLVM instructions, +- implementations emulating LLVM intrinsics. + +Implementations for every supported integer lengths are specified. Their names follow the naming +convention explained in the section above. Each instruction or intrinsic name is a link to the +relevant part of the LLVM Language Reference Manual. + +#### Based on instructions + +- [`add`](https://llvm.org/docs/LangRef.html#add-instruction): + - `__llvm_add_i8_i8 -> i8` + - `__llvm_add_i16_i16 -> i16` + - `__llvm_add_i32_i32 -> i32` + - `__llvm_add_i64_i64 -> i64` + - `__llvm_add_i128_i128 -> i128` +- [`sub`](https://llvm.org/docs/LangRef.html#sub-instruction): + - `__llvm_sub_i8_i8 -> i8` + - `__llvm_sub_i16_i16 -> i16` + - `__llvm_sub_i32_i32 -> i32` + - `__llvm_sub_i64_i64 -> i64` + - `__llvm_sub_i128_i128 -> i128` +- [`mul`](https://llvm.org/docs/LangRef.html#mul-instruction): + - `__llvm_mul_i8_i8 -> i8` + - `__llvm_mul_i16_i16 -> i16` + - `__llvm_mul_i32_i32 -> i32` + - `__llvm_mul_i64_i64 -> i64` + - `__llvm_mul_i128_i128 -> i128` +- [`udiv`](https://llvm.org/docs/LangRef.html#udiv-instruction): + - `__llvm_udiv_i8_i8 -> i8` + - `__llvm_udiv_i16_i16 -> i16` + - `__llvm_udiv_i32_i32 -> i32` + - `__llvm_udiv_i64_i64 -> i64` + - `__llvm_udiv_i128_i128 -> i128` +- [`sdiv`](https://llvm.org/docs/LangRef.html#sdiv-instruction): + - `__llvm_sdiv_i8_i8 -> i8` + - `__llvm_sdiv_i16_i16 -> i16` + - `__llvm_sdiv_i32_i32 -> i32` + - `__llvm_sdiv_i64_i64 -> i64` + - `__llvm_sdiv_i128_i128 -> i128` +- [`urem`](https://llvm.org/docs/LangRef.html#urem-instruction): + - `__llvm_urem_i8_i8 -> i8` + - `__llvm_urem_i16_i16 -> i16` + - `__llvm_urem_i32_i32 -> i32` + - `__llvm_urem_i64_i64 -> i64` + - `__llvm_urem_i128_i128 -> i128` +- [`srem`](https://llvm.org/docs/LangRef.html#srem-instruction): + - `__llvm_srem_i8_i8 -> i8` + - `__llvm_srem_i16_i16 -> i16` + - `__llvm_srem_i32_i32 -> i32` + - `__llvm_srem_i64_i64 -> i64` + - `__llvm_srem_i128_i128 -> i128` +- [`shl`](https://llvm.org/docs/LangRef.html#shl-instruction): + - `__llvm_shl_i8_i8 -> i8` + - `__llvm_shl_i16_i16 -> i16` + - `__llvm_shl_i32_i32 -> i32` + - `__llvm_shl_i64_i64 -> i64` + - `__llvm_shl_i128_i128 -> i128` +- [`lshr`](https://llvm.org/docs/LangRef.html#lshr-instruction): + - `__llvm_lshr_i8_i8 -> i8` + - `__llvm_lshr_i16_i16 -> i16` + - `__llvm_lshr_i32_i32 -> i32` + - `__llvm_lshr_i64_i64 -> i64` + - `__llvm_lshr_i128_i128 -> i128` +- [`ashr`](https://llvm.org/docs/LangRef.html#ashr-instruction): + - `__llvm_ashr_i8_i8 -> i8` + - `__llvm_ashr_i16_i16 -> i16` + - `__llvm_ashr_i32_i32 -> i32` + - `__llvm_ashr_i64_i64 -> i64` + - `__llvm_ashr_i128_i128 -> i128` +- [`and`](https://llvm.org/docs/LangRef.html#and-instruction): + - `__llvm_and_bool_bool -> bool` + - `__llvm_and_i8_i8 -> i8` + - `__llvm_and_i16_i16 -> i16` + - `__llvm_and_i32_i32 -> i32` + - `__llvm_and_i64_i64 -> i64` + - `__llvm_and_i128_i128 -> i128` +- [`or`](https://llvm.org/docs/LangRef.html#or-instruction): + - `__llvm_or_bool_bool -> bool` + - `__llvm_or_i8_i8 -> i8` + - `__llvm_or_i16_i16 -> i16` + - `__llvm_or_i32_i32 -> i32` + - `__llvm_or_i64_i64 -> i64` + - `__llvm_or_i128_i128 -> i128` +- [`xor`](https://llvm.org/docs/LangRef.html#xor-instruction): + - `__llvm_xor_bool_bool -> bool` + - `__llvm_xor_i8_i8 -> i8` + - `__llvm_xor_i16_i16 -> i16` + - `__llvm_xor_i32_i32 -> i32` + - `__llvm_xor_i64_i64 -> i64` + - `__llvm_xor_i128_i128 -> i128` +- [`cmpxchg`](https://llvm.org/docs/LangRef.html#cmpxchg-instruction): + - Unlike the previous instructions, `cmpxchg` accepts three arguments. Some of the arguments can + be integers or pointers. Pointer arguments have the `p` prefix, e.g. `pi8` is a pointer to + `int8`. + - Unlike the previous instructions, `cmpxchg` returns a tuple: the first value is the original + value at the memory location pointed to by the first argument (before exchange) and the second + value indicates if the value loaded equals the value of the second argument. + - `__llvm_cmpxchg_pi8_i8_i8 -> (i8, bool)` + - `__llvm_cmpxchg_pi8_pi8_pi8 -> (i8, bool)` + - `__llvm_cmpxchg_pi16_i16_i16 -> (i16, bool)` + - `__llvm_cmpxchg_pi16_pi16_pi16 -> (i16, bool)` + - `__llvm_cmpxchg_pi32_i32_i32 -> (i32, bool)` + - `__llvm_cmpxchg_pi32_pi32_pi32 -> (i32, bool)` + - `__llvm_cmpxchg_pi64_i64_i64 -> (i64, bool)` + - `__llvm_cmpxchg_pi64_pi64_pi64 -> (i64, bool)` + - `__llvm_cmpxchg_pi128_i128_i128 -> (i128, bool)` + - `__llvm_cmpxchg_pi128_pi128_pi128 -> (i128, bool)` +- [`trunc .. to`](https://llvm.org/docs/LangRef.html#trunc-to-instruction): + - `__llvm_trunc_i128_to_i64 -> i64` + - `__llvm_trunc_i128_to_i32 -> i32` + - `__llvm_trunc_i128_to_i16 -> i16` + - `__llvm_trunc_i128_to_i8 -> i8` + - `__llvm_trunc_i128_to_bool -> bool` + - `__llvm_trunc_i64_to_i32 -> i32` + - `__llvm_trunc_i64_to_i16 -> i16` + - `__llvm_trunc_i64_to_i8 -> i8` + - `__llvm_trunc_i64_to_bool -> bool` + - `__llvm_trunc_i32_to_i16 -> i16` + - `__llvm_trunc_i32_to_i8 -> i8` + - `__llvm_trunc_i32_to_bool -> bool` + - `__llvm_trunc_i16_to_i8 -> i8` + - `__llvm_trunc_i16_to_bool -> bool` + - `__llvm_trunc_i8_to_bool -> bool` +- [`zext .. to`](https://llvm.org/docs/LangRef.html#zext-to-instruction): + - `__llvm_zext_bool_to_i128 -> i128` + - `__llvm_zext_bool_to_i64 -> i64` + - `__llvm_zext_bool_to_i32 -> i32` + - `__llvm_zext_bool_to_i16 -> i16` + - `__llvm_zext_bool_to_i8 -> i8` + - `__llvm_zext_i8_to_i128 -> i128` + - `__llvm_zext_i8_to_i64 -> i64` + - `__llvm_zext_i8_to_i32 -> i32` + - `__llvm_zext_i8_to_i16 -> i16` + - `__llvm_zext_i16_to_i128 -> i128` + - `__llvm_zext_i16_to_i64 -> i64` + - `__llvm_zext_i16_to_i32 -> i32` + - `__llvm_zext_i32_to_i128 -> i128` + - `__llvm_zext_i32_to_i64 -> i64` + - `__llvm_zext_i64_to_i128 -> i128` +- [`sext .. to`](https://llvm.org/docs/LangRef.html#sext-to-instruction): + - `__llvm_sext_bool_to_i128 -> i128` + - `__llvm_sext_bool_to_i64 -> i64` + - `__llvm_sext_bool_to_i32 -> i32` + - `__llvm_sext_bool_to_i16 -> i16` + - `__llvm_sext_bool_to_i8 -> i8` + - `__llvm_sext_i8_to_i128 -> i128` + - `__llvm_sext_i8_to_i64 -> i64` + - `__llvm_sext_i8_to_i32 -> i32` + - `__llvm_sext_i8_to_i16 -> i16` + - `__llvm_sext_i16_to_i128 -> i128` + - `__llvm_sext_i16_to_i64 -> i64` + - `__llvm_sext_i16_to_i32 -> i32` + - `__llvm_sext_i32_to_i128 -> i128` + - `__llvm_sext_i32_to_i64 -> i64` + - `__llvm_sext_i64_to_i128 -> i128` +- [`ptrtoint .. to`](https://llvm.org/docs/LangRef.html#ptrtoint-to-instruction): + - `__llvm_ptrtoint_pbool_to_bool -> bool` + - `__llvm_ptrtoint_pbool_to_i8 -> i8` + - `__llvm_ptrtoint_pbool_to_i16 -> i16` + - `__llvm_ptrtoint_pbool_to_i32 -> i32` + - `__llvm_ptrtoint_pbool_to_i64 -> i64` + - `__llvm_ptrtoint_pbool_to_i128 -> i128` + - `__llvm_ptrtoint_pi8_to_bool -> bool` + - `__llvm_ptrtoint_pi8_to_i8 -> i8` + - `__llvm_ptrtoint_pi8_to_i16 -> i16` + - `__llvm_ptrtoint_pi8_to_i32 -> i32` + - `__llvm_ptrtoint_pi8_to_i64 -> i64` + - `__llvm_ptrtoint_pi8_to_i128 -> i128` + - `__llvm_ptrtoint_pi16_to_bool -> bool` + - `__llvm_ptrtoint_pi16_to_i8 -> i8` + - `__llvm_ptrtoint_pi16_to_i16 -> i16` + - `__llvm_ptrtoint_pi16_to_i32 -> i32` + - `__llvm_ptrtoint_pi16_to_i64 -> i64` + - `__llvm_ptrtoint_pi16_to_i128 -> i128` + - `__llvm_ptrtoint_pi32_to_bool -> bool` + - `__llvm_ptrtoint_pi32_to_i8 -> i8` + - `__llvm_ptrtoint_pi32_to_i16 -> i16` + - `__llvm_ptrtoint_pi32_to_i32 -> i32` + - `__llvm_ptrtoint_pi32_to_i64 -> i64` + - `__llvm_ptrtoint_pi32_to_i128 -> i128` + - `__llvm_ptrtoint_pi64_to_bool -> bool` + - `__llvm_ptrtoint_pi64_to_i8 -> i8` + - `__llvm_ptrtoint_pi64_to_i16 -> i16` + - `__llvm_ptrtoint_pi64_to_i32 -> i32` + - `__llvm_ptrtoint_pi64_to_i64 -> i64` + - `__llvm_ptrtoint_pi64_to_i128 -> i128` + - `__llvm_ptrtoint_pi128_to_bool -> bool` + - `__llvm_ptrtoint_pi128_to_i8 -> i8` + - `__llvm_ptrtoint_pi128_to_i16 -> i16` + - `__llvm_ptrtoint_pi128_to_i32 -> i32` + - `__llvm_ptrtoint_pi128_to_i64 -> i64` + - `__llvm_ptrtoint_pi128_to_i128 -> i128` +- [`inttoptr .. to`](https://llvm.org/docs/LangRef.html#inttoptr-to-instruction): + - `__llvm_inttoptr_bool_to_pbool -> pbool` + - `__llvm_inttoptr_bool_to_pi8 -> pi8` + - `__llvm_inttoptr_bool_to_pi16 -> pi16` + - `__llvm_inttoptr_bool_to_pi32 -> pi32` + - `__llvm_inttoptr_bool_to_pi64 -> pi64` + - `__llvm_inttoptr_bool_to_pi128 -> pi128` + - `__llvm_inttoptr_i8_to_pbool -> pbool` + - `__llvm_inttoptr_i8_to_pi8 -> pi8` + - `__llvm_inttoptr_i8_to_pi16 -> pi16` + - `__llvm_inttoptr_i8_to_pi32 -> pi32` + - `__llvm_inttoptr_i8_to_pi64 -> pi64` + - `__llvm_inttoptr_i8_to_pi128 -> pi128` + - `__llvm_inttoptr_i16_to_pbool -> pbool` + - `__llvm_inttoptr_i16_to_pi8 -> pi8` + - `__llvm_inttoptr_i16_to_pi16 -> pi16` + - `__llvm_inttoptr_i16_to_pi32 -> pi32` + - `__llvm_inttoptr_i16_to_pi64 -> pi64` + - `__llvm_inttoptr_i16_to_pi128 -> pi128` + - `__llvm_inttoptr_i32_to_pbool -> pbool` + - `__llvm_inttoptr_i32_to_pi8 -> pi8` + - `__llvm_inttoptr_i32_to_pi16 -> pi16` + - `__llvm_inttoptr_i32_to_pi32 -> pi32` + - `__llvm_inttoptr_i32_to_pi64 -> pi64` + - `__llvm_inttoptr_i32_to_pi128 -> pi128` + - `__llvm_inttoptr_i64_to_pbool -> pbool` + - `__llvm_inttoptr_i64_to_pi8 -> pi8` + - `__llvm_inttoptr_i64_to_pi16 -> pi16` + - `__llvm_inttoptr_i64_to_pi32 -> pi32` + - `__llvm_inttoptr_i64_to_pi64 -> pi64` + - `__llvm_inttoptr_i64_to_pi128 -> pi128` + - `__llvm_inttoptr_i128_to_pbool -> pbool` + - `__llvm_inttoptr_i128_to_pi8 -> pi8` + - `__llvm_inttoptr_i128_to_pi16 -> pi16` + - `__llvm_inttoptr_i128_to_pi32 -> pi32` + - `__llvm_inttoptr_i128_to_pi64 -> pi64` + - `__llvm_inttoptr_i128_to_pi128 -> pi128` +- [`bitcast .. to`](https://llvm.org/docs/LangRef.html#bitcast-to-instruction): + - `__llvm_bitcast_bool_to_bool -> bool` + - `__llvm_bitcast_bool_to_i8 -> i8` + - `__llvm_bitcast_bool_to_i16 -> i16` + - `__llvm_bitcast_bool_to_i32 -> i32` + - `__llvm_bitcast_bool_to_i64 -> i64` + - `__llvm_bitcast_bool_to_i128 -> i128` + - `__llvm_bitcast_i8_to_bool -> bool` + - `__llvm_bitcast_i8_to_i8 -> i8` + - `__llvm_bitcast_i8_to_i16 -> i16` + - `__llvm_bitcast_i8_to_i32 -> i32` + - `__llvm_bitcast_i8_to_i64 -> i64` + - `__llvm_bitcast_i8_to_i128 -> i128` + - `__llvm_bitcast_i16_to_bool -> bool` + - `__llvm_bitcast_i16_to_i8 -> i8` + - `__llvm_bitcast_i16_to_i16 -> i16` + - `__llvm_bitcast_i16_to_i32 -> i32` + - `__llvm_bitcast_i16_to_i64 -> i64` + - `__llvm_bitcast_i16_to_i128 -> i128` + - `__llvm_bitcast_i32_to_bool -> bool` + - `__llvm_bitcast_i32_to_i8 -> i8` + - `__llvm_bitcast_i32_to_i16 -> i16` + - `__llvm_bitcast_i32_to_i32 -> i32` + - `__llvm_bitcast_i32_to_i64 -> i64` + - `__llvm_bitcast_i32_to_i128 -> i128` + - `__llvm_bitcast_i64_to_bool -> bool` + - `__llvm_bitcast_i64_to_i8 -> i8` + - `__llvm_bitcast_i64_to_i16 -> i16` + - `__llvm_bitcast_i64_to_i32 -> i32` + - `__llvm_bitcast_i64_to_i64 -> i64` + - `__llvm_bitcast_i64_to_i128 -> i128` + - `__llvm_bitcast_i128_to_bool -> bool` + - `__llvm_bitcast_i128_to_i8 -> i8` + - `__llvm_bitcast_i128_to_i16 -> i16` + - `__llvm_bitcast_i128_to_i32 -> i32` + - `__llvm_bitcast_i128_to_i64 -> i64` + - `__llvm_bitcast_i128_to_i128 -> i128` + - `__llvm_bitcast_pbool_to_pbool -> pbool` + - `__llvm_bitcast_pbool_to_pi8 -> pi8` + - `__llvm_bitcast_pbool_to_pi16 -> pi16` + - `__llvm_bitcast_pbool_to_pi32 -> pi32` + - `__llvm_bitcast_pbool_to_pi64 -> pi64` + - `__llvm_bitcast_pbool_to_pi128 -> pi128` + - `__llvm_bitcast_pi8_to_pbool -> pbool` + - `__llvm_bitcast_pi8_to_pi8 -> pi8` + - `__llvm_bitcast_pi8_to_pi16 -> pi16` + - `__llvm_bitcast_pi8_to_pi32 -> pi32` + - `__llvm_bitcast_pi8_to_pi64 -> pi64` + - `__llvm_bitcast_pi8_to_pi128 -> pi128` + - `__llvm_bitcast_pi16_to_pbool -> pbool` + - `__llvm_bitcast_pi16_to_pi8 -> pi8` + - `__llvm_bitcast_pi16_to_pi16 -> pi16` + - `__llvm_bitcast_pi16_to_pi32 -> pi32` + - `__llvm_bitcast_pi16_to_pi64 -> pi64` + - `__llvm_bitcast_pi16_to_pi128 -> pi128` + - `__llvm_bitcast_pi32_to_pbool -> pbool` + - `__llvm_bitcast_pi32_to_pi8 -> pi8` + - `__llvm_bitcast_pi32_to_pi16 -> pi16` + - `__llvm_bitcast_pi32_to_pi32 -> pi32` + - `__llvm_bitcast_pi32_to_pi64 -> pi64` + - `__llvm_bitcast_pi32_to_pi128 -> pi128` + - `__llvm_bitcast_pi64_to_pbool -> pbool` + - `__llvm_bitcast_pi64_to_pi8 -> pi8` + - `__llvm_bitcast_pi64_to_pi16 -> pi16` + - `__llvm_bitcast_pi64_to_pi32 -> pi32` + - `__llvm_bitcast_pi64_to_pi64 -> pi64` + - `__llvm_bitcast_pi64_to_pi128 -> pi128` + - `__llvm_bitcast_pi128_to_pbool -> pbool` + - `__llvm_bitcast_pi128_to_pi8 -> pi8` + - `__llvm_bitcast_pi128_to_pi16 -> pi16` + - `__llvm_bitcast_pi128_to_pi32 -> pi32` + - `__llvm_bitcast_pi128_to_pi64 -> pi64` + - `__llvm_bitcast_pi128_to_pi128 -> pi128` +- [`icmp`](https://llvm.org/docs/LangRef.html#icmp-instruction): + - `icmp` accepts three arguments. The first is a comparison condition. The two others are operands + of the same type. The condition is defined as an enum consisting of these values: `eq`, `ne`, + `ugt`, `uge`, `ult`, `ule`, `sgt`, `sge`, `slt`, `sle`. + - `__llvm_icmp_cond_bool_bool -> bool`, + - `__llvm_icmp_cond_i8_i8 -> bool`, + - `__llvm_icmp_cond_i16_i16 -> bool`, + - `__llvm_icmp_cond_i32_i32 -> bool`, + - `__llvm_icmp_cond_i64_i64 -> bool`, + - `__llvm_icmp_cond_i128_i128 -> bool`, +- [`select`](https://llvm.org/docs/LangRef.html#select-instruction): + - `__llvm_select_bool_bool_bool -> bool`, + - `__llvm_select_bool_i8_i8 -> bool`, + - `__llvm_select_bool_i16_i16 -> bool`, + - `__llvm_select_bool_i32_i32 -> bool`, + - `__llvm_select_bool_i64_i64 -> bool`, + - `__llvm_select_bool_i128_i128 -> bool`, + +#### Based on intrinsics + +- [`llvm.abs.*`](https://llvm.org/docs/LangRef.html#llvm-abs-intrinsic): + - `__llvm_abs_i8 -> i8`, + - `__llvm_abs_i16 -> i16`, + - `__llvm_abs_i32 -> i32`, + - `__llvm_abs_i64 -> i64`, + - `__llvm_abs_i128 -> i128`, +- [`llvm.smax.*`](https://llvm.org/docs/LangRef.html#llvm-smax-intrinsic): + - `__llvm_smax_bool_bool -> bool`, + - `__llvm_smax_i8_i8 -> i8`, + - `__llvm_smax_i16_i8 -> i16`, + - `__llvm_smax_i32_i8 -> i32`, + - `__llvm_smax_i64_i8 -> i64`, + - `__llvm_smax_i128_i8 -> i128`, +- [`llvm.smin.*`](https://llvm.org/docs/LangRef.html#llvm-smin-intrinsic): + - `__llvm_smin_bool_bool -> bool`, + - `__llvm_smin_i8_i8 -> i8`, + - `__llvm_smin_i16_i8 -> i16`, + - `__llvm_smin_i32_i8 -> i32`, + - `__llvm_smin_i64_i8 -> i64`, + - `__llvm_smin_i128_i8 -> i128`, +- [`llvm_umax.*`](https://llvm.org/docs/LangRef.html#llvm-umax-intrinsic): + - `__llvm_umax_bool_bool -> bool`, + - `__llvm_umax_i8_i8 -> i8`, + - `__llvm_umax_i16_i8 -> i16`, + - `__llvm_umax_i32_i8 -> i32`, + - `__llvm_umax_i64_i8 -> i64`, + - `__llvm_umax_i128_i8 -> i128`, +- [`llvm.umin.*`](https://llvm.org/docs/LangRef.html#llvm-umin-intrinsic): + - `__llvm_umin_bool_bool -> bool`, + - `__llvm_umin_i8_i8 -> i8`, + - `__llvm_umin_i16_i8 -> i16`, + - `__llvm_umin_i32_i8 -> i32`, + - `__llvm_umin_i64_i8 -> i64`, + - `__llvm_umin_i128_i8 -> i128`, +- [`llvm.scmp.*`](https://llvm.org/docs/LangRef.html#llvm-scmp-intrinsic): + - `scmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the + closest possible type is `i8`. + - `__llvm_ucmp_bool_bool -> i8`, + - `__llvm_scmp_i8_i8 -> i8`, + - `__llvm_scmp_i16_i8 -> i8`, + - `__llvm_scmp_i32_i8 -> i8`, + - `__llvm_scmp_i64_i8 -> i8`, + - `__llvm_scmp_i128_i8 -> i8`, +- [`llvm.ucmp.*`](https://llvm.org/docs/LangRef.html#llvm-ucmp-intrinsic): + - `ucmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the + closest possible type is `i8`. + - `__llvm_ucmp_bool_bool -> i8`, + - `__llvm_ucmp_i8_i8 -> i8`, + - `__llvm_ucmp_i16_i8 -> i8`, + - `__llvm_ucmp_i32_i8 -> i8`, + - `__llvm_ucmp_i64_i8 -> i8`, + - `__llvm_ucmp_i128_i8 -> i8`, +- [`llvm.bitreverse.*`]https://llvm.org/docs/LangRef.html#llvm-bitreverse-intrinsics): + - `__llvm_bitreverse_bool -> bool`, + - `__llvm_bitreverse_i8 -> i8`, + - `__llvm_bitreverse_i16 -> i16`, + - `__llvm_bitreverse_i32 -> i32`, + - `__llvm_bitreverse_i64 -> i64`, + - `__llvm_bitreverse_i128 -> i128`, +- [`llvm.bswap.*`](https://llvm.org/docs/LangRef.html#llvm-bswap-intrinsics): + - `__llvm_bswap_i8 -> i8`, + - `__llvm_bswap_i16 -> i16`, + - `__llvm_bswap_i32 -> i32`, + - `__llvm_bswap_i64 -> i64`, + - `__llvm_bswap_i128 -> i128`, +- [`llvm.ctpop.*`](https://llvm.org/docs/LangRef.html#llvm-ctpop-intrinsics): + - `__llvm_ctpop_bool -> bool`, + - `__llvm_ctpop_i8 -> i8`, + - `__llvm_ctpop_i16 -> i16`, + - `__llvm_ctpop_i32 -> i32`, + - `__llvm_ctpop_i64 -> i64`, + - `__llvm_ctpop_i128 -> i128`, +- [`llvm.ctlz.*`](https://llvm.org/docs/LangRef.html#llvm-ctlz-intrinsics): + - `__llvm_ctlz_bool -> bool`, + - `__llvm_ctlz_i8 -> i8`, + - `__llvm_ctlz_i16 -> i16`, + - `__llvm_ctlz_i32 -> i32`, + - `__llvm_ctlz_i64 -> i64`, + - `__llvm_ctlz_i128 -> i128`, +- [`llvm.cttz.*`](https://llvm.org/docs/LangRef.html#llvm-cttz-intrinsics): + - `__llvm_cttz_bool -> bool`, + - `__llvm_cttz_i8 -> i8`, + - `__llvm_cttz_i16 -> i16`, + - `__llvm_cttz_i32 -> i32`, + - `__llvm_cttz_i64 -> i64`, + - `__llvm_cttz_i128 -> i128`, +- [`llvm.fshl.*`](https://llvm.org/docs/LangRef.html#llvm-fshl-intrinsics): + - `__llvm_fshl_i8_i8_i8 -> i8`, + - `__llvm_fshl_i16_i16_i16 -> i16`, + - `__llvm_fshl_i32_i32_i32 -> i32`, + - `__llvm_fshl_i64_i64_i64 -> i64`, + - `__llvm_fshl_i128_i128_i128 -> i128`, +- [`llvm.fshr.*`](https://llvm.org/docs/LangRef.html#llvm-fshr-intrinsics): + - `__llvm_fshr_i8_i8_i8 -> i8`, + - `__llvm_fshr_i16_i16_i16 -> i16`, + - `__llvm_fshr_i32_i32_i32 -> i32`, + - `__llvm_fshr_i64_i64_i64 -> i64`, + - `__llvm_fshr_i128_i128_i128 -> i128`, +- [`llvm.sadd.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-sadd-with-overflow-intrinsics): + - `__llvm_sadd_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_sadd_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_sadd_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_sadd_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_sadd_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.uadd.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-uadd-with-overflow-intrinsics): + - `__llvm_uadd_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_uadd_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_uadd_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_uadd_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_uadd_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.ssub.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-ssub-with-overflow-intrinsics): + - `__llvm_ssub_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_ssub_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_ssub_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_ssub_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_ssub_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.usub.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-usub-with-overflow-intrinsics): + - `__llvm_usub_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_usub_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_usub_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_usub_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_usub_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.smul.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-smul-with-overflow-intrinsics): + - `__llvm_smul_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_smul_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_smul_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_smul_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_smul_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.umul.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-umul-with-overflow-intrinsics): + - `__llvm_umul_with_overflow_i8_i8 -> (i8, bool)`, + - `__llvm_umul_with_overflow_i16_i16 -> (i16, bool)`, + - `__llvm_umul_with_overflow_i32_i32 -> (i32, bool)`, + - `__llvm_umul_with_overflow_i64_i64 -> (i64, bool)`, + - `__llvm_umul_with_overflow_i128_i128 -> (i128, bool)`, +- [`llvm.sadd.sat.*`](https://llvm.org/docs/LangRef.html#llvm-sadd-sat-intrinsics): + - `__llvm_sadd_sat_i8_i8 -> i8`, + - `__llvm_sadd_sat_i16_i16 -> i16`, + - `__llvm_sadd_sat_i32_i32 -> i32`, + - `__llvm_sadd_sat_i64_i64 -> i64`, + - `__llvm_sadd_sat_i128_i128 -> i128`, +- [`llvm.uadd.sat.*`](https://llvm.org/docs/LangRef.html#llvm-uadd-sat-intrinsics): + - `__llvm_uadd_sat_i8_i8 -> i8`, + - `__llvm_uadd_sat_i16_i16 -> i16`, + - `__llvm_uadd_sat_i32_i32 -> i32`, + - `__llvm_uadd_sat_i64_i64 -> i64`, + - `__llvm_uadd_sat_i128_i128 -> i128`, +- [`llvm.ssub.sat.*`](https://llvm.org/docs/LangRef.html#llvm-ssub-sat-intrinsics): + - `__llvm_ssub_sat_i8_i8 -> i8`, + - `__llvm_ssub_sat_i16_i16 -> i16`, + - `__llvm_ssub_sat_i32_i32 -> i32`, + - `__llvm_ssub_sat_i64_i64 -> i64`, + - `__llvm_ssub_sat_i128_i128 -> i128`, +- [`llvm.usub.sat.*`](https://llvm.org/docs/LangRef.html#llvm-usub-sat-intrinsics): + - `__llvm_usub_sat_i8_i8 -> i8`, + - `__llvm_usub_sat_i16_i16 -> i16`, + - `__llvm_usub_sat_i32_i32 -> i32`, + - `__llvm_usub_sat_i64_i64 -> i64`, + - `__llvm_usub_sat_i128_i128 -> i128`, +- [`llvm.sshl.sat.*`](https://llvm.org/docs/LangRef.html#llvm-sshl-sat-intrinsics): + - `__llvm_sshl_sat_i8_i8 -> i8`, + - `__llvm_sshl_sat_i16_i16 -> i16`, + - `__llvm_sshl_sat_i32_i32 -> i32`, + - `__llvm_sshl_sat_i64_i64 -> i64`, + - `__llvm_sshl_sat_i128_i128 -> i128`, +- [`llvm.ushl.sat.*`](https://llvm.org/docs/LangRef.html#llvm-ushl-sat-intrinsics): + - `__llvm_ushl_sat_i8_i8 -> i8`, + - `__llvm_ushl_sat_i16_i16 -> i16`, + - `__llvm_ushl_sat_i32_i32 -> i32`, + - `__llvm_ushl_sat_i64_i64 -> i64`, + - `__llvm_ushl_sat_i128_i128 -> i128`, From da4f4d1396ab7a57e65920f1f5e5e2346e8f4f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=BBmuda?= <5251642+wzmuda@users.noreply.github.com> Date: Wed, 16 Oct 2024 00:18:05 +0200 Subject: [PATCH 02/22] Ara's grammar and wording fixes Co-authored-by: Ara Adkins --- docs/ALU Design.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 10f7ebb..2284360 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -16,7 +16,7 @@ document will be updated. ## Research -ALU will have to target two concepts of LLVM IR: instructions and intrinsics. +ALU will have to target two concepts in the LLVM IR: instructions and intrinsics. ### Instructions @@ -70,7 +70,7 @@ The example above includes the following line: %0 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %left, i64 %right), !dbg !17 ``` -Unlike the previous example, this snippet does nto contain the `add` instruction. The adding +Unlike the previous example, this snippet does not contain the `add` instruction. The adding operation is done by an intrinsic named `llvm.uadd.with.overflow.i64`, which is called with the `call` instruction. The intrinsic is defined in the LLVM codebase and its source code does not make it into the `.ll` file produced out of the adding operation in Rust code. @@ -78,7 +78,7 @@ it into the `.ll` file produced out of the adding operation in Rust code. The LLVM Language Reference Manual has an extensive list of intrinsics. Here's the example of [`llvm.uadd.with.overflow.`](https://llvm.org/docs/LangRef.html#llvm-uadd-with-overflow-intrinsics). -### Data types +### Data Types This ALU will support only integers. Floating point numbers are out of scope of this document. @@ -97,7 +97,7 @@ abstraction, the Cairo language supports with the same increment Cairo does, plus architecture-dependent `isize` and `usize`. Rust also supports booleans. -The Cairo VM does not have a classical registers of length constrained by the hardware. Therefore +The Cairo VM does not have classical registers of a length constrained by the hardware. Therefore there is no obvious indicator of how long `usize`/`isize` should be on that target. Since from the LLVM point of view a pointer must have a finite size, this decision must be made based on some other feature of the architecture. We have evaluated the following choices: @@ -114,7 +114,7 @@ above possibilities. This length is a consequence of using the `aarch64-unknown- target triple. The choice of the triple determines the length of the pointer which in turn determines the length of `usize`. This target triple is a temporary choice before a custom target triple is proposed. It has been chosen for its soft float support and no host operating system. The -pointer length is just one of its parameters we accept on this stage of the project. +pointer length is just one of its parameters we accept at this stage of the project. Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 bits. @@ -125,9 +125,9 @@ LLVM IR has only one generic pointer type - `ptr`, which works as a rough equiva in C. Type-specific pointers (e.g. equivalent of C's `int`) existed, but are now deprecated. Therefore, we expect to see in the input IR only the generic `ptr` pointer. -Not only Rust and the Cairo language support a generic pointer type, their support for pointer does +Not only do Rust and the Cairo language support a generic pointer type, their support for pointers does not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. Both -languages operates on strongly typed smart pointers, that handle, under the hood, their own memory. +languages operates on strongly typed smart pointers, that handle their own memory under the hood. Based on these observations, ALU operations must be strongly typed, by the limitation of the language it will be implemented in. When the input IR will be parsed, it generic pointer types must @@ -135,15 +135,15 @@ be inferred from the context, to allow matching with the proper implementation. #### Vectors -Neither the Cairo VM, Cairo language nor no-std Rust have support for vector operations. +Neither the Cairo VM, Cairo language nor no-std Rust have support for vectorized operations. LLVM IR has vectors as first class citizens. However, _[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#t-vector)_. -If Cairo target definition supplied to `rustc` will not suggest the existence of vector extension on -the target platform, we do not expect any vector intrinsics to appear in the IR. Therefore, vector -support is not planned in the initial phase of the project. +If Cairo target definition supplied to `rustc` does not suggest the existence of vector extension on +the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, vector +support is not planned as part of the initial phase of the project. -#### Type conversion +#### Type Conversion Cairo does not have Rust's `as` keyword, so it's not possible to do e.g. `let a = b as u32` given `b` is a `u64`. @@ -155,7 +155,7 @@ disadvantages: - there is no automatic wraparound as in the case of `as`. Should type conversion be necessary in the implementation of the operations, it will need to handle -the type conversion with `try_into()` and manual recover from errors: +the type conversion with `try_into()` and manually recover from errors: ```rust let result: u32 = match sum.try_into() { @@ -198,14 +198,14 @@ br i1 %_3.1, label %panic, label %bb1, !dbg !17 - by demanding that input data is correct and producing undefined behavior otherwise, - by emitting poison values, if producing a correct value is not possible. -Based on these observations, we decide to deliver the ALU as a collection of stateless arithmetic +Based on these observations, we have decided to deliver the ALU as a collection of stateless arithmetic operations. ### Tests Cairo has an [integrated test framework](https://book.cairo-lang.org/ch10-01-how-to-write-tests.html), similar to -the one offered by Rust. Our ALU implementation will then come with a test suite to verify that we +the one offered by Rust. Our ALU implementation will come with a test suite to verify that we implement the desired behavior, e.g. to make sure we indicate overflow on obvious situations like `0xFFFFFFFF + 1` for a `u32` add. @@ -233,9 +233,9 @@ Each function will follow the semantics of its LLVM IR counterpart. This require Each function will follow the naming scheme described in the relevant section below. -### Naming convention +### Naming Convention -#### Instruction polyfills +#### Instruction Polyfills Name template: `__llvm___`. In case the instruction works with both operands of the same data type, the template degrades to `__llvm___`. @@ -249,7 +249,7 @@ In case the instruction works with pointer type, the generic LLVM keyword `ptr` `p`. For an example instruction `inst ptr %a, i8 %b`, where `%a` is a pointer to the value of the same type as `%b`, the polyfill would be named `__llvm_inst_pi8_i8`. -#### Intrinsic polyfills +#### Intrinsic Polyfills Name template: `____`, where type `` indicates every argument accepted by the intrinsic. @@ -261,17 +261,17 @@ All other naming rules defined for instructions also apply to intrinsics. ### Operations -The list below specifies all implementations of arithmetic operations that will be provided by ALU. +The list below specifies all implementations of arithmetic operations that will be provided by the ALU. The list is divided to two parts: -- implementations emulating LLVM instructions, -- implementations emulating LLVM intrinsics. +- Implementations emulating LLVM instructions, +- Implementations emulating LLVM intrinsics. Implementations for every supported integer lengths are specified. Their names follow the naming convention explained in the section above. Each instruction or intrinsic name is a link to the relevant part of the LLVM Language Reference Manual. -#### Based on instructions +#### Based on Instructions - [`add`](https://llvm.org/docs/LangRef.html#add-instruction): - `__llvm_add_i8_i8 -> i8` @@ -584,7 +584,7 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_select_bool_i64_i64 -> bool`, - `__llvm_select_bool_i128_i128 -> bool`, -#### Based on intrinsics +#### Based on Intrinsics - [`llvm.abs.*`](https://llvm.org/docs/LangRef.html#llvm-abs-intrinsic): - `__llvm_abs_i8 -> i8`, From 32feaef8ca1c3a18fe4f66283409c2b5e08d75e8 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Wed, 16 Oct 2024 00:19:20 +0200 Subject: [PATCH 03/22] Dont mention lack of floats, makes no sense --- docs/ALU Design.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 2284360..ecae8f1 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -80,8 +80,6 @@ The LLVM Language Reference Manual has an extensive list of intrinsics. Here's t ### Data Types -This ALU will support only integers. Floating point numbers are out of scope of this document. - #### Integers LLVM IR supports integers of arbitrary width. A general syntax for an integer type is `iN`, where @@ -125,9 +123,10 @@ LLVM IR has only one generic pointer type - `ptr`, which works as a rough equiva in C. Type-specific pointers (e.g. equivalent of C's `int`) existed, but are now deprecated. Therefore, we expect to see in the input IR only the generic `ptr` pointer. -Not only do Rust and the Cairo language support a generic pointer type, their support for pointers does -not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. Both -languages operates on strongly typed smart pointers, that handle their own memory under the hood. +Not only do Rust and the Cairo language support a generic pointer type, their support for pointers +does not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. +Both languages operates on strongly typed smart pointers, that handle their own memory under the +hood. Based on these observations, ALU operations must be strongly typed, by the limitation of the language it will be implemented in. When the input IR will be parsed, it generic pointer types must @@ -140,8 +139,8 @@ Neither the Cairo VM, Cairo language nor no-std Rust have support for vectorized LLVM IR has vectors as first class citizens. However, _[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#t-vector)_. If Cairo target definition supplied to `rustc` does not suggest the existence of vector extension on -the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, vector -support is not planned as part of the initial phase of the project. +the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, +vector support is not planned as part of the initial phase of the project. #### Type Conversion @@ -198,8 +197,8 @@ br i1 %_3.1, label %panic, label %bb1, !dbg !17 - by demanding that input data is correct and producing undefined behavior otherwise, - by emitting poison values, if producing a correct value is not possible. -Based on these observations, we have decided to deliver the ALU as a collection of stateless arithmetic -operations. +Based on these observations, we have decided to deliver the ALU as a collection of stateless +arithmetic operations. ### Tests @@ -261,8 +260,8 @@ All other naming rules defined for instructions also apply to intrinsics. ### Operations -The list below specifies all implementations of arithmetic operations that will be provided by the ALU. -The list is divided to two parts: +The list below specifies all implementations of arithmetic operations that will be provided by the +ALU. The list is divided to two parts: - Implementations emulating LLVM instructions, - Implementations emulating LLVM intrinsics. From dd4bdfc5322ab02986e2fce4b68f1f7144503f55 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Wed, 16 Oct 2024 00:23:21 +0200 Subject: [PATCH 04/22] Say we don't support arbitrary width ints --- docs/ALU Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index ecae8f1..810677b 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -115,7 +115,7 @@ triple is proposed. It has been chosen for its soft float support and no host op pointer length is just one of its parameters we accept at this stage of the project. Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 -bits. +bits. Specifically, do not intend to add operations over arbitrary-width integers. #### Pointers From 77c2ac1375937baf5d5d9dcfe61b382546ea42c7 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Wed, 16 Oct 2024 00:30:16 +0200 Subject: [PATCH 05/22] Integers: expand rationale of usize width --- docs/ALU Design.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 810677b..81b5dac 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -101,18 +101,22 @@ LLVM point of view a pointer must have a finite size, this decision must be made feature of the architecture. We have evaluated the following choices: - The Cairo language already has 32 bit `usize`, so we can follow this approach, making `usize` and - `isize` also 32 bit, + `isize` also 32 bit. This approach was rejected for the lack of the strong rationale behind + Cairo's choice of this particular width. It does not seem to correspond with any feature of the + platform architecture. - The architecture's natural word size is 252 bit, being the length of the field element. It may be - reasonable to set `usize` and `isize` length to 252 bit, + reasonable to set `usize` and `isize` length to 252 bit. - 256 bit is the next power-of-2 after 252. Having `usize` and `isize` 256 bit long leaves 4 extra bits that may be used to keep some metadata. Ultimately the size of `usize` and `isize` has been decided to be 64 bits, which is neither of the above possibilities. This length is a consequence of using the `aarch64-unknown-none-softfloat` target triple. The choice of the triple determines the length of the pointer which in turn -determines the length of `usize`. This target triple is a temporary choice before a custom target -triple is proposed. It has been chosen for its soft float support and no host operating system. The -pointer length is just one of its parameters we accept at this stage of the project. +determines the length of `usize`. This specific triple has been chosen for its soft float support +and no host operating system. The pointer length is just one of its parameters we accept at this +stage of the project. This target triple is a temporary choice before a custom target triple is +proposed. When designing our custom triple, it is possible that the choice of `usize` and `isize` +width will be reevaluated and possibly changed to match the width of the field element. Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 bits. Specifically, do not intend to add operations over arbitrary-width integers. From bfade77e33288c67f676d3b6d0b6edf87e5f0917 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Wed, 16 Oct 2024 00:36:43 +0200 Subject: [PATCH 06/22] typo --- docs/ALU Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 81b5dac..ed97bba 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -133,7 +133,7 @@ Both languages operates on strongly typed smart pointers, that handle their own hood. Based on these observations, ALU operations must be strongly typed, by the limitation of the -language it will be implemented in. When the input IR will be parsed, it generic pointer types must +language it will be implemented in. When the input IR will be parsed, its generic pointer types must be inferred from the context, to allow matching with the proper implementation. #### Vectors From a180eb6e8ab4c96996a70be05f0bc9122a8913ab Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Wed, 16 Oct 2024 00:36:53 +0200 Subject: [PATCH 07/22] vector fix link --- docs/ALU Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index ed97bba..deae71a 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -141,7 +141,7 @@ be inferred from the context, to allow matching with the proper implementation. Neither the Cairo VM, Cairo language nor no-std Rust have support for vectorized operations. LLVM IR has vectors as first class citizens. However, -_[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#t-vector)_. +_[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#vector-type)_. If Cairo target definition supplied to `rustc` does not suggest the existence of vector extension on the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, vector support is not planned as part of the initial phase of the project. From 33fcfb261d1850e60008bcd3ba8e054ab8218143 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Thu, 17 Oct 2024 22:23:07 +0200 Subject: [PATCH 08/22] pointers: i lost a * --- docs/ALU Design.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index deae71a..01f7b7b 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -124,8 +124,9 @@ bits. Specifically, do not intend to add operations over arbitrary-width integer #### Pointers LLVM IR has only one generic pointer type - `ptr`, which works as a rough equivalent of the `void *` -in C. Type-specific pointers (e.g. equivalent of C's `int`) existed, but are now deprecated. -Therefore, we expect to see in the input IR only the generic `ptr` pointer. +in C. Type-specific pointers (e.g. equivalent of C's `int *`) existed in LLVM in the past, but are +now deprecated. Therefore, we expect to see in the input IR only the generic `ptr` pointer. This +does not translate well to higher-level programming languages. Not only do Rust and the Cairo language support a generic pointer type, their support for pointers does not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. From 4d2d1f1498549b3a0a2ce21e9d7ec4efacc78d23 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 00:42:00 +0200 Subject: [PATCH 09/22] pointers: add more details --- docs/ALU Design.md | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 01f7b7b..1f29b10 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -128,14 +128,43 @@ in C. Type-specific pointers (e.g. equivalent of C's `int *`) existed in LLVM in now deprecated. Therefore, we expect to see in the input IR only the generic `ptr` pointer. This does not translate well to higher-level programming languages. -Not only do Rust and the Cairo language support a generic pointer type, their support for pointers -does not follow the mechanism known from C, which would smoothly translate into LLVM IR semantics. -Both languages operates on strongly typed smart pointers, that handle their own memory under the -hood. +No-std Rust support for pointers is twofold: + +- strongly typed smart pointers with the `Box<>` construct, that handle their own memory under the + hood, +- strongly typed raw pointers that can be dereferenced within an `unsafe {}` block. + +Usage of smart pointers translate to multiple LLVM IR instructions, involving heap memory +allocation. The IR generated from a similar code involving raw pointers is simpler in comparison. +Bothapproaches ultimately generate the `ptr` LLVM type. + +The Cairo language operates solely on strongly typed smart pointers. There is no raw pointers. The +`unsafe` keyword is reserved for the future use. Based on these observations, ALU operations must be strongly typed, by the limitation of the -language it will be implemented in. When the input IR will be parsed, its generic pointer types must -be inferred from the context, to allow matching with the proper implementation. +language they will be implemented in. Specifically, we are unable to provide a generic +`__llvm_instr_ptr` polyfill for an instruction accepting a single pointer argument, because such +construct is not supported by Cairo. Instead, we must provide the whole family of polyfills, one for +each possible pointer type: + +- `__llvm_instr_pbool`, +- `__llvm_instr_pi8`, +- `__llvm_instr_pi16`, +- `__llvm_instr_pi32`, +- `__llvm_instr_pi64`, +- `__llvm_instr_pi128`. Some of the implementations may be omitted if they do not reflect LLVM IR + semantics for a given instruction. + +When the input IR will is parsed and a generic pointer is found, its concrete type must be inferred +from the context, to allow matching with the proper implementation. For example this IR snippet: + +```llvm +%num = alloca [4 x i8], align 4 +%_5 = ptrtoint ptr %num to i64, !dbg !13 +``` + +must be mapped to the following implementation: `__llvm_ptrtoint_pi8_to_i64`, as `num` is a pointer +to an array of `i8`. #### Vectors From 20b7393fab79f640a6c98d9ac22a8c70fb25ed4b Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 00:47:08 +0200 Subject: [PATCH 10/22] overview: more details on linking and flatlowered --- docs/ALU Design.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 1f29b10..ee54aa6 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -249,8 +249,9 @@ implement the desired behavior, e.g. to make sure we indicate overflow on obviou The ALU will be implemented as a source code written in [Cairo](https://book.cairo-lang.org/title-page.html). During the [LLVM-to-Cairo compilation pipeline](https://www.notion.so/reilabs/System-Architecture-113d2f80c874802b8480d997347933a2?pvs=4) -it will be translated to `FlatLowered` objects. Then, on the linking phase, arithmetic operations -from `FLIR` objects created from the input LLVM IR will be linked with their Cairo implementations. +the polyfills implementations will be translated to `FlatLowered` objects and then extracted to +`.flo` files. Then, on the linking phase, all the `.flo` files (those created from arithmetic +operations implementations and those from the LLVM IR) will be linked together. As discussed in the relevant section of the Research part, each operation will be an independent, stateless block of code composed of a single Cairo From 0a8a3e58551cd86fa7114e4a1861cbd7eb5e9316 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 00:51:36 +0200 Subject: [PATCH 11/22] overview: mention subroutines are ok --- docs/ALU Design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index ee54aa6..1a066c9 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -253,10 +253,10 @@ the polyfills implementations will be translated to `FlatLowered` objects and th `.flo` files. Then, on the linking phase, all the `.flo` files (those created from arithmetic operations implementations and those from the LLVM IR) will be linked together. -As discussed in the relevant section of the Research part, each operation will be an independent, -stateless block of code composed of a single Cairo -[function](https://book.cairo-lang.org/ch02-03-functions.html), which is an equivalent concept of a -function in any other procedural programming language. +As discussed in the relevant section of the Research part, each operation will be a stateless block +of code composed of a single Cairo [function](https://book.cairo-lang.org/ch02-03-functions.html) +(possibly composed of subroutines for common parts) which is an equivalent concept of a function in +any other procedural programming language. Each function will follow the semantics of its LLVM IR counterpart. This requires: From d0cf7aad8b9a07d4197b9b092866a6e0ed82efcf Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 00:57:46 +0200 Subject: [PATCH 12/22] overview: more about semantics --- docs/ALU Design.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 1a066c9..9f683ea 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -263,7 +263,16 @@ Each function will follow the semantics of its LLVM IR counterpart. This require - accepting the same number of arguments, of the same type and in the same order as the original operation's operands, - returning the same number or values, of the same type and in the same order as the original - operation. + operation, +- implementing the exact semantics as expected by LLVM. + +As an example, for the `sub` instruction, our polyfill operating on `i8` operands must: + +- accept exactly two `i8` operands, +- the operands must be in the same order, i.e. for `sub %a, %b` our polyfill `__llvm_sub_i8_i8` must + accept `a` and `b` in the same order, +- as `sub %a, %b` performs the `a-b` subtraction, our polyfill must not perform `b-a` instead and + all corner cases, like underflow, must be handled in the same way as LLVM handles them. Each function will follow the naming scheme described in the relevant section below. From 734ce06e8994876bbd0d30943d4029e6aea0011c Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 18:43:41 +0200 Subject: [PATCH 13/22] pointers: add missing space --- docs/ALU Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 9f683ea..7777c92 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -136,7 +136,7 @@ No-std Rust support for pointers is twofold: Usage of smart pointers translate to multiple LLVM IR instructions, involving heap memory allocation. The IR generated from a similar code involving raw pointers is simpler in comparison. -Bothapproaches ultimately generate the `ptr` LLVM type. +Both approaches ultimately generate the `ptr` LLVM type. The Cairo language operates solely on strongly typed smart pointers. There is no raw pointers. The `unsafe` keyword is reserved for the future use. From bd516c5fd64b19edbd857f4a3eefbd795ebb35d6 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 18:43:51 +0200 Subject: [PATCH 14/22] h1: capitalize properly --- docs/ALU Design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 7777c92..9dc3729 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -1,4 +1,4 @@ -# ALU design +# ALU Design This document describes the research done for [#27 Design ALU](https://github.com/reilabs/llvm-to-cairo/issues/27). From a6e6083941e0faf8c212854dc124c80bd00007f5 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 18:58:06 +0200 Subject: [PATCH 15/22] Link sections together --- docs/ALU Design.md | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 9dc3729..4e9ebf6 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -3,10 +3,10 @@ This document describes the research done for [#27 Design ALU](https://github.com/reilabs/llvm-to-cairo/issues/27). -The first part, **Research**, describes selected features of LLVM IR, Rust and Cairo (both the -virtual machine and the programming language), that impact the way we must handle arithmetic and -logic operations. The second part, **Design**, specifies decisions made with regard to the shape of -the ALU component of the project. +The first part, [**Research**](#Research), describes selected features of LLVM IR, Rust and Cairo +(both the virtual machine and the programming language), that impact the way we must handle +arithmetic and logic operations. The second part, [**Design**](#design), specifies decisions made +with regard to the shape of the ALU component of the project. Most of the design decision are based on the outcomes of experiments described in the research part. Some decisions are made arbitrarily. All decisions are subject to change, especially if more @@ -53,10 +53,10 @@ keywords modifying its behavior. An #### Poison -In the example of `add`, if `nuw` or `nsw` keywords occur, they guarantee specific behavior, i.e. no -(un)signed overflow. However, if the operands cause the overflow, the instruction returns a poison, -which is an equivalent of a value indicating undefined behavior that can propagate throughout the -program. +In the [example of `add`](#keywords), if `nuw` or `nsw` keywords occur, they guarantee specific +behavior, i.e. no (un)signed overflow. However, if the operands cause the overflow, the instruction +returns a poison, which is an equivalent of a value indicating undefined behavior that can propagate +throughout the program. [According to the experiment](https://github.com/reilabs/llvm-to-cairo/issues/27#issuecomment-2397645979), LLVM does not seem to emit such instructions from the Rust code, so the initial version of ALU will @@ -64,16 +64,16 @@ not handle `nuw`, `nsw` or other keywords in any specific way. ### Intrinsics -The example above includes the following line: +Consider the following LLVM IR code: ```llvm %0 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %left, i64 %right), !dbg !17 ``` -Unlike the previous example, this snippet does not contain the `add` instruction. The adding -operation is done by an intrinsic named `llvm.uadd.with.overflow.i64`, which is called with the -`call` instruction. The intrinsic is defined in the LLVM codebase and its source code does not make -it into the `.ll` file produced out of the adding operation in Rust code. +Unlike the [previous example](#keywords), this snippet does not contain the `add` instruction. The +adding operation is done by an intrinsic named `llvm.uadd.with.overflow.i64`, which is called with +the `call` instruction. The intrinsic is defined in the LLVM codebase and its source code does not +make it into the `.ll` file produced out of the adding operation in Rust code. The LLVM Language Reference Manual has an extensive list of intrinsics. Here's the example of [`llvm.uadd.with.overflow.`](https://llvm.org/docs/LangRef.html#llvm-uadd-with-overflow-intrinsics). @@ -217,7 +217,7 @@ managed during that time. Additionally, it has been noticed [in one of the experiments](https://github.com/reilabs/llvm-to-cairo/issues/27#issuecomment-2391893640), that LLVM IR follows the same principle of not managing the internal state of arithmetic operations. -This is either done by +This is either done by: - returning a tuple containing both the operation result and the state information: @@ -253,10 +253,11 @@ the polyfills implementations will be translated to `FlatLowered` objects and th `.flo` files. Then, on the linking phase, all the `.flo` files (those created from arithmetic operations implementations and those from the LLVM IR) will be linked together. -As discussed in the relevant section of the Research part, each operation will be a stateless block -of code composed of a single Cairo [function](https://book.cairo-lang.org/ch02-03-functions.html) -(possibly composed of subroutines for common parts) which is an equivalent concept of a function in -any other procedural programming language. +As discussed in the [relevant section of the Research part](#statefulness), each operation will be a +stateless block of code composed of a single Cairo +[function](https://book.cairo-lang.org/ch02-03-functions.html)(possibly composed of subroutines for +common parts) which is an equivalent concept of a function in any other procedural programming +language. Each function will follow the semantics of its LLVM IR counterpart. This requires: @@ -274,7 +275,8 @@ As an example, for the `sub` instruction, our polyfill operating on `i8` operand - as `sub %a, %b` performs the `a-b` subtraction, our polyfill must not perform `b-a` instead and all corner cases, like underflow, must be handled in the same way as LLVM handles them. -Each function will follow the naming scheme described in the relevant section below. +Each function will follow the naming scheme described in the +[relevant section below](#naming-convention). ### Naming Convention @@ -300,15 +302,15 @@ argument accepted by the intrinsic. In the example of `llvm.uadd.with.overflow.i64(i64 %left, i64 %right)`, the polyfill would be named `__llvm_uadd_with_overflow_i64_i64`. -All other naming rules defined for instructions also apply to intrinsics. +All other [naming rules defined for instructions](#instruction-polyfills) also apply to intrinsics. ### Operations The list below specifies all implementations of arithmetic operations that will be provided by the ALU. The list is divided to two parts: -- Implementations emulating LLVM instructions, -- Implementations emulating LLVM intrinsics. +- [Implementations emulating LLVM instructions](#based-on-instructions), +- [Implementations emulating LLVM intrinsics](#based-on-intrinsics)). Implementations for every supported integer lengths are specified. Their names follow the naming convention explained in the section above. Each instruction or intrinsic name is a link to the From c0110e97aa045bd74baf8ce980209389ef035d54 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 20:38:07 +0200 Subject: [PATCH 16/22] i128 polyfills are optional --- docs/ALU Design.md | 223 +++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 107 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 4e9ebf6..4a6c1ca 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -116,10 +116,14 @@ determines the length of `usize`. This specific triple has been chosen for its s and no host operating system. The pointer length is just one of its parameters we accept at this stage of the project. This target triple is a temporary choice before a custom target triple is proposed. When designing our custom triple, it is possible that the choice of `usize` and `isize` -width will be reevaluated and possibly changed to match the width of the field element. +width will be reevaluated and possibly changed to match the width of the field element. Also, since +`aarch64-unknown-none-softfloat` does not naturally support 128 bit integers, we do not expect LLVM +to generate `i128` in the IR. Our custom triple may support this data type. -Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 -bits. Specifically, do not intend to add operations over arbitrary-width integers. +Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32 and 64 bits. +After proposing our custom triple, we will expect 128 bit integers to appear in the IR, which will +require extending the polyfills set with `i128` support. We do not intend to support operations over +arbitrary-width integers. #### Pointers @@ -152,8 +156,10 @@ each possible pointer type: - `__llvm_instr_pi16`, - `__llvm_instr_pi32`, - `__llvm_instr_pi64`, -- `__llvm_instr_pi128`. Some of the implementations may be omitted if they do not reflect LLVM IR - semantics for a given instruction. +- `__llvm_instr_pi128` _(optionally, if a triple supporting 128 bit integers is introduced)_. + +Some of the implementations may be omitted if they do not reflect LLVM IR semantics for a given +instruction. When the input IR will is parsed and a generic pointer is found, its concrete type must be inferred from the context, to allow matching with the proper implementation. For example this IR snippet: @@ -310,12 +316,15 @@ The list below specifies all implementations of arithmetic operations that will ALU. The list is divided to two parts: - [Implementations emulating LLVM instructions](#based-on-instructions), -- [Implementations emulating LLVM intrinsics](#based-on-intrinsics)). +- [Implementations emulating LLVM intrinsics](#based-on-intrinsics). Implementations for every supported integer lengths are specified. Their names follow the naming convention explained in the section above. Each instruction or intrinsic name is a link to the relevant part of the LLVM Language Reference Manual. +Operations prepended with (\*) are the extended goal and will not be implemented in the initial +phase. See [Data Types](#data-types) for details. + #### Based on Instructions - [`add`](https://llvm.org/docs/LangRef.html#add-instruction): @@ -323,82 +332,82 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_add_i16_i16 -> i16` - `__llvm_add_i32_i32 -> i32` - `__llvm_add_i64_i64 -> i64` - - `__llvm_add_i128_i128 -> i128` + - (\*) `__llvm_add_i128_i128 -> i128` - [`sub`](https://llvm.org/docs/LangRef.html#sub-instruction): - `__llvm_sub_i8_i8 -> i8` - `__llvm_sub_i16_i16 -> i16` - `__llvm_sub_i32_i32 -> i32` - `__llvm_sub_i64_i64 -> i64` - - `__llvm_sub_i128_i128 -> i128` + - (\*) `__llvm_sub_i128_i128 -> i128` - [`mul`](https://llvm.org/docs/LangRef.html#mul-instruction): - `__llvm_mul_i8_i8 -> i8` - `__llvm_mul_i16_i16 -> i16` - `__llvm_mul_i32_i32 -> i32` - `__llvm_mul_i64_i64 -> i64` - - `__llvm_mul_i128_i128 -> i128` + - (\*) `__llvm_mul_i128_i128 -> i128` - [`udiv`](https://llvm.org/docs/LangRef.html#udiv-instruction): - `__llvm_udiv_i8_i8 -> i8` - `__llvm_udiv_i16_i16 -> i16` - `__llvm_udiv_i32_i32 -> i32` - `__llvm_udiv_i64_i64 -> i64` - - `__llvm_udiv_i128_i128 -> i128` + - (\*) `__llvm_udiv_i128_i128 -> i128` - [`sdiv`](https://llvm.org/docs/LangRef.html#sdiv-instruction): - `__llvm_sdiv_i8_i8 -> i8` - `__llvm_sdiv_i16_i16 -> i16` - `__llvm_sdiv_i32_i32 -> i32` - `__llvm_sdiv_i64_i64 -> i64` - - `__llvm_sdiv_i128_i128 -> i128` + - (\*) `__llvm_sdiv_i128_i128 -> i128` - [`urem`](https://llvm.org/docs/LangRef.html#urem-instruction): - `__llvm_urem_i8_i8 -> i8` - `__llvm_urem_i16_i16 -> i16` - `__llvm_urem_i32_i32 -> i32` - `__llvm_urem_i64_i64 -> i64` - - `__llvm_urem_i128_i128 -> i128` + - (\*) `__llvm_urem_i128_i128 -> i128` - [`srem`](https://llvm.org/docs/LangRef.html#srem-instruction): - `__llvm_srem_i8_i8 -> i8` - `__llvm_srem_i16_i16 -> i16` - `__llvm_srem_i32_i32 -> i32` - `__llvm_srem_i64_i64 -> i64` - - `__llvm_srem_i128_i128 -> i128` + - (\*) `__llvm_srem_i128_i128 -> i128` - [`shl`](https://llvm.org/docs/LangRef.html#shl-instruction): - `__llvm_shl_i8_i8 -> i8` - `__llvm_shl_i16_i16 -> i16` - `__llvm_shl_i32_i32 -> i32` - `__llvm_shl_i64_i64 -> i64` - - `__llvm_shl_i128_i128 -> i128` + - (\*) `__llvm_shl_i128_i128 -> i128` - [`lshr`](https://llvm.org/docs/LangRef.html#lshr-instruction): - `__llvm_lshr_i8_i8 -> i8` - `__llvm_lshr_i16_i16 -> i16` - `__llvm_lshr_i32_i32 -> i32` - `__llvm_lshr_i64_i64 -> i64` - - `__llvm_lshr_i128_i128 -> i128` + - (\*) `__llvm_lshr_i128_i128 -> i128` - [`ashr`](https://llvm.org/docs/LangRef.html#ashr-instruction): - `__llvm_ashr_i8_i8 -> i8` - `__llvm_ashr_i16_i16 -> i16` - `__llvm_ashr_i32_i32 -> i32` - `__llvm_ashr_i64_i64 -> i64` - - `__llvm_ashr_i128_i128 -> i128` + - (\*) `__llvm_ashr_i128_i128 -> i128` - [`and`](https://llvm.org/docs/LangRef.html#and-instruction): - `__llvm_and_bool_bool -> bool` - `__llvm_and_i8_i8 -> i8` - `__llvm_and_i16_i16 -> i16` - `__llvm_and_i32_i32 -> i32` - `__llvm_and_i64_i64 -> i64` - - `__llvm_and_i128_i128 -> i128` + - (\*) `__llvm_and_i128_i128 -> i128` - [`or`](https://llvm.org/docs/LangRef.html#or-instruction): - `__llvm_or_bool_bool -> bool` - `__llvm_or_i8_i8 -> i8` - `__llvm_or_i16_i16 -> i16` - `__llvm_or_i32_i32 -> i32` - `__llvm_or_i64_i64 -> i64` - - `__llvm_or_i128_i128 -> i128` + - (\*) `__llvm_or_i128_i128 -> i128` - [`xor`](https://llvm.org/docs/LangRef.html#xor-instruction): - `__llvm_xor_bool_bool -> bool` - `__llvm_xor_i8_i8 -> i8` - `__llvm_xor_i16_i16 -> i16` - `__llvm_xor_i32_i32 -> i32` - `__llvm_xor_i64_i64 -> i64` - - `__llvm_xor_i128_i128 -> i128` + - (\*) `__llvm_xor_i128_i128 -> i128` - [`cmpxchg`](https://llvm.org/docs/LangRef.html#cmpxchg-instruction): - Unlike the previous instructions, `cmpxchg` accepts three arguments. Some of the arguments can be integers or pointers. Pointer arguments have the `p` prefix, e.g. `pi8` is a pointer to @@ -414,14 +423,14 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_cmpxchg_pi32_pi32_pi32 -> (i32, bool)` - `__llvm_cmpxchg_pi64_i64_i64 -> (i64, bool)` - `__llvm_cmpxchg_pi64_pi64_pi64 -> (i64, bool)` - - `__llvm_cmpxchg_pi128_i128_i128 -> (i128, bool)` - - `__llvm_cmpxchg_pi128_pi128_pi128 -> (i128, bool)` + - (\*) `__llvm_cmpxchg_pi128_i128_i128 -> (i128, bool)` + - (\*) `__llvm_cmpxchg_pi128_pi128_pi128 -> (i128, bool)` - [`trunc .. to`](https://llvm.org/docs/LangRef.html#trunc-to-instruction): - - `__llvm_trunc_i128_to_i64 -> i64` - - `__llvm_trunc_i128_to_i32 -> i32` - - `__llvm_trunc_i128_to_i16 -> i16` - - `__llvm_trunc_i128_to_i8 -> i8` - - `__llvm_trunc_i128_to_bool -> bool` + - (\*) `__llvm_trunc_i128_to_i64 -> i64` + - (\*) `__llvm_trunc_i128_to_i32 -> i32` + - (\*) `__llvm_trunc_i128_to_i16 -> i16` + - (\*) `__llvm_trunc_i128_to_i8 -> i8` + - (\*) `__llvm_trunc_i128_to_bool -> bool` - `__llvm_trunc_i64_to_i32 -> i32` - `__llvm_trunc_i64_to_i16 -> i16` - `__llvm_trunc_i64_to_i8 -> i8` @@ -433,184 +442,184 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_trunc_i16_to_bool -> bool` - `__llvm_trunc_i8_to_bool -> bool` - [`zext .. to`](https://llvm.org/docs/LangRef.html#zext-to-instruction): - - `__llvm_zext_bool_to_i128 -> i128` + - (\*) `__llvm_zext_bool_to_i128 -> i128` - `__llvm_zext_bool_to_i64 -> i64` - `__llvm_zext_bool_to_i32 -> i32` - `__llvm_zext_bool_to_i16 -> i16` - `__llvm_zext_bool_to_i8 -> i8` - - `__llvm_zext_i8_to_i128 -> i128` + - (\*) `__llvm_zext_i8_to_i128 -> i128` - `__llvm_zext_i8_to_i64 -> i64` - `__llvm_zext_i8_to_i32 -> i32` - `__llvm_zext_i8_to_i16 -> i16` - - `__llvm_zext_i16_to_i128 -> i128` + - (\*) `__llvm_zext_i16_to_i128 -> i128` - `__llvm_zext_i16_to_i64 -> i64` - `__llvm_zext_i16_to_i32 -> i32` - - `__llvm_zext_i32_to_i128 -> i128` + - (\*) `__llvm_zext_i32_to_i128 -> i128` - `__llvm_zext_i32_to_i64 -> i64` - - `__llvm_zext_i64_to_i128 -> i128` + - (\*) `__llvm_zext_i64_to_i128 -> i128` - [`sext .. to`](https://llvm.org/docs/LangRef.html#sext-to-instruction): - - `__llvm_sext_bool_to_i128 -> i128` + - (\*) `__llvm_sext_bool_to_i128 -> i128` - `__llvm_sext_bool_to_i64 -> i64` - `__llvm_sext_bool_to_i32 -> i32` - `__llvm_sext_bool_to_i16 -> i16` - `__llvm_sext_bool_to_i8 -> i8` - - `__llvm_sext_i8_to_i128 -> i128` + - (\*) `__llvm_sext_i8_to_i128 -> i128` - `__llvm_sext_i8_to_i64 -> i64` - `__llvm_sext_i8_to_i32 -> i32` - `__llvm_sext_i8_to_i16 -> i16` - - `__llvm_sext_i16_to_i128 -> i128` + - (\*) `__llvm_sext_i16_to_i128 -> i128` - `__llvm_sext_i16_to_i64 -> i64` - `__llvm_sext_i16_to_i32 -> i32` - - `__llvm_sext_i32_to_i128 -> i128` + - (\*) `__llvm_sext_i32_to_i128 -> i128` - `__llvm_sext_i32_to_i64 -> i64` - - `__llvm_sext_i64_to_i128 -> i128` + - (\*) `__llvm_sext_i64_to_i128 -> i128` - [`ptrtoint .. to`](https://llvm.org/docs/LangRef.html#ptrtoint-to-instruction): - `__llvm_ptrtoint_pbool_to_bool -> bool` - `__llvm_ptrtoint_pbool_to_i8 -> i8` - `__llvm_ptrtoint_pbool_to_i16 -> i16` - `__llvm_ptrtoint_pbool_to_i32 -> i32` - `__llvm_ptrtoint_pbool_to_i64 -> i64` - - `__llvm_ptrtoint_pbool_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pbool_to_i128 -> i128` - `__llvm_ptrtoint_pi8_to_bool -> bool` - `__llvm_ptrtoint_pi8_to_i8 -> i8` - `__llvm_ptrtoint_pi8_to_i16 -> i16` - `__llvm_ptrtoint_pi8_to_i32 -> i32` - `__llvm_ptrtoint_pi8_to_i64 -> i64` - - `__llvm_ptrtoint_pi8_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pi8_to_i128 -> i128` - `__llvm_ptrtoint_pi16_to_bool -> bool` - `__llvm_ptrtoint_pi16_to_i8 -> i8` - `__llvm_ptrtoint_pi16_to_i16 -> i16` - `__llvm_ptrtoint_pi16_to_i32 -> i32` - `__llvm_ptrtoint_pi16_to_i64 -> i64` - - `__llvm_ptrtoint_pi16_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pi16_to_i128 -> i128` - `__llvm_ptrtoint_pi32_to_bool -> bool` - `__llvm_ptrtoint_pi32_to_i8 -> i8` - `__llvm_ptrtoint_pi32_to_i16 -> i16` - `__llvm_ptrtoint_pi32_to_i32 -> i32` - `__llvm_ptrtoint_pi32_to_i64 -> i64` - - `__llvm_ptrtoint_pi32_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pi32_to_i128 -> i128` - `__llvm_ptrtoint_pi64_to_bool -> bool` - `__llvm_ptrtoint_pi64_to_i8 -> i8` - `__llvm_ptrtoint_pi64_to_i16 -> i16` - `__llvm_ptrtoint_pi64_to_i32 -> i32` - `__llvm_ptrtoint_pi64_to_i64 -> i64` - - `__llvm_ptrtoint_pi64_to_i128 -> i128` - - `__llvm_ptrtoint_pi128_to_bool -> bool` - - `__llvm_ptrtoint_pi128_to_i8 -> i8` - - `__llvm_ptrtoint_pi128_to_i16 -> i16` - - `__llvm_ptrtoint_pi128_to_i32 -> i32` - - `__llvm_ptrtoint_pi128_to_i64 -> i64` - - `__llvm_ptrtoint_pi128_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pi64_to_i128 -> i128` + - (\*) `__llvm_ptrtoint_pi128_to_bool -> bool` + - (\*) `__llvm_ptrtoint_pi128_to_i8 -> i8` + - (\*) `__llvm_ptrtoint_pi128_to_i16 -> i16` + - (\*) `__llvm_ptrtoint_pi128_to_i32 -> i32` + - (\*) `__llvm_ptrtoint_pi128_to_i64 -> i64` + - (\*) `__llvm_ptrtoint_pi128_to_i128 -> i128` - [`inttoptr .. to`](https://llvm.org/docs/LangRef.html#inttoptr-to-instruction): - `__llvm_inttoptr_bool_to_pbool -> pbool` - `__llvm_inttoptr_bool_to_pi8 -> pi8` - `__llvm_inttoptr_bool_to_pi16 -> pi16` - `__llvm_inttoptr_bool_to_pi32 -> pi32` - `__llvm_inttoptr_bool_to_pi64 -> pi64` - - `__llvm_inttoptr_bool_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_bool_to_pi128 -> pi128` - `__llvm_inttoptr_i8_to_pbool -> pbool` - `__llvm_inttoptr_i8_to_pi8 -> pi8` - `__llvm_inttoptr_i8_to_pi16 -> pi16` - `__llvm_inttoptr_i8_to_pi32 -> pi32` - `__llvm_inttoptr_i8_to_pi64 -> pi64` - - `__llvm_inttoptr_i8_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_i8_to_pi128 -> pi128` - `__llvm_inttoptr_i16_to_pbool -> pbool` - `__llvm_inttoptr_i16_to_pi8 -> pi8` - `__llvm_inttoptr_i16_to_pi16 -> pi16` - `__llvm_inttoptr_i16_to_pi32 -> pi32` - `__llvm_inttoptr_i16_to_pi64 -> pi64` - - `__llvm_inttoptr_i16_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_i16_to_pi128 -> pi128` - `__llvm_inttoptr_i32_to_pbool -> pbool` - `__llvm_inttoptr_i32_to_pi8 -> pi8` - `__llvm_inttoptr_i32_to_pi16 -> pi16` - `__llvm_inttoptr_i32_to_pi32 -> pi32` - `__llvm_inttoptr_i32_to_pi64 -> pi64` - - `__llvm_inttoptr_i32_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_i32_to_pi128 -> pi128` - `__llvm_inttoptr_i64_to_pbool -> pbool` - `__llvm_inttoptr_i64_to_pi8 -> pi8` - `__llvm_inttoptr_i64_to_pi16 -> pi16` - `__llvm_inttoptr_i64_to_pi32 -> pi32` - `__llvm_inttoptr_i64_to_pi64 -> pi64` - - `__llvm_inttoptr_i64_to_pi128 -> pi128` - - `__llvm_inttoptr_i128_to_pbool -> pbool` - - `__llvm_inttoptr_i128_to_pi8 -> pi8` - - `__llvm_inttoptr_i128_to_pi16 -> pi16` - - `__llvm_inttoptr_i128_to_pi32 -> pi32` - - `__llvm_inttoptr_i128_to_pi64 -> pi64` - - `__llvm_inttoptr_i128_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_i64_to_pi128 -> pi128` + - (\*) `__llvm_inttoptr_i128_to_pbool -> pbool` + - (\*) `__llvm_inttoptr_i128_to_pi8 -> pi8` + - (\*) `__llvm_inttoptr_i128_to_pi16 -> pi16` + - (\*) `__llvm_inttoptr_i128_to_pi32 -> pi32` + - (\*) `__llvm_inttoptr_i128_to_pi64 -> pi64` + - (\*) `__llvm_inttoptr_i128_to_pi128 -> pi128` - [`bitcast .. to`](https://llvm.org/docs/LangRef.html#bitcast-to-instruction): - `__llvm_bitcast_bool_to_bool -> bool` - `__llvm_bitcast_bool_to_i8 -> i8` - `__llvm_bitcast_bool_to_i16 -> i16` - `__llvm_bitcast_bool_to_i32 -> i32` - `__llvm_bitcast_bool_to_i64 -> i64` - - `__llvm_bitcast_bool_to_i128 -> i128` + - (\*) `__llvm_bitcast_bool_to_i128 -> i128` - `__llvm_bitcast_i8_to_bool -> bool` - `__llvm_bitcast_i8_to_i8 -> i8` - `__llvm_bitcast_i8_to_i16 -> i16` - `__llvm_bitcast_i8_to_i32 -> i32` - `__llvm_bitcast_i8_to_i64 -> i64` - - `__llvm_bitcast_i8_to_i128 -> i128` + - (\*) `__llvm_bitcast_i8_to_i128 -> i128` - `__llvm_bitcast_i16_to_bool -> bool` - `__llvm_bitcast_i16_to_i8 -> i8` - `__llvm_bitcast_i16_to_i16 -> i16` - `__llvm_bitcast_i16_to_i32 -> i32` - `__llvm_bitcast_i16_to_i64 -> i64` - - `__llvm_bitcast_i16_to_i128 -> i128` + - (\*) `__llvm_bitcast_i16_to_i128 -> i128` - `__llvm_bitcast_i32_to_bool -> bool` - `__llvm_bitcast_i32_to_i8 -> i8` - `__llvm_bitcast_i32_to_i16 -> i16` - `__llvm_bitcast_i32_to_i32 -> i32` - `__llvm_bitcast_i32_to_i64 -> i64` - - `__llvm_bitcast_i32_to_i128 -> i128` + - (\*) `__llvm_bitcast_i32_to_i128 -> i128` - `__llvm_bitcast_i64_to_bool -> bool` - `__llvm_bitcast_i64_to_i8 -> i8` - `__llvm_bitcast_i64_to_i16 -> i16` - `__llvm_bitcast_i64_to_i32 -> i32` - `__llvm_bitcast_i64_to_i64 -> i64` - - `__llvm_bitcast_i64_to_i128 -> i128` - - `__llvm_bitcast_i128_to_bool -> bool` - - `__llvm_bitcast_i128_to_i8 -> i8` - - `__llvm_bitcast_i128_to_i16 -> i16` - - `__llvm_bitcast_i128_to_i32 -> i32` - - `__llvm_bitcast_i128_to_i64 -> i64` - - `__llvm_bitcast_i128_to_i128 -> i128` + - (\*) `__llvm_bitcast_i64_to_i128 -> i128` + - (\*) `__llvm_bitcast_i128_to_bool -> bool` + - (\*) `__llvm_bitcast_i128_to_i8 -> i8` + - (\*) `__llvm_bitcast_i128_to_i16 -> i16` + - (\*) `__llvm_bitcast_i128_to_i32 -> i32` + - (\*) `__llvm_bitcast_i128_to_i64 -> i64` + - (\*) `__llvm_bitcast_i128_to_i128 -> i128` - `__llvm_bitcast_pbool_to_pbool -> pbool` - `__llvm_bitcast_pbool_to_pi8 -> pi8` - `__llvm_bitcast_pbool_to_pi16 -> pi16` - `__llvm_bitcast_pbool_to_pi32 -> pi32` - `__llvm_bitcast_pbool_to_pi64 -> pi64` - - `__llvm_bitcast_pbool_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pbool_to_pi128 -> pi128` - `__llvm_bitcast_pi8_to_pbool -> pbool` - `__llvm_bitcast_pi8_to_pi8 -> pi8` - `__llvm_bitcast_pi8_to_pi16 -> pi16` - `__llvm_bitcast_pi8_to_pi32 -> pi32` - `__llvm_bitcast_pi8_to_pi64 -> pi64` - - `__llvm_bitcast_pi8_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pi8_to_pi128 -> pi128` - `__llvm_bitcast_pi16_to_pbool -> pbool` - `__llvm_bitcast_pi16_to_pi8 -> pi8` - `__llvm_bitcast_pi16_to_pi16 -> pi16` - `__llvm_bitcast_pi16_to_pi32 -> pi32` - `__llvm_bitcast_pi16_to_pi64 -> pi64` - - `__llvm_bitcast_pi16_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pi16_to_pi128 -> pi128` - `__llvm_bitcast_pi32_to_pbool -> pbool` - `__llvm_bitcast_pi32_to_pi8 -> pi8` - `__llvm_bitcast_pi32_to_pi16 -> pi16` - `__llvm_bitcast_pi32_to_pi32 -> pi32` - `__llvm_bitcast_pi32_to_pi64 -> pi64` - - `__llvm_bitcast_pi32_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pi32_to_pi128 -> pi128` - `__llvm_bitcast_pi64_to_pbool -> pbool` - `__llvm_bitcast_pi64_to_pi8 -> pi8` - `__llvm_bitcast_pi64_to_pi16 -> pi16` - `__llvm_bitcast_pi64_to_pi32 -> pi32` - `__llvm_bitcast_pi64_to_pi64 -> pi64` - - `__llvm_bitcast_pi64_to_pi128 -> pi128` - - `__llvm_bitcast_pi128_to_pbool -> pbool` - - `__llvm_bitcast_pi128_to_pi8 -> pi8` - - `__llvm_bitcast_pi128_to_pi16 -> pi16` - - `__llvm_bitcast_pi128_to_pi32 -> pi32` - - `__llvm_bitcast_pi128_to_pi64 -> pi64` - - `__llvm_bitcast_pi128_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pi64_to_pi128 -> pi128` + - (\*) `__llvm_bitcast_pi128_to_pbool -> pbool` + - (\*) `__llvm_bitcast_pi128_to_pi8 -> pi8` + - (\*) `__llvm_bitcast_pi128_to_pi16 -> pi16` + - (\*) `__llvm_bitcast_pi128_to_pi32 -> pi32` + - (\*) `__llvm_bitcast_pi128_to_pi64 -> pi64` + - (\*) `__llvm_bitcast_pi128_to_pi128 -> pi128` - [`icmp`](https://llvm.org/docs/LangRef.html#icmp-instruction): - `icmp` accepts three arguments. The first is a comparison condition. The two others are operands of the same type. The condition is defined as an enum consisting of these values: `eq`, `ne`, @@ -620,14 +629,14 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_icmp_cond_i16_i16 -> bool`, - `__llvm_icmp_cond_i32_i32 -> bool`, - `__llvm_icmp_cond_i64_i64 -> bool`, - - `__llvm_icmp_cond_i128_i128 -> bool`, + - (\*) `__llvm_icmp_cond_i128_i128 -> bool`, - [`select`](https://llvm.org/docs/LangRef.html#select-instruction): - `__llvm_select_bool_bool_bool -> bool`, - `__llvm_select_bool_i8_i8 -> bool`, - `__llvm_select_bool_i16_i16 -> bool`, - `__llvm_select_bool_i32_i32 -> bool`, - `__llvm_select_bool_i64_i64 -> bool`, - - `__llvm_select_bool_i128_i128 -> bool`, + - (\*) `__llvm_select_bool_i128_i128 -> bool`, #### Based on Intrinsics @@ -636,35 +645,35 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_abs_i16 -> i16`, - `__llvm_abs_i32 -> i32`, - `__llvm_abs_i64 -> i64`, - - `__llvm_abs_i128 -> i128`, + - (\*) `__llvm_abs_i128 -> i128`, - [`llvm.smax.*`](https://llvm.org/docs/LangRef.html#llvm-smax-intrinsic): - `__llvm_smax_bool_bool -> bool`, - `__llvm_smax_i8_i8 -> i8`, - `__llvm_smax_i16_i8 -> i16`, - `__llvm_smax_i32_i8 -> i32`, - `__llvm_smax_i64_i8 -> i64`, - - `__llvm_smax_i128_i8 -> i128`, + - (\*) `__llvm_smax_i128_i8 -> i128`, - [`llvm.smin.*`](https://llvm.org/docs/LangRef.html#llvm-smin-intrinsic): - `__llvm_smin_bool_bool -> bool`, - `__llvm_smin_i8_i8 -> i8`, - `__llvm_smin_i16_i8 -> i16`, - `__llvm_smin_i32_i8 -> i32`, - `__llvm_smin_i64_i8 -> i64`, - - `__llvm_smin_i128_i8 -> i128`, + - (\*) `__llvm_smin_i128_i8 -> i128`, - [`llvm_umax.*`](https://llvm.org/docs/LangRef.html#llvm-umax-intrinsic): - `__llvm_umax_bool_bool -> bool`, - `__llvm_umax_i8_i8 -> i8`, - `__llvm_umax_i16_i8 -> i16`, - `__llvm_umax_i32_i8 -> i32`, - `__llvm_umax_i64_i8 -> i64`, - - `__llvm_umax_i128_i8 -> i128`, + - (\*) `__llvm_umax_i128_i8 -> i128`, - [`llvm.umin.*`](https://llvm.org/docs/LangRef.html#llvm-umin-intrinsic): - `__llvm_umin_bool_bool -> bool`, - `__llvm_umin_i8_i8 -> i8`, - `__llvm_umin_i16_i8 -> i16`, - `__llvm_umin_i32_i8 -> i32`, - `__llvm_umin_i64_i8 -> i64`, - - `__llvm_umin_i128_i8 -> i128`, + - (\*) `__llvm_umin_i128_i8 -> i128`, - [`llvm.scmp.*`](https://llvm.org/docs/LangRef.html#llvm-scmp-intrinsic): - `scmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the closest possible type is `i8`. @@ -673,7 +682,7 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_scmp_i16_i8 -> i8`, - `__llvm_scmp_i32_i8 -> i8`, - `__llvm_scmp_i64_i8 -> i8`, - - `__llvm_scmp_i128_i8 -> i8`, + - (\*) `__llvm_scmp_i128_i8 -> i8`, - [`llvm.ucmp.*`](https://llvm.org/docs/LangRef.html#llvm-ucmp-intrinsic): - `ucmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the closest possible type is `i8`. @@ -682,27 +691,27 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_ucmp_i16_i8 -> i8`, - `__llvm_ucmp_i32_i8 -> i8`, - `__llvm_ucmp_i64_i8 -> i8`, - - `__llvm_ucmp_i128_i8 -> i8`, + - (\*) `__llvm_ucmp_i128_i8 -> i8`, - [`llvm.bitreverse.*`]https://llvm.org/docs/LangRef.html#llvm-bitreverse-intrinsics): - `__llvm_bitreverse_bool -> bool`, - `__llvm_bitreverse_i8 -> i8`, - `__llvm_bitreverse_i16 -> i16`, - `__llvm_bitreverse_i32 -> i32`, - `__llvm_bitreverse_i64 -> i64`, - - `__llvm_bitreverse_i128 -> i128`, + - (\*) `__llvm_bitreverse_i128 -> i128`, - [`llvm.bswap.*`](https://llvm.org/docs/LangRef.html#llvm-bswap-intrinsics): - `__llvm_bswap_i8 -> i8`, - `__llvm_bswap_i16 -> i16`, - `__llvm_bswap_i32 -> i32`, - `__llvm_bswap_i64 -> i64`, - - `__llvm_bswap_i128 -> i128`, + - (\*) `__llvm_bswap_i128 -> i128`, - [`llvm.ctpop.*`](https://llvm.org/docs/LangRef.html#llvm-ctpop-intrinsics): - `__llvm_ctpop_bool -> bool`, - `__llvm_ctpop_i8 -> i8`, - `__llvm_ctpop_i16 -> i16`, - `__llvm_ctpop_i32 -> i32`, - `__llvm_ctpop_i64 -> i64`, - - `__llvm_ctpop_i128 -> i128`, + - (\*) `__llvm_ctpop_i128 -> i128`, - [`llvm.ctlz.*`](https://llvm.org/docs/LangRef.html#llvm-ctlz-intrinsics): - `__llvm_ctlz_bool -> bool`, - `__llvm_ctlz_i8 -> i8`, @@ -716,88 +725,88 @@ relevant part of the LLVM Language Reference Manual. - `__llvm_cttz_i16 -> i16`, - `__llvm_cttz_i32 -> i32`, - `__llvm_cttz_i64 -> i64`, - - `__llvm_cttz_i128 -> i128`, + - (\*) `__llvm_cttz_i128 -> i128`, - [`llvm.fshl.*`](https://llvm.org/docs/LangRef.html#llvm-fshl-intrinsics): - `__llvm_fshl_i8_i8_i8 -> i8`, - `__llvm_fshl_i16_i16_i16 -> i16`, - `__llvm_fshl_i32_i32_i32 -> i32`, - `__llvm_fshl_i64_i64_i64 -> i64`, - - `__llvm_fshl_i128_i128_i128 -> i128`, + - (\*) `__llvm_fshl_i128_i128_i128 -> i128`, - [`llvm.fshr.*`](https://llvm.org/docs/LangRef.html#llvm-fshr-intrinsics): - `__llvm_fshr_i8_i8_i8 -> i8`, - `__llvm_fshr_i16_i16_i16 -> i16`, - `__llvm_fshr_i32_i32_i32 -> i32`, - `__llvm_fshr_i64_i64_i64 -> i64`, - - `__llvm_fshr_i128_i128_i128 -> i128`, + - (\*) `__llvm_fshr_i128_i128_i128 -> i128`, - [`llvm.sadd.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-sadd-with-overflow-intrinsics): - `__llvm_sadd_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_sadd_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_sadd_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_sadd_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_sadd_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_sadd_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.uadd.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-uadd-with-overflow-intrinsics): - `__llvm_uadd_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_uadd_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_uadd_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_uadd_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_uadd_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_uadd_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.ssub.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-ssub-with-overflow-intrinsics): - `__llvm_ssub_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_ssub_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_ssub_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_ssub_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_ssub_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_ssub_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.usub.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-usub-with-overflow-intrinsics): - `__llvm_usub_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_usub_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_usub_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_usub_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_usub_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_usub_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.smul.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-smul-with-overflow-intrinsics): - `__llvm_smul_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_smul_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_smul_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_smul_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_smul_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_smul_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.umul.with.overflow.*`](https://llvm.org/docs/LangRef.html#llvm-umul-with-overflow-intrinsics): - `__llvm_umul_with_overflow_i8_i8 -> (i8, bool)`, - `__llvm_umul_with_overflow_i16_i16 -> (i16, bool)`, - `__llvm_umul_with_overflow_i32_i32 -> (i32, bool)`, - `__llvm_umul_with_overflow_i64_i64 -> (i64, bool)`, - - `__llvm_umul_with_overflow_i128_i128 -> (i128, bool)`, + - (\*) `__llvm_umul_with_overflow_i128_i128 -> (i128, bool)`, - [`llvm.sadd.sat.*`](https://llvm.org/docs/LangRef.html#llvm-sadd-sat-intrinsics): - `__llvm_sadd_sat_i8_i8 -> i8`, - `__llvm_sadd_sat_i16_i16 -> i16`, - `__llvm_sadd_sat_i32_i32 -> i32`, - `__llvm_sadd_sat_i64_i64 -> i64`, - - `__llvm_sadd_sat_i128_i128 -> i128`, + - (\*) `__llvm_sadd_sat_i128_i128 -> i128`, - [`llvm.uadd.sat.*`](https://llvm.org/docs/LangRef.html#llvm-uadd-sat-intrinsics): - `__llvm_uadd_sat_i8_i8 -> i8`, - `__llvm_uadd_sat_i16_i16 -> i16`, - `__llvm_uadd_sat_i32_i32 -> i32`, - `__llvm_uadd_sat_i64_i64 -> i64`, - - `__llvm_uadd_sat_i128_i128 -> i128`, + - (\*) `__llvm_uadd_sat_i128_i128 -> i128`, - [`llvm.ssub.sat.*`](https://llvm.org/docs/LangRef.html#llvm-ssub-sat-intrinsics): - `__llvm_ssub_sat_i8_i8 -> i8`, - `__llvm_ssub_sat_i16_i16 -> i16`, - `__llvm_ssub_sat_i32_i32 -> i32`, - `__llvm_ssub_sat_i64_i64 -> i64`, - - `__llvm_ssub_sat_i128_i128 -> i128`, + - (\*) `__llvm_ssub_sat_i128_i128 -> i128`, - [`llvm.usub.sat.*`](https://llvm.org/docs/LangRef.html#llvm-usub-sat-intrinsics): - `__llvm_usub_sat_i8_i8 -> i8`, - `__llvm_usub_sat_i16_i16 -> i16`, - `__llvm_usub_sat_i32_i32 -> i32`, - `__llvm_usub_sat_i64_i64 -> i64`, - - `__llvm_usub_sat_i128_i128 -> i128`, + - (\*) `__llvm_usub_sat_i128_i128 -> i128`, - [`llvm.sshl.sat.*`](https://llvm.org/docs/LangRef.html#llvm-sshl-sat-intrinsics): - `__llvm_sshl_sat_i8_i8 -> i8`, - `__llvm_sshl_sat_i16_i16 -> i16`, - `__llvm_sshl_sat_i32_i32 -> i32`, - `__llvm_sshl_sat_i64_i64 -> i64`, - - `__llvm_sshl_sat_i128_i128 -> i128`, + - (\*) `__llvm_sshl_sat_i128_i128 -> i128`, - [`llvm.ushl.sat.*`](https://llvm.org/docs/LangRef.html#llvm-ushl-sat-intrinsics): - `__llvm_ushl_sat_i8_i8 -> i8`, - `__llvm_ushl_sat_i16_i16 -> i16`, - `__llvm_ushl_sat_i32_i32 -> i32`, - `__llvm_ushl_sat_i64_i64 -> i64`, - - `__llvm_ushl_sat_i128_i128 -> i128`, + - (\*) `__llvm_ushl_sat_i128_i128 -> i128`, From 9bbbcb1d4762027989fa5a09c31acc47e767b18d Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 23:30:11 +0200 Subject: [PATCH 17/22] data types: 128 bit will come, just later --- docs/ALU Design.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 4a6c1ca..3fb7742 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -116,14 +116,11 @@ determines the length of `usize`. This specific triple has been chosen for its s and no host operating system. The pointer length is just one of its parameters we accept at this stage of the project. This target triple is a temporary choice before a custom target triple is proposed. When designing our custom triple, it is possible that the choice of `usize` and `isize` -width will be reevaluated and possibly changed to match the width of the field element. Also, since -`aarch64-unknown-none-softfloat` does not naturally support 128 bit integers, we do not expect LLVM -to generate `i128` in the IR. Our custom triple may support this data type. - -Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32 and 64 bits. -After proposing our custom triple, we will expect 128 bit integers to appear in the IR, which will -require extending the polyfills set with `i128` support. We do not intend to support operations over -arbitrary-width integers. +width will be reevaluated and possibly changed to match the width of the field element. + +Summing up, we expect to see in the IR integers of the following lengths: 1, 8, 16, 32, 64 and 128 +bits. We do not intend to support operations over arbitrary-width integers. We also decided to add +support for 128 bit integers in later phase of the project. #### Pointers From 09214dcbffb85965d5bbe75a5dabff53aacad729 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 23:32:18 +0200 Subject: [PATCH 18/22] scmp, ucmp: i2 -> i8 is ok --- docs/ALU Design.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 3fb7742..d701d28 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -672,8 +672,10 @@ phase. See [Data Types](#data-types) for details. - `__llvm_umin_i64_i8 -> i64`, - (\*) `__llvm_umin_i128_i8 -> i128`, - [`llvm.scmp.*`](https://llvm.org/docs/LangRef.html#llvm-scmp-intrinsic): - - `scmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the - closest possible type is `i8`. + - As per the LLVM Language Reference Manual, `scmp` returns needs to return at least `i2`. Since + ALU does not operate on such type, the closest possible type is `i8`. Luckily, + [this is what LLVM generates](https://blog.llvm.org/posts/2024-08-29-gsoc-three-way-comparison/) + for these intrinsics, therefore our implementations will follow this pattern. - `__llvm_ucmp_bool_bool -> i8`, - `__llvm_scmp_i8_i8 -> i8`, - `__llvm_scmp_i16_i8 -> i8`, @@ -681,8 +683,10 @@ phase. See [Data Types](#data-types) for details. - `__llvm_scmp_i64_i8 -> i8`, - (\*) `__llvm_scmp_i128_i8 -> i8`, - [`llvm.ucmp.*`](https://llvm.org/docs/LangRef.html#llvm-ucmp-intrinsic): - - `ucmp` returns needs to return at least `i2`. Since ALU does not operate on such type, the - closest possible type is `i8`. + - As per the LLVM Language Reference Manual, `ucmp` returns needs to return at least `i2`. Since + ALU does not operate on such type, the closest possible type is `i8`. Luckily, + [this is what LLVM generates](https://blog.llvm.org/posts/2024-08-29-gsoc-three-way-comparison/) + for these intrinsics, therefore our implementations will follow this pattern. - `__llvm_ucmp_bool_bool -> i8`, - `__llvm_ucmp_i8_i8 -> i8`, - `__llvm_ucmp_i16_i8 -> i8`, From d99c3732fc4016584d56f28dd8f7b752abe6b9f5 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 23:50:58 +0200 Subject: [PATCH 19/22] icmp: discrete implementations instead of an enum condition --- docs/ALU Design.md | 69 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index d701d28..015ea04 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -618,15 +618,66 @@ phase. See [Data Types](#data-types) for details. - (\*) `__llvm_bitcast_pi128_to_pi64 -> pi64` - (\*) `__llvm_bitcast_pi128_to_pi128 -> pi128` - [`icmp`](https://llvm.org/docs/LangRef.html#icmp-instruction): - - `icmp` accepts three arguments. The first is a comparison condition. The two others are operands - of the same type. The condition is defined as an enum consisting of these values: `eq`, `ne`, - `ugt`, `uge`, `ult`, `ule`, `sgt`, `sge`, `slt`, `sle`. - - `__llvm_icmp_cond_bool_bool -> bool`, - - `__llvm_icmp_cond_i8_i8 -> bool`, - - `__llvm_icmp_cond_i16_i16 -> bool`, - - `__llvm_icmp_cond_i32_i32 -> bool`, - - `__llvm_icmp_cond_i64_i64 -> bool`, - - (\*) `__llvm_icmp_cond_i128_i128 -> bool`, + - `__llvm_icmp_eq_bool_bool -> bool`, + - `__llvm_icmp_eq_i8_i8 -> bool`, + - `__llvm_icmp_eq_i16_i16 -> bool`, + - `__llvm_icmp_eq_i32_i32 -> bool`, + - `__llvm_icmp_eq_i64_i64 -> bool`, + - (\*) `__llvm_icmp_eq_i128_i128 -> bool`, + - `__llvm_icmp_ne_bool_bool -> bool`, + - `__llvm_icmp_ne_i8_i8 -> bool`, + - `__llvm_icmp_ne_i16_i16 -> bool`, + - `__llvm_icmp_ne_i32_i32 -> bool`, + - `__llvm_icmp_ne_i64_i64 -> bool`, + - (\*) `__llvm_icmp_ne_i128_i128 -> bool`, + - `__llvm_icmp_ugt_bool_bool -> bool`, + - `__llvm_icmp_ugt_i8_i8 -> bool`, + - `__llvm_icmp_ugt_i16_i16 -> bool`, + - `__llvm_icmp_ugt_i32_i32 -> bool`, + - `__llvm_icmp_ugt_i64_i64 -> bool`, + - (\*) `__llvm_icmp_ugt_i128_i128 -> bool`, + - `__llvm_icmp_uge_bool_bool -> bool`, + - `__llvm_icmp_uge_i8_i8 -> bool`, + - `__llvm_icmp_uge_i16_i16 -> bool`, + - `__llvm_icmp_uge_i32_i32 -> bool`, + - `__llvm_icmp_uet_i64_i64 -> bool`, + - (\*) `__llvm_icmp_uge_i128_i128 -> bool`, + - `__llvm_icmp_ult_bool_bool -> bool`, + - `__llvm_icmp_ult_i8_i8 -> bool`, + - `__llvm_icmp_ult_i16_i16 -> bool`, + - `__llvm_icmp_ult_i32_i32 -> bool`, + - `__llvm_icmp_ult_i64_i64 -> bool`, + - (\*) `__llvm_icmp_ult_i128_i128 -> bool`, + - `__llvm_icmp_ule_bool_bool -> bool`, + - `__llvm_icmp_ule_i8_i8 -> bool`, + - `__llvm_icmp_ule_i16_i16 -> bool`, + - `__llvm_icmp_ule_i32_i32 -> bool`, + - `__llvm_icmp_ule_i64_i64 -> bool`, + - (\*) `__llvm_icmp_ule_i128_i128 -> bool`, + - `__llvm_icmp_sgt_bool_bool -> bool`, + - `__llvm_icmp_sgt_i8_i8 -> bool`, + - `__llvm_icmp_sgt_i16_i16 -> bool`, + - `__llvm_icmp_sgt_i32_i32 -> bool`, + - `__llvm_icmp_sgt_i64_i64 -> bool`, + - (\*) `__llvm_icmp_sgt_i128_i128 -> bool`, + - `__llvm_icmp_sge_bool_bool -> bool`, + - `__llvm_icmp_sge_i8_i8 -> bool`, + - `__llvm_icmp_sge_i16_i16 -> bool`, + - `__llvm_icmp_sge_i32_i32 -> bool`, + - `__llvm_icmp_sge_i64_i64 -> bool`, + - (\*) `__llvm_icmp_sge_i128_i128 -> bool`, + - `__llvm_icmp_slt_bool_bool -> bool`, + - `__llvm_icmp_slt_i8_i8 -> bool`, + - `__llvm_icmp_slt_i16_i16 -> bool`, + - `__llvm_icmp_slt_i32_i32 -> bool`, + - `__llvm_icmp_slt_i64_i64 -> bool`, + - (\*) `__llvm_icmp_slt_i128_i128 -> bool`, + - `__llvm_icmp_sle_bool_bool -> bool`, + - `__llvm_icmp_sle_i8_i8 -> bool`, + - `__llvm_icmp_sle_i16_i16 -> bool`, + - `__llvm_icmp_sle_i32_i32 -> bool`, + - `__llvm_icmp_sle_i64_i64 -> bool`, + - (\*) `__llvm_icmp_sle_i128_i128 -> bool`, - [`select`](https://llvm.org/docs/LangRef.html#select-instruction): - `__llvm_select_bool_bool_bool -> bool`, - `__llvm_select_bool_i8_i8 -> bool`, From 8bd55dd7ee0ce3955fe79575728ac393c6e2eaf8 Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Fri, 18 Oct 2024 23:59:24 +0200 Subject: [PATCH 20/22] fix some minor typos --- docs/ALU Design.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 015ea04..781de13 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -258,7 +258,7 @@ operations implementations and those from the LLVM IR) will be linked together. As discussed in the [relevant section of the Research part](#statefulness), each operation will be a stateless block of code composed of a single Cairo -[function](https://book.cairo-lang.org/ch02-03-functions.html)(possibly composed of subroutines for +[function](https://book.cairo-lang.org/ch02-03-functions.html) (possibly composed of subroutines for common parts) which is an equivalent concept of a function in any other procedural programming language. @@ -744,7 +744,7 @@ phase. See [Data Types](#data-types) for details. - `__llvm_ucmp_i32_i8 -> i8`, - `__llvm_ucmp_i64_i8 -> i8`, - (\*) `__llvm_ucmp_i128_i8 -> i8`, -- [`llvm.bitreverse.*`]https://llvm.org/docs/LangRef.html#llvm-bitreverse-intrinsics): +- [`llvm.bitreverse.*`](https://llvm.org/docs/LangRef.html#llvm-bitreverse-intrinsics): - `__llvm_bitreverse_bool -> bool`, - `__llvm_bitreverse_i8 -> i8`, - `__llvm_bitreverse_i16 -> i16`, @@ -861,4 +861,4 @@ phase. See [Data Types](#data-types) for details. - `__llvm_ushl_sat_i16_i16 -> i16`, - `__llvm_ushl_sat_i32_i32 -> i32`, - `__llvm_ushl_sat_i64_i64 -> i64`, - - (\*) `__llvm_ushl_sat_i128_i128 -> i128`, + - (\*) `__llvm_ushl_sat_i128_i128 -> i128`. From 73217557fb2fa40adffd6b1424ad3267381ce18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20=C5=BBmuda?= <5251642+wzmuda@users.noreply.github.com> Date: Sat, 19 Oct 2024 00:50:51 +0200 Subject: [PATCH 21/22] Another set of typos and stuff Co-authored-by: Ara Adkins --- docs/ALU Design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 781de13..31e71fb 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -174,7 +174,7 @@ to an array of `i8`. Neither the Cairo VM, Cairo language nor no-std Rust have support for vectorized operations. LLVM IR has vectors as first class citizens. However, -_[vector types are used where multiple primitive data are operated in parallel using a single instruction (SIMD)](https://llvm.org/docs/LangRef.html#vector-type)_. +_vector types are [used](https://llvm.org/docs/LangRef.html#vector-type) where multiple primitive data are operated in parallel using a single instruction (SIMD)_. If Cairo target definition supplied to `rustc` does not suggest the existence of vector extension on the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, vector support is not planned as part of the initial phase of the project. @@ -249,7 +249,7 @@ implement the desired behavior, e.g. to make sure we indicate overflow on obviou ### Overview -The ALU will be implemented as a source code written in +The ALU will be implemented as source code written in [Cairo](https://book.cairo-lang.org/title-page.html). During the [LLVM-to-Cairo compilation pipeline](https://www.notion.so/reilabs/System-Architecture-113d2f80c874802b8480d997347933a2?pvs=4) the polyfills implementations will be translated to `FlatLowered` objects and then extracted to From 281a56d5edb758fff7ff7535c91a440a604e172b Mon Sep 17 00:00:00 2001 From: Wojciech Zmuda Date: Sat, 19 Oct 2024 00:55:03 +0200 Subject: [PATCH 22/22] prettyfier --- docs/ALU Design.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/ALU Design.md b/docs/ALU Design.md index 31e71fb..f180d2d 100644 --- a/docs/ALU Design.md +++ b/docs/ALU Design.md @@ -173,11 +173,12 @@ to an array of `i8`. Neither the Cairo VM, Cairo language nor no-std Rust have support for vectorized operations. -LLVM IR has vectors as first class citizens. However, -_vector types are [used](https://llvm.org/docs/LangRef.html#vector-type) where multiple primitive data are operated in parallel using a single instruction (SIMD)_. -If Cairo target definition supplied to `rustc` does not suggest the existence of vector extension on -the target platform, we would not expect any vector intrinsics to appear in the IR. Therefore, -vector support is not planned as part of the initial phase of the project. +LLVM IR has vectors as first class citizens. However, _vector types are +[used](https://llvm.org/docs/LangRef.html#vector-type) where multiple primitive data are operated in +parallel using a single instruction (SIMD)_. If Cairo target definition supplied to `rustc` does not +suggest the existence of vector extension on the target platform, we would not expect any vector +intrinsics to appear in the IR. Therefore, vector support is not planned as part of the initial +phase of the project. #### Type Conversion