[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