Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -30,6 +30,8 @@ (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. Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -194,6 +194,11 @@ } // 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 //===----------------------------------------------------------------------===// Index: llvm/test/CodeGen/WebAssembly/comparisons-f32.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/comparisons-f32.ll +++ llvm/test/CodeGen/WebAssembly/comparisons-f32.ll @@ -187,3 +187,198 @@ %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() Index: llvm/test/CodeGen/WebAssembly/comparisons-f64.ll =================================================================== --- llvm/test/CodeGen/WebAssembly/comparisons-f64.ll +++ llvm/test/CodeGen/WebAssembly/comparisons-f64.ll @@ -186,3 +186,198 @@ %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()