Skip to content

Add lookup-table instructions (LUTI) Learning Path - #3663

Open
audevuilli wants to merge 1 commit into
ArmDeveloperEcosystem:mainfrom
audevuilli:luti-learning-path
Open

Add lookup-table instructions (LUTI) Learning Path#3663
audevuilli wants to merge 1 commit into
ArmDeveloperEcosystem:mainfrom
audevuilli:luti-learning-path

Conversation

@audevuilli

Copy link
Copy Markdown

Introduce the LUTI concepts, code implementation, and validation.

Before submitting a pull request for a new Learning Path, please review Create a Learning Path

  • I have reviewed Create a Learning Path

Please do not include any confidential information in your contribution. This includes confidential microarchitecture details and unannounced product information.

  • I have checked my contribution for confidential information

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the Creative Commons Attribution 4.0 International License.

* Introduce the lookup-table instructions (LUTI): concepts, code implementation, and validation.

Signed-off-by: Aude Vuilliomenet <aude.vuilliomenet@arm.com>
</em>
</p>

This approach trades reconstruction accuracy for lower memory use. Its value also depends on decoding the packed codes efficiently. LUTI addresses that work by expanding low-bit codes directly into arithmetic-ready vector values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"LUTI addresses that work by expanding low-bit codes directly into arithmetic-ready vector values."
Whilst grammatically correct, this sentence is prone to mis-parsing by the reader because "addresses" can be a noun or a verb and "work" can be a noun or intransitive verb. I think your intended meaning was:
noun(LUTI) verb(addresses) that noun(work) by...
However I initially read it as:
noun(LUTI addresses) that verb(work) by...
Consequently it read to me as an incomplete sentence, until after some time I was able to parse it the way you had intended. Let's make it easy on the reader by amending it to:
"LUTI achieves that by expanding low-bit codes directly into arithmetic-ready vector values."
Sorry for the long explanation!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The second-from-right purple box should read "LUT [1]" or alternatively the second-from-right orange box should read "00".


## Identify LUTI responsibilities

Keep these boundaries in mind when using LUTI:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Keep these boundaries in mind..."
->
"Keep these points in mind..."

```asm
smstart // Enable Streaming SVE mode and ZA/ZT0 state
zero {za} // Zero initialize accumulators for this output tile
ldr zt0, [x_lut] // load LUT into fixed 512-bit ZT0 table

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Having used lut_i8_i2 on line 97, it would be good to reuse it here - or alternatively amend line 97 to use x_lut. This is just for consistency so the reader can tell it is the same register.

```asm
luti2 { z24.b - z27.b }, zt0, z16[0] // unpack 2-bit indices
luti2 { z4.b - z7.b }, zt0, z17[0]

@apickard apickard Sep 2, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is this blank line intended? Consider deleting it, but it's fine if you prefer to keep it.

{{< /tab >}}
{{< tab header="Linux host" language="bash">}}
wget https://dl.google.com/android/repository/android-ndk-r29-linux.zip
unzip android-ndk-r29-darwin.zip

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

unzip android-ndk-r29-darwin.zip
->
sudo apt update
sudo apt install unzip
unzip android-ndk-r29-linux.zip

export ANDROID_NDK_HOME=$NDK_PATH
{{< /tab >}}
{{< tab header="Linux host" language="bash">}}
export NDK_PATH=$HOME/Android/android-ndk-r29/

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

export NDK_PATH=$HOME/Android/android-ndk-r29/
->
export NDK_PATH=$HOME/android-ndk-r29/

brew install android-platform-tools
{{< /tab >}}
{{< tab header="Linux host" language="bash">}}
sudo apt update

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You can remove the "sudo apt update" on line 87 if you add it above in response to my comment on line 64.

__[!REVIEW - ADD THE PUBLIC CODE-EXAMPLE ARCHIVE URL BEFORE PUBLISHING]__

Download and extract the published code-example archive, then change to its `code` directory.

@apickard apickard Sep 2, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You can insert this code to download the files (remove the .clang-format line if you don't need it):

```bash
BASE_URL=https://raw.githubusercontent.com/ArmDeveloperEcosystem/arm-learning-paths/main/content/learning-paths/mobile-graphics-and-gaming/luti

mkdir code
cd code
for FILE in \
  .clang-format \
  Makefile \
  example_1_luti_sme2.c \
  luti_sme2_programming.c \
  luti_sme2_programming_test.c; do
  wget -q "$BASE_URL/code/$FILE" -O "$FILE"
done
```


## Download and explore the code examples

__[!REVIEW - ADD THE PUBLIC CODE-EXAMPLE ARCHIVE URL BEFORE PUBLISHING]__

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remove this line and replace with the code in my comment below.

From the same `code` directory, cross-compile for Android:

```bash
make clean

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First need: "sudo apt install build-essential"


```bash
make clean
make android

@apickard apickard Sep 2, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For me this gives:

error: Android NDK LLVM 21 or newer is required; found '' from /home/ubuntu/android-ndk-r29//toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang
make: *** [Makefile:97: check-android-llvm] Error 1

adb push sme2_luti_android /data/local/tmp/sme2_luti_android
```

Start a new shell to access the device’s system from your development machine and runs the executable:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

runs -> run


## Choose an SME2 execution environment

You can run the examples using one of the following route:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

route -> routes

```text
rhs_packed[col]
bits [7:6] | [5:4] | [3:2] | [1:0]
RHS: [k3,col] | [k2,col] | [k1,col] | [0k,col]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"[0k,col]" -> "[k0,col]"

From the `code` directory, compile `example_1_luti_sme2.c` with SME2 enabled:

```bash
/opt/homebrew/opt/llvm/bin/clang \

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is MacOS-specific. It would be good to also have alternate instructions for Linux + Android.

`LUTI2` followed by four `SMOPA` instructions.

```bash
/opt/homebrew/opt/llvm/bin/llvm-objdump -d example_1_luti_sme2 | \

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is MacOS-specific. It would be good to also have alternate instructions for Linux + Android.

- N = svcntb() = 512 / 8 = 64
- K = 4

| Block | Calculation | Size |

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Consider adding a diagram so that readers can see this visually (though it's not essential).

The examples cover the following combinations and have their base
in KleidiAI's matrix multiplication micro-kernels:

| Example | Decode | Arithmetic | Main concept |

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Perhaps replace "One" and "Two" with something more descriptive
e.g:
"One" -> "arm_lp_gemm_luti4" or "FP16 LUTI4 + FMOPA"
"Two" -> "arm_lp_gemv_luti2_luti4" or "LUTI4 -> LUTI2 -> SDOT"
i.e. refer to the examples by their function name or their description in the output.

| 3 | How many destination Z registers do you need the lookup to fill? | Choose x1, x2, or x4 to match the target operation. |
| 4 | How much of the source Z register fills the destination register group? | Source-register segment |

A *source segment* is the portion of one packed source Z register that fills the chosen destination group.</br>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It would be great to have a diagram to illustrate visually what a source segment is (though it's not essential).

}
}
```
## Two-stage LUTI4 and LUTI2 for GEMV using SDOT

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

## Example 2: Two-stage LUTI4 and LUTI2 for GEMV using SDOT

(to be consistent with line 60)


## Use Z-register tables with FEAT_LUT

`FEAT_LUT` expand the functionality of `FEAT_SME2` allowing to use scalable Z registers as the lookup-table source. This provide an alternative to using the `ZT0` register.

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`FEAT_LUT` expands the functionality of `FEAT_SME2` allowing the use of scalable Z registers as the lookup-table source. This provides an alternative to using the `ZT0` register.

("expand" -> "expands", "to use" -> "the use of", "provide" -> "provides")

one result Z register
```

Use this form for vector kernels that do not need `ZT0` register and where multiple LUT are

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LUT -> LUTs

svuint8_t packed_indices = svld1_u8(pg8, rhs_indices);
rhs_indices += vl_b;
```
<del><code> svldr_zt(0, zt0_luti4);</code></del>

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It is unclear what the strikethrough means. Are you trying to say "Replace svldr_zt(0, zt0_luti4) with:"? If so, it might be clearer to say that explicitly.

svluti4_lane_u8(luti4_table_z, packed_indices, /* segment */ 0);
..
```
<del><code> svldr_zt(0, zt0_luti2);</code></del>

@apickard apickard Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It is unclear what the strikethrough means. Are you trying to say "Replace svldr_zt(0, zt0_luti2) with:"? If so, it might be clearer to say that explicitly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants