From b01d87622b02cf0b9225984270e0f388b334ff35 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 2 Jul 2018 19:45:57 +0000 Subject: [PATCH] [WebAssembly] Fix fast-isel optimization of branch conditions. 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 --- .../lib/Target/WebAssembly/WebAssemblyFastISel.cpp | 2 +- llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll | 48 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index 7b5eab4..566ef68 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -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 index 0000000..76b6e1e --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/fast-isel-br-i1.ll @@ -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() -- 2.7.4