[llvm] 92e7771 - [WebAssembly] Invert branch condition on xor input
Sam Parker via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 1 01:24:09 PDT 2021
Author: Sam Parker
Date: 2021-04-01T09:23:28+01:00
New Revision: 92e7771483597935bce523a6f2a1b6109efe7af0
URL: https://github.com/llvm/llvm-project/commit/92e7771483597935bce523a6f2a1b6109efe7af0
DIFF: https://github.com/llvm/llvm-project/commit/92e7771483597935bce523a6f2a1b6109efe7af0.diff
LOG: [WebAssembly] Invert branch condition on xor input
A frequent pattern for floating point conditional branches use an xor
to invert the input for the branch. Instead we can fold away the xor
by swapping the branch target instead.
Differential Revision: https://reviews.llvm.org/D99171
Added:
Modified:
llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
llvm/test/CodeGen/WebAssembly/comparisons-f32.ll
llvm/test/CodeGen/WebAssembly/comparisons-f64.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
index e96ae4fe752f3..dab516130a14d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
@@ -30,6 +30,8 @@ def : Pat<(brcond (i32 (setne I32:$cond, 0)), bb:$dst),
(BR_IF bb_op:$dst, I32:$cond)>;
def : Pat<(brcond (i32 (seteq I32:$cond, 0)), bb:$dst),
(BR_UNLESS bb_op:$dst, I32:$cond)>;
+def : Pat<(brcond (i32 (xor bool_node:$cond, (i32 1))), bb:$dst),
+ (BR_UNLESS bb_op:$dst, I32:$cond)>;
// A list of branch targets enclosed in {} and separated by comma.
// Used by br_table only.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index f6b9efa85cb9c..cf897a914b830 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -194,6 +194,11 @@ def TypeIndex : Operand<i32>;
} // OperandNamespace = "WebAssembly"
+// TODO: Find more places to use this.
+def bool_node : PatLeaf<(i32 I32:$cond), [{
+ return CurDAG->computeKnownBits(SDValue(N, 0)).countMinLeadingZeros() == 31;
+}]>;
+
//===----------------------------------------------------------------------===//
// WebAssembly Register to Stack instruction mapping
//===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/WebAssembly/comparisons-f32.ll b/llvm/test/CodeGen/WebAssembly/comparisons-f32.ll
index 60b6381b16b69..f1378bccb3faa 100644
--- a/llvm/test/CodeGen/WebAssembly/comparisons-f32.ll
+++ b/llvm/test/CodeGen/WebAssembly/comparisons-f32.ll
@@ -187,3 +187,198 @@ define i32 @uge_f32(float %x, float %y) {
%b = zext i1 %a to i32
ret i32 %b
}
+
+; CHECK-LABEL: olt_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.lt $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @olt_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp olt float %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ole_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ole_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp ole float %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ugt_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ugt_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp ugt float %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ogt_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.gt $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ogt_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp ogt float %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ult_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ult_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp ult float %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ule_f32_branch
+; CHECK: local.get $push[[L4:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 1
+; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $pop[[L4]], $pop[[L3]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ule_f32_branch(float %a, float %b) {
+entry:
+ %cmp = fcmp ult float %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: xor_zext_switch
+; CHECK: i32.const $push[[L1:[0-9]+]]=, 0
+; CHECK-NEXT: br_if 0, $pop[[L1]]
+; CHECK-NEXT: block
+; CHECK-NEXT: block
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L2:[0-9]+]]=, 1
+; CHECK-NEXT: f32.ge $push[[L0:[0-9]+]]=, $pop[[L3]], $pop[[L2]]
+; CHECK-NEXT: br_table $pop[[L0]], 0, 1, 0
+define void @xor_zext_switch(float %a, float %b) {
+entry:
+ %cmp = fcmp ult float %a, %b
+ %zext = zext i1 %cmp to i32
+ %xor = xor i32 %zext, 1
+ switch i32 %xor, label %exit [
+ i32 0, label %sw.bb.1
+ i32 1, label %sw.bb.2
+ ]
+
+sw.bb.1:
+ tail call void @foo1()
+ br label %exit
+
+sw.bb.2:
+ tail call void @foo2()
+ br label %exit
+
+exit:
+ ret void
+}
+
+; CHECK-LABEL: xor_add_switch
+; CHECK: local.get $push[[L8:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L7:[0-9]+]]=, 1
+; CHECK-NEXT: f32.ge $push[[L1:[0-9]+]]=, $pop[[L8]], $pop[[L7]]
+; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 1
+; CHECK-NEXT: i32.xor $push[[L3:[0-9]+]]=, $pop[[L1]], $pop[[L2]]
+; CHECK-NEXT: i32.const $push[[L6:[0-9]+]]=, 1
+; CHECK-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L3]], $pop[[L6]]
+; CHECK-NEXT: i32.const $push[[L5:[0-9]+]]=, 1
+; CHECK-NEXT: i32.xor $push[[L0:[0-9]+]]=, $pop[[L4]], $pop[[L5]]
+; CHECK-NEXT: br_table $pop[[L0]], 0, 1, 2, 3
+define void @xor_add_switch(float %a, float %b) {
+entry:
+ %cmp = fcmp ult float %a, %b
+ %zext = zext i1 %cmp to i32
+ %add = add nsw nuw i32 %zext, 1
+ %xor = xor i32 %add, 1
+ switch i32 %xor, label %exit [
+ i32 0, label %sw.bb.1
+ i32 1, label %sw.bb.2
+ i32 2, label %sw.bb.3
+ ]
+
+sw.bb.1:
+ tail call void @foo1()
+ br label %exit
+
+sw.bb.2:
+ tail call void @foo2()
+ br label %exit
+
+sw.bb.3:
+ tail call void @foo3()
+ br label %exit
+
+exit:
+ ret void
+}
+
+declare void @foo1()
+declare void @foo2()
+declare void @foo3()
+declare void @_Z5call1v()
diff --git a/llvm/test/CodeGen/WebAssembly/comparisons-f64.ll b/llvm/test/CodeGen/WebAssembly/comparisons-f64.ll
index 063a293b7fa8e..6dbe555330e02 100644
--- a/llvm/test/CodeGen/WebAssembly/comparisons-f64.ll
+++ b/llvm/test/CodeGen/WebAssembly/comparisons-f64.ll
@@ -186,3 +186,198 @@ define i32 @uge_f64(double %x, double %y) {
%b = zext i1 %a to i32
ret i32 %b
}
+
+; CHECK-LABEL: olt_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.lt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @olt_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp olt double %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ole_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ole_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp ole double %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ugt_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ugt_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp ugt double %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ogt_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ogt_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp ogt double %a, %b
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ult_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.ge $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ult_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp ult double %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: ule_f64_branch:
+; CHECK: local.get $push[[L0:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1
+; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]
+; CHECK-NEXT: i32.eqz $push[[NUM3:[0-9]+]]=, $pop[[NUM0]]
+; CHECK-NEXT: br_if 0, $pop[[NUM3]]
+; CHECK-NEXT: call _Z5call1v
+define void @ule_f64_branch(double %a, double %b) {
+entry:
+ %cmp = fcmp ule double %a, %b
+ br i1 %cmp, label %if.end, label %if.then
+
+if.then:
+ tail call void @_Z5call1v()
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+; CHECK-LABEL: xor_zext_switch
+; CHECK: i32.const $push[[L1:[0-9]+]]=, 0
+; CHECK-NEXT: br_if 0, $pop[[L1]]
+; CHECK-NEXT: block
+; CHECK-NEXT: block
+; CHECK-NEXT: local.get $push[[L3:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L2:[0-9]+]]=, 1
+; CHECK-NEXT: f64.ge $push[[L0:[0-9]+]]=, $pop[[L3]], $pop[[L2]]
+; CHECK-NEXT: br_table $pop[[L0]], 0, 1, 0
+define void @xor_zext_switch(double %a, double %b) {
+entry:
+ %cmp = fcmp ult double %a, %b
+ %zext = zext i1 %cmp to i32
+ %xor = xor i32 %zext, 1
+ switch i32 %xor, label %exit [
+ i32 0, label %sw.bb.1
+ i32 1, label %sw.bb.2
+ ]
+
+sw.bb.1:
+ tail call void @foo1()
+ br label %exit
+
+sw.bb.2:
+ tail call void @foo2()
+ br label %exit
+
+exit:
+ ret void
+}
+
+; CHECK-LABEL: xor_add_switch
+; CHECK: local.get $push[[L8:[0-9]+]]=, 0
+; CHECK-NEXT: local.get $push[[L7:[0-9]+]]=, 1
+; CHECK-NEXT: f64.ge $push[[L1:[0-9]+]]=, $pop[[L8]], $pop[[L7]]
+; CHECK-NEXT: i32.const $push[[L2:[0-9]+]]=, 1
+; CHECK-NEXT: i32.xor $push[[L3:[0-9]+]]=, $pop[[L1]], $pop[[L2]]
+; CHECK-NEXT: i32.const $push[[L6:[0-9]+]]=, 1
+; CHECK-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L3]], $pop[[L6]]
+; CHECK-NEXT: i32.const $push[[L5:[0-9]+]]=, 1
+; CHECK-NEXT: i32.xor $push[[L0:[0-9]+]]=, $pop[[L4]], $pop[[L5]]
+; CHECK-NEXT: br_table $pop[[L0]], 0, 1, 2, 3
+define void @xor_add_switch(double %a, double %b) {
+entry:
+ %cmp = fcmp ult double %a, %b
+ %zext = zext i1 %cmp to i32
+ %add = add nsw nuw i32 %zext, 1
+ %xor = xor i32 %add, 1
+ switch i32 %xor, label %exit [
+ i32 0, label %sw.bb.1
+ i32 1, label %sw.bb.2
+ i32 2, label %sw.bb.3
+ ]
+
+sw.bb.1:
+ tail call void @foo1()
+ br label %exit
+
+sw.bb.2:
+ tail call void @foo2()
+ br label %exit
+
+sw.bb.3:
+ tail call void @foo3()
+ br label %exit
+
+exit:
+ ret void
+}
+
+declare void @foo1()
+declare void @foo2()
+declare void @foo3()
+declare void @_Z5call1v()
More information about the llvm-commits
mailing list