<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/89866>89866</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            weird IR generation on RISCV
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          guoyuqi020
      </td>
    </tr>
</table>

<pre>
    I'm a researcher studying the difference between clang's IR generation on x86-64 and RISCV64. Recently, I've been trying the `brotli-1.0.9` package. I found that on RISCV64, clang can generate weird complex IR for simple load-and-store logic.

For the same basic block, the IR generated on x86-64 is like this:
```
if.else853:                                       ; preds = %while.body
  tail call void @llvm.dbg.declare(metadata ptr %is_all_caps, metadata !2178, metadata !DIExpression()), !dbg !2180
  %transform854 = getelementptr inbounds %struct.DictWord, ptr %w, i32 0, i32 1, !dbg !2181
 %1133 = load i8, ptr %transform854, align 1, !dbg !2181
  %conv855 = zext i8 %1133 to i32, !dbg !2181
  %cmp856 = icmp ne i32 %conv855, 10, !dbg !2181
  %lnot858 = xor i1 %cmp856, true, !dbg !2181
  %lnot860 = xor i1 %lnot858, true, !dbg !2181
  %1134 = zext i1 %lnot860 to i64, !dbg !2181
  %cond = select i1 %lnot860, i32 1, i32 0, !dbg !2181
  store i32 %cond, ptr %is_all_caps, align 4, !dbg !2180
  tail call void @llvm.dbg.declare(metadata ptr %s862, metadata !2182, metadata !DIExpression()), !dbg !2183
  %1135 = load ptr, ptr %dictionary.addr, align 8, !dbg !2184
  %words863 = getelementptr inbounds %struct.BrotliEncoderDictionary, ptr %1135, i32 0, i32 0, !dbg !2186
 %1136 = load ptr, ptr %words863, align 8, !dbg !2186
  %1137 = load ptr, ptr %data.addr, align 8, !dbg !2187
  %1138 = load i64, ptr %max_length.addr, align 8, !dbg !2188
  %1139 = load i32, ptr %w, align 2, !dbg !2189
  store i32 %1139, ptr %w.i2875, align 2
  store ptr %1136, ptr %dictionary.addr.i2876, align 8
  tail call void @llvm.dbg.declare(metadata ptr %dictionary.addr.i2876, metadata !2190, metadata !DIExpression()), !dbg !2194
  tail call void @llvm.dbg.declare(metadata ptr %w.i2875, metadata !2196, metadata !DIExpression()), !dbg !2197
  store ptr %1137, ptr %data.addr.i2877, align 8
  tail call void @llvm.dbg.declare(metadata ptr %data.addr.i2877, metadata !2198, metadata !DIExpression()), !dbg !2199
  store i64 %1138, ptr %max_length.addr.i2878, align 8
  tail call void @llvm.dbg.declare(metadata ptr %max_length.addr.i2878, metadata !2200, metadata !DIExpression()), !dbg !2201
  %1140 = load i8, ptr %w.i2875, align 2, !dbg !2202
  %conv.i2882 = zext i8 %1140 to i64, !dbg !2204
 %1141 = load i64, ptr %max_length.addr.i2878, align 8, !dbg !2205
 %cmp.i2883 = icmp ugt i64 %conv.i2882, %1141, !dbg !2206
  br i1 %cmp.i2883, label %if.then.i2967, label %if.else.i2884, !dbg !2207
```

On RISCV64, it's like this:
```
if.else853: ; preds = %while.body
  tail call void @llvm.dbg.declare(metadata ptr %is_all_caps, metadata !2372, metadata !DIExpression()), !dbg !2374
  %transform854 = getelementptr inbounds %struct.DictWord, ptr %w, i32 0, i32 1, !dbg !2375
  %1127 = load i8, ptr %transform854, align 1, !dbg !2375
  %conv855 = zext i8 %1127 to i32, !dbg !2375
  %cmp856 = icmp ne i32 %conv855, 10, !dbg !2375
  %lnot858 = xor i1 %cmp856, true, !dbg !2375
  %lnot860 = xor i1 %lnot858, true, !dbg !2375
  %1128 = zext i1 %lnot860 to i64, !dbg !2375
  %cond = select i1 %lnot860, i32 1, i32 0, !dbg !2375
  store i32 %cond, ptr %is_all_caps, align 4, !dbg !2374
  tail call void @llvm.dbg.declare(metadata ptr %s862, metadata !2376, metadata !DIExpression()), !dbg !2377
  %1129 = load ptr, ptr %dictionary.addr, align 8, !dbg !2378
  %words863 = getelementptr inbounds %struct.BrotliEncoderDictionary, ptr %1129, i32 0, i32 0, !dbg !2380
  %1130 = load ptr, ptr %words863, align 8, !dbg !2380
  %1131 = load ptr, ptr %data.addr, align 8, !dbg !2381
  %1132 = load i64, ptr %max_length.addr, align 8, !dbg !2382
  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %w.coerce, ptr align 2 %w, i64 4, i1 false), !dbg !2383
  %1133 = load i64, ptr %w.coerce, align 8, !dbg !2383
  store i64 %1133, ptr %tmp.coerce.i2880, align 8
  call void @llvm.memcpy.p0.p0.i64(ptr align 2 %w.i2879, ptr align 8 %tmp.coerce.i2880, i64 4, i1 false)
  store ptr %1130, ptr %dictionary.addr.i2881, align 8
  tail call void @llvm.dbg.declare(metadata ptr %dictionary.addr.i2881, metadata !2384, metadata !DIExpression()), !dbg !2388
  tail call void @llvm.dbg.declare(metadata ptr %w.i2879, metadata !2390, metadata !DIExpression()), !dbg !2391
  store ptr %1131, ptr %data.addr.i2882, align 8
  tail call void @llvm.dbg.declare(metadata ptr %data.addr.i2882, metadata !2392, metadata !DIExpression()), !dbg !2393
  store i64 %1132, ptr %max_length.addr.i2883, align 8
  tail call void @llvm.dbg.declare(metadata ptr %max_length.addr.i2883, metadata !2394, metadata !DIExpression()), !dbg !2395
  %1134 = load i8, ptr %w.i2879, align 2, !dbg !2396
  %conv.i2887 = zext i8 %1134 to i64, !dbg !2398
 %1135 = load i64, ptr %max_length.addr.i2883, align 8, !dbg !2399
 %cmp.i2888 = icmp ugt i64 %conv.i2887, %1135, !dbg !2400
  br i1 %cmp.i2888, label %if.then.i2972, label %if.else.i2889, !dbg !2401
```

Most of the code is the same. The difference exists in a small load-and-store logic. On x86-64, I have:
```
  %1139 = load i32, ptr %w, align 2, !dbg !2189
  store i32 %1139, ptr %w.i2875, align 2
```

But on RISCV64, I have:
```
  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %w.coerce, ptr align 2 %w, i64 4, i1 false), !dbg !2383
  %1133 = load i64, ptr %w.coerce, align 8, !dbg !2383
  store i64 %1133, ptr %tmp.coerce.i2880, align 8
  call void @llvm.memcpy.p0.p0.i64(ptr align 2 %w.i2879, ptr align 8 %tmp.coerce.i2880, i64 4, i1 false)
```

Note that `%w` points to a struct with 2-byte aligned:
```
  %w = alloca %struct.DictWord, align 2
```
And `%struct.DictWord` is a 32-bit struct:
```
  %struct.DictWord = type { i8, i8, i16 }
```

These two slices of code do the same thing. They load an `i32` from `%w` and then store it in another value. The problem is, since this is an `i32` value, why RISCV64 bothers to use two `i64` variables and two `memcpy` calls to do such simple value transmission? Do you have any ideas?

======================================================

I have uploaded the source code of the package `brotli-1.0.9`.
[brotli-1.0.9.zip](https://github.com/llvm/llvm-project/files/15087235/brotli-1.0.9.zip)


The instructions I used to generate IR:
```
cd brotli-1.0.9
cd c
clang -g -fno-discard-value-names -S -emit-llvm ./enc/static_dict.c -I./include -o ~/x86.ll
```

I uploaded the IR generated on my machines. Hope they may help.
[IR.zip](https://github.com/llvm/llvm-project/files/15087271/IR.zip)


I'm using commit `132bf4aedd678277b57d8e2bdabf9a1e9eb254c5` of LLVM.


If you need any other information, please let me know. 

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWluPozj2_zTUy1EQmJt5yENXZ6J_pJn_SD2j2ceWgUPibbBZ7FQq87CffWWTCwRI16135mFLUSqB-Odz9-_YMKX4ViAunejRiVYPbK93sl1u9_K4_xf3iPeQyeK43DgkqYFBiwpZm--wBaX3xZGLLegdQsHLElsUOUKG-oAoIK-Y2DokUbD5AlsU2DLNpQAp4JnGizgEJgr4svnt8x9x6MIXzFHo6uiQz2BmezJIKEC3l0mc2MtaqSu-8F3PTZ3Yg4bl39gWXdhAKfeiAL1j2kxxwjVoVhDImThLgXBA3haQy7qp8NnIV8oWFDdfoZKsWDBRLJSWrfm65bnreCvH-9S9r2VrxVGsRsiY4jlklcy_mbnM9au6WPS05Qoq_g1B77hyghOWE3unl_3KSxcrhTQKnOATvOzPCR6habFQ4AQrcEh02PEKXeO2DhRAM15BzqoKniQvwAm9qnqq3SLbugXmFWvRIbRGzQqmGTS6NTBcfWVV9TVnjTKaXW47xCd-Qm-vrTY_PTctKsWlcAh1SGpfn829Itt2w6h3FskhkW6ZUKVsaxqFVvYtaqywRqGNCFxkxqPK_FTpdp9rd8Vz_Q_ZFgb2JOXBfOYBAe_8wR9N6p8mdUjk-0Fg5zJeBk57SH1xzGVW8a24g2bG5FI80SiyiH_iswZOL7NoacS5P7xuaBTb0TyvGxBoNbgCm9G-dxejElLTiFqQZ9kC96_INiLbPX4fIPZuAE6wL0Lw_SDsmcDvoxordGl4z4iFHa6wwvwGYODVi5-nsbqEvVqwHyc30dw5dyyX966UUTQm41yho2svy5VgaOLoGreNbnuqFTw3hZW1R5cVRXtVj44gwx7kQbaFonHwstR7tIX3J5HLAtvVZcaeGEbEUTKOvRUPkjGeU-os3T1t4qGBklkDMc2-a5pkCEZ7VaKL3xNYzZ6_Vii2evddSDqETHuQXWHo17AOZFwv0snoNnB9BJcTmkR9nMGoq4vi-cCxGHFfoffkwiz4MDlS703JkYbvEq5nrxtxRiK-TJxkzt7JVBza2ZMPs_QY9kapty3W6W3oxeE5OebzwcpAP0q1WfCBgsR7UxARb7iIhd4MM5jIrlskckMKzAhKxrwgnFkRiRf262Lov7D8jM19ixtdcfO6sXIFV8ax3-qzX69idxhWjBHcpeZmParRoZrfVizDyq63pat3KFxO0ji5vWM4rh0zNkMyyYu7918HtJ5r21y8klP_FWw5SN7EAIIk_O-z5SCJBklBknfR5SHcLF0myTRdvhn-Jro8xHgDXZ4AeCVdHhmVvoouj4z4Drrcw3o3Xe4F6MfR5WDMEl6WLEMCR9J30-UgoT-ULnc63KXLwaBh9v3AeztfHmH57-DLwW0DSN7NlwN6WUTHgVRjnTdHt_HMy05ADf4JqVukc4ltjuepTyv1terFYRfA3IeSVQonYui25QrmlOpPNqdNMMeegn4VrZsTlF0PvQni9EpjkCtjSYe2oHMTTppmhs969_sH6v_A_qEDH1aLjkK8ulrQ9wnXs-9QnLe1M0Hqz9nbn-sfOpr24f3DeLOCBOnb6Es6mwHkPqGlwQ_sHzrwGwXfFkRpNLUJNtc_pPP9Q5DGU_1DMrGvGM5QhJQO9lWiV_QP9N6icWkCe0yf3u8fkkv_0G0I9eBCz5vtH-hc_9Cx58n-4dYl4bmlm-wffpFKgyztJr1ZmIGry0a-C78PjzHwmSutgAtgoGoTd5MHA_DreYPfiLKBHXvCuU7kL9wImrTH4_72qOR78v9vYf6bLMyT_vx_qbE7ADM3jHljDxrJhVamajDoyCkcuN4BWWRHjZ0EWNwN2YO1NqsqmbOZ_vJesH0y_YoV6HZg7JkUZBCQRcb1Sby7otwgWMH0sUFwksdT0T29-zE4yeqOtX7foULQBwmq4jkqUxlsVSjk9XhP77jY2tpw7MKNCaOLSdvYg7KVdd_WzB5AojhHlrblQ0i9wxaeWLU_lZmmlVmFNXDbXClu6o3ecWWt0Z_AjjG_OeyO5zyFzOJZl-5PGpgRcdiNaDnLKlSdMN29Li7NbROzdmQhQe3z3fnQ004EtqevebfqBWtYSTjKva0JwMQReIFMOcG6b0YnWP3dXz1puwIH-8Y4E4vO0XLf5qcV4bQ6nI6VJ06czyfB0WP_hvsnb5xo5RC607qxW1Fk7ZD1luvdPnNzWTtkbUrE6d-iaeU_MdcOWZe8QuWQtR95NCFmxVyPkC9ZPwxf4KLLBy6Fgo2JhsL49nLMvfkyl0x5AQPFzhfz0yd7ZL7YwqIUclFwlbO2WNggWQhWo4LFb7DAmuuFUQdch6xR5A5ZK800z78a9u7msNiYO1zk1b5AWEj4t0PWzzR2q-pOZm6G_rk9T6-PULN8xwUqF_5PNiZ30Fw7wg6r5uqhzZcP80viO2R9wpvyRvd8xF5xsYVc1jW3NdgPSFaGDIsiTihJkixKCookK1hWpszHFDMShXlkMlOW8PPPf_ziTmCXNgsFYmGzsCsnXJSyre0jFXY1qZAphAo11AjfhDy40A1_KJZBkQYpe8Cln_hBSmgYRw-7JfHSwCtIwjCKPc-LCTLiFWWaZBHLk6B84EvikdALSegFfkgiN04zVmBZ0iyMwqT0nNDDmvHKtaufbLcPXKk9LmlK4_jBMjZlHywhROAB7E2HECdaPbRLa-9sv1Vm9TRc64qiua5w2T2kMXp4xJbBh31bLV_tUyuAcaoV8D8BAAD__1qZ4vQ">