[WebAssembly] Fix fast-isel optimization of branch conditions.
authorDan Gohman <dan433584@gmail.com>
Mon, 2 Jul 2018 19:45:57 +0000 (19:45 +0000)
committerDan Gohman <dan433584@gmail.com>
Mon, 2 Jul 2018 19:45:57 +0000 (19:45 +0000)
LLVM doesn't guarantee anything about the high bits of a register holding
an i1 value at the IR level, so don't translate LLVM IR i1 values directly
into WebAssembly conditional branch operands. WebAssembly's conditional
branches do demand all 32 bits be valid.

Fixes PR38019.

llvm-svn: 336138

llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll [new file with mode: 0644]

index 7b5eab4..566ef68 100644 (file)
@@ -419,7 +419,7 @@ unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
         return getRegForValue(ICmp->getOperand(0));
       }
 
-  if (BinaryOperator::isNot(V)) {
+  if (BinaryOperator::isNot(V) && V->getType()->isIntegerTy(32)) {
     Not = true;
     return getRegForValue(BinaryOperator::getNotArgument(V));
   }
diff --git a/llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll b/llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll
new file mode 100644 (file)
index 0000000..76b6e1e
--- /dev/null
@@ -0,0 +1,48 @@
+; RUN: llc < %s -fast-isel -asm-verbose=false | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; Fast-isel uses a 32-bit xor with -1 to negate i1 values, because it doesn't
+; make any guarantees about the contents of the high bits of a register holding
+; an i1 value. Test that when we do a `br_if` or `br_unless` with what what an
+; i1 value in LLVM IR, that we only test the low bit.
+
+; CHECK: i32.xor
+; CHECK: i32.const       $push[[L0:[0-9]+]]=, 1{{$}}
+; CHECK: i32.and         $push[[L1:[0-9]+]]=, $pop{{[0-9]+}}, $pop[[L0]]{{$}}
+; CHECK: br_if           0, $pop[[L1]]{{$}}
+
+; CHECK: i32.xor
+; CHECK: i32.const       $push[[L2:[0-9]+]]=, 1{{$}}
+; CHECK: i32.and         $push[[L3:[0-9]+]]=, $pop{{[0-9]+}}, $pop[[L2]]{{$}}
+; CHECK: br_if           0, $pop[[L3]]{{$}}
+
+define void @test() {
+start:
+  %0 = call i32 @return_one()
+  br label %bb1
+
+bb1:
+  %1 = icmp eq i32 %0, 1
+  %2 = xor i1 %1, true
+  br i1 %2, label %bb2, label %bb3
+
+bb2:
+  call void @panic()
+  unreachable
+
+bb3:
+  %3 = xor i1 %2, true
+  br i1 %3, label %bb4, label %bb5
+
+bb4:
+  call void @panic()
+  unreachable
+
+bb5:
+  ret void
+}
+
+declare i32 @return_one()
+declare void @panic()