switch (From) {
case MVT::i1:
- // If the value is naturally an i1, we don't need to mask it.
- // TODO: Recursively examine selects, phis, and, or, xor, constants.
- if (From == MVT::i1 && V != nullptr) {
- if (isa<CmpInst>(V) ||
- (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr()))
- return copyValue(Reg);
- }
+ // If the value is naturally an i1, we don't need to mask it. We only know
+ // if a value is naturally an i1 if it is definitely lowered by FastISel,
+ // not a DAG ISel fallback.
+ if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
+ return copyValue(Reg);
break;
case MVT::i8:
case MVT::i16:
--- /dev/null
+; RUN: llc < %s -O0 -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s
+
+; Regression test for bug 40172. The problem was that FastISel assumed
+; that CmpInst results did not need to be zero extended because
+; WebAssembly's compare instructions always return 0 or 1. But in this
+; test case FastISel falls back to DAG ISel, which combines away the
+; comparison, invalidating FastISel's assumption.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK: i32.sub $[[BASE:[0-9]+]]=,
+; CHECK: local.copy $[[ARG:[0-9]+]]=, $0{{$}}
+; CHECK: i32.const $[[A0:[0-9]+]]=, 1{{$}}
+; CHECK: i32.and $[[A1:[0-9]+]]=, $[[ARG]], $[[A0]]{{$}}
+; CHECK: i32.store8 8($[[BASE]]), $[[A1]]{{$}}
+
+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
+}
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s --check-prefixes CHECK,SLOW
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s --check-prefixes CHECK,FAST
; Test that basic 32-bit integer comparison operations assemble as expected.
; CHECK-NEXT: .functype eq_i32 (i32, i32) -> (i32){{$}}
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
-; CHECK-NEXT: i32.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: i32.eq $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; SLOW-NEXT: return $pop[[L2]]{{$}}
+; FAST-NEXT: i32.const $push[[L3:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; FAST-NEXT: return $pop[[L4]]{{$}}
define i32 @eq_i32(i32 %x, i32 %y) {
%a = icmp eq i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ne_i32:
-; CHECK: i32.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.ne $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ne_i32(i32 %x, i32 %y) {
%a = icmp ne i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: slt_i32:
-; CHECK: i32.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.lt_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @slt_i32(i32 %x, i32 %y) {
%a = icmp slt i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sle_i32:
-; CHECK: i32.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.le_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sle_i32(i32 %x, i32 %y) {
%a = icmp sle i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ult_i32:
-; CHECK: i32.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.lt_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ult_i32(i32 %x, i32 %y) {
%a = icmp ult i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ule_i32:
-; CHECK: i32.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.le_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ule_i32(i32 %x, i32 %y) {
%a = icmp ule i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sgt_i32:
-; CHECK: i32.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.gt_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sgt_i32(i32 %x, i32 %y) {
%a = icmp sgt i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sge_i32:
-; CHECK: i32.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.ge_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sge_i32(i32 %x, i32 %y) {
%a = icmp sge i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ugt_i32:
-; CHECK: i32.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.gt_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ugt_i32(i32 %x, i32 %y) {
%a = icmp ugt i32 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: uge_i32:
-; CHECK: i32.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i32.ge_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @uge_i32(i32 %x, i32 %y) {
%a = icmp uge i32 %x, %y
%b = zext i1 %a to i32
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s --check-prefixes CHECK,SLOW
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 | FileCheck %s --check-prefixes CHECK,FAST
; Test that basic 64-bit integer comparison operations assemble as expected.
; CHECK-NEXT: .functype eq_i64 (i64, i64) -> (i32){{$}}
; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}}
-; CHECK-NEXT: i64.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK-NEXT: i64.eq $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; SLOW-NEXT: return $pop[[L2]]{{$}}
+; FAST-NEXT: i32.const $push[[L3:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; FAST-NEXT: return $pop[[L4]]{{$}}
define i32 @eq_i64(i64 %x, i64 %y) {
%a = icmp eq i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ne_i64:
-; CHECK: i64.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.ne $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ne_i64(i64 %x, i64 %y) {
%a = icmp ne i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: slt_i64:
-; CHECK: i64.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.lt_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @slt_i64(i64 %x, i64 %y) {
%a = icmp slt i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sle_i64:
-; CHECK: i64.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.le_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sle_i64(i64 %x, i64 %y) {
%a = icmp sle i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ult_i64:
-; CHECK: i64.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.lt_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ult_i64(i64 %x, i64 %y) {
%a = icmp ult i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ule_i64:
-; CHECK: i64.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.le_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ule_i64(i64 %x, i64 %y) {
%a = icmp ule i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sgt_i64:
-; CHECK: i64.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.gt_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sgt_i64(i64 %x, i64 %y) {
%a = icmp sgt i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: sge_i64:
-; CHECK: i64.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.ge_s $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @sge_i64(i64 %x, i64 %y) {
%a = icmp sge i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: ugt_i64:
-; CHECK: i64.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.gt_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @ugt_i64(i64 %x, i64 %y) {
%a = icmp ugt i64 %x, %y
%b = zext i1 %a to i32
}
; CHECK-LABEL: uge_i64:
-; CHECK: i64.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
-; CHECK-NEXT: return $pop[[NUM]]{{$}}
+; CHECK: i64.ge_u $push[[L0:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; SLOW-NEXT: return $pop[[L0]]{{$}}
+; FAST-NEXT: i32.const $push[[L1:[0-9]+]]=, 1{{$}}
+; FAST-NEXT: i32.and $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; FAST-NEXT: return $pop[[L2]]{{$}}
define i32 @uge_i64(i64 %x, i64 %y) {
%a = icmp uge i64 %x, %y
%b = zext i1 %a to i32
; CHECK: i32.const {{.*}}, 24
; CHECK: i32.shr_s
; CHECK: i32.const {{.*}}, 64
-; CHECK: br_if 0, $pop0
+; CHECK: i32.lt_s
+; CHECK: i32.const {{.*}}, 1
+; CHECK: i32.and
+; CHECK: i32.eqz
+; CHECK: br_if 0, $pop{{[0-9]+}}
define hidden i32 @d() #0 {
entry:
%t = icmp slt i8 ptrtoint (void ()* @addr to i8), 64
; CHECK: i32.const {{.*}}, 255
; CHECK: i32.and
; CHECK: i32.const {{.*}}, 64
-; CHECK: br_if 0, $pop0
+; CHECK: i32.lt_u
+; CHECK: i32.const {{.*}}, 1
+; CHECK: i32.and
+; CHECK: i32.eqz
+; CHECK: br_if 0, $pop{{[0-9]+}}
define hidden i32 @e() #0 {
entry:
%t = icmp ult i8 ptrtoint (void ()* @addr to i8), 64