<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - [WebAssembly] Incorrect FastISel of icmp + zext due to missing masking"
href="https://bugs.llvm.org/show_bug.cgi?id=40172">40172</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>[WebAssembly] Incorrect FastISel of icmp + zext due to missing masking
</td>
</tr>
<tr>
<th>Product</th>
<td>libraries
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>All
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>Backend: WebAssembly
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>nikita.ppv@gmail.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>Originally reported at: <a href="https://github.com/rust-lang/rust/issues/57152">https://github.com/rust-lang/rust/issues/57152</a>
For LLVM IR:
define void @test(i8 %byte) {
%t = alloca { i8, i8 }, align 1
%x4 = and i8 %byte, 1
%x5 = icmp eq i8 %x4, 1
%x6 = and i8 %byte, 2
%x7 = icmp eq i8 %x6, 2
%x8 = bitcast { i8, i8 }* %t to i8*
%x9 = zext i1 %x5 to i8
store i8 %x9, i8* %x8, align 1
%x10 = getelementptr inbounds { i8, i8 }, { i8, i8 }* %t, i32 0, i32 1
%x11 = zext i1 %x7 to i8
store i8 %x11, i8* %x10, align 1
ret void
}
An llc -O0 -mtriple=wasm32 -debug trace shows:
bb.0 (%ir-block.0):
liveins: $arguments
%0:i32 = ARGUMENT_i32 0, implicit $arguments
%10:i32 = CONST_I32 2, implicit-def $arguments
%5:i32 = COPY %0:i32
%14:i32 = CONST_I32 2, implicit-def dead $arguments
%7:i32 = AND_I32 %0:i32, killed %14:i32, implicit-def dead $arguments
%8:i32 = CONST_I32 255, implicit-def $arguments
%9:i32 = AND_I32 %7:i32, %8:i32, implicit-def $arguments
%11:i32 = CONST_I32 255, implicit-def $arguments
%12:i32 = AND_I32 %10:i32, %11:i32, implicit-def $arguments
%13:i32 = EQ_I32 %9:i32, %12:i32, implicit-def $arguments
%6:i32 = COPY %5:i32
STORE8_I32 0, 0, %stack.0.t, %6:i32, implicit-def $arguments :: (store 1 into
%ir.x8)
%3:i32 = COPY %13:i32
STORE8_I32 0, 1, %stack.0.t, %3:i32, implicit-def $arguments :: (store 1 into
%ir.x10)
RETURN_VOID implicit-def $arguments
The first STORE8_I32 stores %6, which is a COPY of %5 which is a copy of %0, so
it stores the argument directly, rather than the argument masked with 1.
Looking at debug output, we can see that the first icmp generates this
SelectionDAG fragment:
t2: i32,ch = CopyFromReg t0, Register:i32 %0
t3: i8 = truncate t2
t5: i8 = and t3, Constant:i8<1>
t7: i1 = setcc t5, Constant:i8<1>, seteq:ch
t8: i32 = any_extend t7
t10: ch = CopyToReg t0, Register:i32 %5, t8
Which then (correctly) combines down to:
t2: i32,ch = CopyFromReg t0, Register:i32 %0
t10: ch = CopyToReg t0, Register:i32 %5, t2
That is, the masking has been removed *on the assumption that only the lowest
bit is significant*. Note that the any_extend above has been generated as part
of a copy to a virtual export register.
However, FastISel for WebAssembly has a reverse assumption in
<a href="https://github.com/llvm-mirror/llvm/blob/78dfeb7de614170c9deebe990c9f0f5aa838d5b6/lib/Target/WebAssembly/WebAssemblyFastISel.cpp#L448">https://github.com/llvm-mirror/llvm/blob/78dfeb7de614170c9deebe990c9f0f5aa838d5b6/lib/Target/WebAssembly/WebAssemblyFastISel.cpp#L448</a>
that the result of an icmp will always be 0 or 1.
I'm not totally sure what the right way to fix this is. The conservative fix
would be to remove the specialized code for (zext (icmp)) from wasm FastISel,
but probably there's a better way to do this.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>