diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 098e5f22834f4..4b61f588f18c8 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -27,6 +27,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" @@ -1752,8 +1753,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTPOP, MVT::i64, Subtarget->usePopc() ? Legal : Expand); - setOperationAction(ISD::CTTZ , MVT::i64, Expand); - setOperationAction(ISD::CTLZ , MVT::i64, Expand); + setOperationAction(ISD::CTTZ, MVT::i64, Expand); setOperationAction(ISD::BSWAP, MVT::i64, Expand); setOperationAction(ISD::ROTL , MVT::i64, Expand); setOperationAction(ISD::ROTR , MVT::i64, Expand); @@ -1814,8 +1814,7 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM, setOperationAction(ISD::FSINCOS, MVT::f32, Expand); setOperationAction(ISD::FREM , MVT::f32, Expand); setOperationAction(ISD::FMA , MVT::f32, Expand); - setOperationAction(ISD::CTTZ , MVT::i32, Expand); - setOperationAction(ISD::CTLZ , MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); setOperationAction(ISD::ROTL , MVT::i32, Expand); setOperationAction(ISD::ROTR , MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i32, Expand); @@ -1986,6 +1985,24 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM, if (Subtarget->hasLeonCycleCounter()) setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom); + if (Subtarget->isVIS3()) { + setOperationAction(ISD::CTLZ, MVT::i32, Legal); + setOperationAction(ISD::CTLZ, MVT::i64, Legal); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Legal); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Legal); + } else if (Subtarget->usePopc()) { + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + } else { + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, + Subtarget->is64Bit() ? Promote : LibCall); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, LibCall); + } + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); setMinFunctionAlignment(Align(4)); @@ -3571,6 +3588,8 @@ bool SparcTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, Imm.isZero(); } +bool SparcTargetLowering::isCtlzFast() const { return Subtarget->isVIS3(); } + // Override to disable global variable loading on Linux. void SparcTargetLowering::insertSSPDeclarations(Module &M) const { if (!Subtarget->isTargetLinux()) diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h index c09e465f5d05e..ef87e20094c98 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -210,6 +210,12 @@ namespace llvm { bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; + bool isCtlzFast() const override; + + bool isCheapToSpeculateCtlz(Type *Ty) const override { + return isCtlzFast(); + } + bool shouldInsertFencesForAtomic(const Instruction *I) const override { // FIXME: We insert fences for each atomics and generate // sub-optimal code for PSO/TSO. (Approximately nobody uses any diff --git a/llvm/lib/Target/Sparc/SparcInstrVIS.td b/llvm/lib/Target/Sparc/SparcInstrVIS.td index ee24d8a54fe8e..78f50888b5508 100644 --- a/llvm/lib/Target/Sparc/SparcInstrVIS.td +++ b/llvm/lib/Target/Sparc/SparcInstrVIS.td @@ -294,4 +294,14 @@ def : Pat<(f32 fpnegimm0), (FNEGS (FZEROS))>; // VIS3 instruction patterns. let Predicates = [HasVIS3] in { def : Pat<(i64 (adde i64:$lhs, i64:$rhs)), (ADDXCCC $lhs, $rhs)>; + +def : Pat<(i64 (ctlz i64:$src)), (LZCNT $src)>; +def : Pat<(i64 (ctlz_zero_undef i64:$src)), (LZCNT $src)>; +// 32-bit LZCNT. +// The zero extension will leave us with 32 extra leading zeros, +// so we need to compensate for it. +// FIXME remove this when the codegen supports using 64-bit values directly +// in V8+ mode. +def : Pat<(i32 (ctlz i32:$src)), (ADDri (LZCNT (SRLri $src, 0)), (i32 -32))>; +def : Pat<(i32 (ctlz_zero_undef i32:$src)), (ADDri (LZCNT (SRLri $src, 0)), (i32 -32))>; } // Predicates = [HasVIS3] diff --git a/llvm/test/CodeGen/SPARC/ctlz.ll b/llvm/test/CodeGen/SPARC/ctlz.ll new file mode 100644 index 0000000000000..72505f221469e --- /dev/null +++ b/llvm/test/CodeGen/SPARC/ctlz.ll @@ -0,0 +1,405 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=sparc | FileCheck %s -check-prefix=SPARC +; RUN: llc < %s -mtriple=sparc -mattr=popc | FileCheck %s -check-prefix=SPARC-POPC +; RUN: llc < %s -mtriple=sparc -mattr=vis3 | FileCheck %s -check-prefix=SPARC-VIS3 +; RUN: llc < %s -mtriple=sparcv9 | FileCheck %s -check-prefix=SPARC64 +; RUN: llc < %s -mtriple=sparcv9 -mattr=popc | FileCheck %s -check-prefix=SPARC64-POPC +; RUN: llc < %s -mtriple=sparcv9 -mattr=vis3 | FileCheck %s -check-prefix=SPARC64-VIS3 + +define i32 @i32_nopoison(i32 %x) nounwind { +; SPARC-LABEL: i32_nopoison: +; SPARC: ! %bb.0: +; SPARC-NEXT: save %sp, -96, %sp +; SPARC-NEXT: cmp %i0, 0 +; SPARC-NEXT: be .LBB0_2 +; SPARC-NEXT: nop +; SPARC-NEXT: ! %bb.1: ! %cond.false +; SPARC-NEXT: call __clzsi2 +; SPARC-NEXT: mov %i0, %o0 +; SPARC-NEXT: ret +; SPARC-NEXT: restore %g0, %o0, %o0 +; SPARC-NEXT: .LBB0_2: +; SPARC-NEXT: ret +; SPARC-NEXT: restore %g0, 32, %o0 +; +; SPARC-POPC-LABEL: i32_nopoison: +; SPARC-POPC: ! %bb.0: +; SPARC-POPC-NEXT: save %sp, -96, %sp +; SPARC-POPC-NEXT: cmp %i0, 0 +; SPARC-POPC-NEXT: be .LBB0_2 +; SPARC-POPC-NEXT: nop +; SPARC-POPC-NEXT: ! %bb.1: ! %cond.false +; SPARC-POPC-NEXT: call __clzsi2 +; SPARC-POPC-NEXT: mov %i0, %o0 +; SPARC-POPC-NEXT: ret +; SPARC-POPC-NEXT: restore %g0, %o0, %o0 +; SPARC-POPC-NEXT: .LBB0_2: +; SPARC-POPC-NEXT: ret +; SPARC-POPC-NEXT: restore %g0, 32, %o0 +; +; SPARC-VIS3-LABEL: i32_nopoison: +; SPARC-VIS3: ! %bb.0: +; SPARC-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: add %o0, -32, %o0 +; +; SPARC64-LABEL: i32_nopoison: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -176, %sp +; SPARC64-NEXT: cmp %i0, 0 +; SPARC64-NEXT: be %icc, .LBB0_2 +; SPARC64-NEXT: nop +; SPARC64-NEXT: ! %bb.1: ! %cond.false +; SPARC64-NEXT: call __clzdi2 +; SPARC64-NEXT: sllx %i0, 32, %o0 +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, %o0, %o0 +; SPARC64-NEXT: .LBB0_2: +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, 32, %o0 +; +; SPARC64-POPC-LABEL: i32_nopoison: +; SPARC64-POPC: ! %bb.0: +; SPARC64-POPC-NEXT: cmp %o0, 0 +; SPARC64-POPC-NEXT: be %icc, .LBB0_2 +; SPARC64-POPC-NEXT: nop +; SPARC64-POPC-NEXT: ! %bb.1: ! %cond.false +; SPARC64-POPC-NEXT: srl %o0, 1, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 2, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 4, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 8, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 16, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: xor %o0, -1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 0, %o0 +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: popc %o0, %o0 +; SPARC64-POPC-NEXT: .LBB0_2: +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: mov 32, %o0 +; +; SPARC64-VIS3-LABEL: i32_nopoison: +; SPARC64-VIS3: ! %bb.0: +; SPARC64-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC64-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC64-VIS3-NEXT: retl +; SPARC64-VIS3-NEXT: add %o0, -32, %o0 + %ret = call i32 @llvm.ctlz.i32(i32 %x, i1 false) + ret i32 %ret +} + +define i32 @i32_poison(i32 %x) nounwind { +; SPARC-LABEL: i32_poison: +; SPARC: ! %bb.0: +; SPARC-NEXT: save %sp, -96, %sp +; SPARC-NEXT: call __clzsi2 +; SPARC-NEXT: mov %i0, %o0 +; SPARC-NEXT: ret +; SPARC-NEXT: restore %g0, %o0, %o0 +; +; SPARC-POPC-LABEL: i32_poison: +; SPARC-POPC: ! %bb.0: +; SPARC-POPC-NEXT: save %sp, -96, %sp +; SPARC-POPC-NEXT: call __clzsi2 +; SPARC-POPC-NEXT: mov %i0, %o0 +; SPARC-POPC-NEXT: ret +; SPARC-POPC-NEXT: restore %g0, %o0, %o0 +; +; SPARC-VIS3-LABEL: i32_poison: +; SPARC-VIS3: ! %bb.0: +; SPARC-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: add %o0, -32, %o0 +; +; SPARC64-LABEL: i32_poison: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -176, %sp +; SPARC64-NEXT: call __clzdi2 +; SPARC64-NEXT: sllx %i0, 32, %o0 +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, %o0, %o0 +; +; SPARC64-POPC-LABEL: i32_poison: +; SPARC64-POPC: ! %bb.0: +; SPARC64-POPC-NEXT: srl %o0, 1, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 2, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 4, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 8, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 16, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: xor %o0, -1, %o0 +; SPARC64-POPC-NEXT: srl %o0, 0, %o0 +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: popc %o0, %o0 +; +; SPARC64-VIS3-LABEL: i32_poison: +; SPARC64-VIS3: ! %bb.0: +; SPARC64-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC64-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC64-VIS3-NEXT: retl +; SPARC64-VIS3-NEXT: add %o0, -32, %o0 + %ret = call i32 @llvm.ctlz.i32(i32 %x, i1 true) + ret i32 %ret +} + +define i64 @i64_nopoison(i64 %x) nounwind { +; SPARC-LABEL: i64_nopoison: +; SPARC: ! %bb.0: +; SPARC-NEXT: save %sp, -96, %sp +; SPARC-NEXT: call __clzsi2 +; SPARC-NEXT: mov %i0, %o0 +; SPARC-NEXT: cmp %i0, 0 +; SPARC-NEXT: bne .LBB2_2 +; SPARC-NEXT: nop +; SPARC-NEXT: ! %bb.1: +; SPARC-NEXT: srl %i1, 1, %i0 +; SPARC-NEXT: or %i1, %i0, %i0 +; SPARC-NEXT: srl %i0, 2, %i1 +; SPARC-NEXT: or %i0, %i1, %i0 +; SPARC-NEXT: srl %i0, 4, %i1 +; SPARC-NEXT: or %i0, %i1, %i0 +; SPARC-NEXT: srl %i0, 8, %i1 +; SPARC-NEXT: or %i0, %i1, %i0 +; SPARC-NEXT: srl %i0, 16, %i1 +; SPARC-NEXT: or %i0, %i1, %i0 +; SPARC-NEXT: xor %i0, -1, %i0 +; SPARC-NEXT: srl %i0, 1, %i1 +; SPARC-NEXT: sethi 1398101, %i2 +; SPARC-NEXT: or %i2, 341, %i2 +; SPARC-NEXT: and %i1, %i2, %i1 +; SPARC-NEXT: sub %i0, %i1, %i0 +; SPARC-NEXT: sethi 838860, %i1 +; SPARC-NEXT: or %i1, 819, %i1 +; SPARC-NEXT: and %i0, %i1, %i2 +; SPARC-NEXT: srl %i0, 2, %i0 +; SPARC-NEXT: and %i0, %i1, %i0 +; SPARC-NEXT: add %i2, %i0, %i0 +; SPARC-NEXT: srl %i0, 4, %i1 +; SPARC-NEXT: add %i0, %i1, %i0 +; SPARC-NEXT: sethi 246723, %i1 +; SPARC-NEXT: or %i1, 783, %i1 +; SPARC-NEXT: and %i0, %i1, %i0 +; SPARC-NEXT: sll %i0, 8, %i1 +; SPARC-NEXT: add %i0, %i1, %i0 +; SPARC-NEXT: sll %i0, 16, %i1 +; SPARC-NEXT: add %i0, %i1, %i0 +; SPARC-NEXT: srl %i0, 24, %i0 +; SPARC-NEXT: add %i0, 32, %o0 +; SPARC-NEXT: .LBB2_2: +; SPARC-NEXT: mov %g0, %i0 +; SPARC-NEXT: ret +; SPARC-NEXT: restore %g0, %o0, %o1 +; +; SPARC-POPC-LABEL: i64_nopoison: +; SPARC-POPC: ! %bb.0: +; SPARC-POPC-NEXT: save %sp, -96, %sp +; SPARC-POPC-NEXT: call __clzsi2 +; SPARC-POPC-NEXT: mov %i0, %o0 +; SPARC-POPC-NEXT: cmp %i0, 0 +; SPARC-POPC-NEXT: bne .LBB2_2 +; SPARC-POPC-NEXT: nop +; SPARC-POPC-NEXT: ! %bb.1: +; SPARC-POPC-NEXT: srl %i1, 1, %i0 +; SPARC-POPC-NEXT: or %i1, %i0, %i0 +; SPARC-POPC-NEXT: srl %i0, 2, %i1 +; SPARC-POPC-NEXT: or %i0, %i1, %i0 +; SPARC-POPC-NEXT: srl %i0, 4, %i1 +; SPARC-POPC-NEXT: or %i0, %i1, %i0 +; SPARC-POPC-NEXT: srl %i0, 8, %i1 +; SPARC-POPC-NEXT: or %i0, %i1, %i0 +; SPARC-POPC-NEXT: srl %i0, 16, %i1 +; SPARC-POPC-NEXT: or %i0, %i1, %i0 +; SPARC-POPC-NEXT: xor %i0, -1, %i0 +; SPARC-POPC-NEXT: srl %i0, 1, %i1 +; SPARC-POPC-NEXT: sethi 1398101, %i2 +; SPARC-POPC-NEXT: or %i2, 341, %i2 +; SPARC-POPC-NEXT: and %i1, %i2, %i1 +; SPARC-POPC-NEXT: sub %i0, %i1, %i0 +; SPARC-POPC-NEXT: sethi 838860, %i1 +; SPARC-POPC-NEXT: or %i1, 819, %i1 +; SPARC-POPC-NEXT: and %i0, %i1, %i2 +; SPARC-POPC-NEXT: srl %i0, 2, %i0 +; SPARC-POPC-NEXT: and %i0, %i1, %i0 +; SPARC-POPC-NEXT: add %i2, %i0, %i0 +; SPARC-POPC-NEXT: srl %i0, 4, %i1 +; SPARC-POPC-NEXT: add %i0, %i1, %i0 +; SPARC-POPC-NEXT: sethi 246723, %i1 +; SPARC-POPC-NEXT: or %i1, 783, %i1 +; SPARC-POPC-NEXT: and %i0, %i1, %i0 +; SPARC-POPC-NEXT: sll %i0, 8, %i1 +; SPARC-POPC-NEXT: add %i0, %i1, %i0 +; SPARC-POPC-NEXT: sll %i0, 16, %i1 +; SPARC-POPC-NEXT: add %i0, %i1, %i0 +; SPARC-POPC-NEXT: srl %i0, 24, %i0 +; SPARC-POPC-NEXT: add %i0, 32, %o0 +; SPARC-POPC-NEXT: .LBB2_2: +; SPARC-POPC-NEXT: mov %g0, %i0 +; SPARC-POPC-NEXT: ret +; SPARC-POPC-NEXT: restore %g0, %o0, %o1 +; +; SPARC-VIS3-LABEL: i64_nopoison: +; SPARC-VIS3: ! %bb.0: +; SPARC-VIS3-NEXT: cmp %o0, 0 +; SPARC-VIS3-NEXT: bne .LBB2_2 +; SPARC-VIS3-NEXT: nop +; SPARC-VIS3-NEXT: ! %bb.1: +; SPARC-VIS3-NEXT: srl %o1, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: add %o0, -32, %o0 +; SPARC-VIS3-NEXT: add %o0, 32, %o1 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: mov %g0, %o0 +; SPARC-VIS3-NEXT: .LBB2_2: +; SPARC-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: add %o0, -32, %o1 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: mov %g0, %o0 +; +; SPARC64-LABEL: i64_nopoison: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -176, %sp +; SPARC64-NEXT: brz %i0, .LBB2_2 +; SPARC64-NEXT: nop +; SPARC64-NEXT: ! %bb.1: ! %cond.false +; SPARC64-NEXT: call __clzdi2 +; SPARC64-NEXT: mov %i0, %o0 +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, %o0, %o0 +; SPARC64-NEXT: .LBB2_2: +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, 64, %o0 +; +; SPARC64-POPC-LABEL: i64_nopoison: +; SPARC64-POPC: ! %bb.0: +; SPARC64-POPC-NEXT: brz %o0, .LBB2_2 +; SPARC64-POPC-NEXT: nop +; SPARC64-POPC-NEXT: ! %bb.1: ! %cond.false +; SPARC64-POPC-NEXT: srlx %o0, 1, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 2, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 4, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 8, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 16, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 32, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: xor %o0, -1, %o0 +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: popc %o0, %o0 +; SPARC64-POPC-NEXT: .LBB2_2: +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: mov 64, %o0 +; +; SPARC64-VIS3-LABEL: i64_nopoison: +; SPARC64-VIS3: ! %bb.0: +; SPARC64-VIS3-NEXT: retl +; SPARC64-VIS3-NEXT: lzcnt %o0, %o0 + %ret = call i64 @llvm.ctlz.i64(i64 %x, i1 false) + ret i64 %ret +} + +define i64 @i64_poison(i64 %x) nounwind { +; SPARC-LABEL: i64_poison: +; SPARC: ! %bb.0: +; SPARC-NEXT: save %sp, -96, %sp +; SPARC-NEXT: mov %i1, %o0 +; SPARC-NEXT: call __clzsi2 +; SPARC-NEXT: mov %i0, %i1 +; SPARC-NEXT: mov %o0, %i0 +; SPARC-NEXT: call __clzsi2 +; SPARC-NEXT: mov %i1, %o0 +; SPARC-NEXT: cmp %i1, 0 +; SPARC-NEXT: bne .LBB3_2 +; SPARC-NEXT: nop +; SPARC-NEXT: ! %bb.1: +; SPARC-NEXT: add %i0, 32, %o0 +; SPARC-NEXT: .LBB3_2: +; SPARC-NEXT: mov %g0, %i0 +; SPARC-NEXT: ret +; SPARC-NEXT: restore %g0, %o0, %o1 +; +; SPARC-POPC-LABEL: i64_poison: +; SPARC-POPC: ! %bb.0: +; SPARC-POPC-NEXT: save %sp, -96, %sp +; SPARC-POPC-NEXT: mov %i1, %o0 +; SPARC-POPC-NEXT: call __clzsi2 +; SPARC-POPC-NEXT: mov %i0, %i1 +; SPARC-POPC-NEXT: mov %o0, %i0 +; SPARC-POPC-NEXT: call __clzsi2 +; SPARC-POPC-NEXT: mov %i1, %o0 +; SPARC-POPC-NEXT: cmp %i1, 0 +; SPARC-POPC-NEXT: bne .LBB3_2 +; SPARC-POPC-NEXT: nop +; SPARC-POPC-NEXT: ! %bb.1: +; SPARC-POPC-NEXT: add %i0, 32, %o0 +; SPARC-POPC-NEXT: .LBB3_2: +; SPARC-POPC-NEXT: mov %g0, %i0 +; SPARC-POPC-NEXT: ret +; SPARC-POPC-NEXT: restore %g0, %o0, %o1 +; +; SPARC-VIS3-LABEL: i64_poison: +; SPARC-VIS3: ! %bb.0: +; SPARC-VIS3-NEXT: cmp %o0, 0 +; SPARC-VIS3-NEXT: bne .LBB3_2 +; SPARC-VIS3-NEXT: nop +; SPARC-VIS3-NEXT: ! %bb.1: +; SPARC-VIS3-NEXT: srl %o1, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: add %o0, -32, %o0 +; SPARC-VIS3-NEXT: add %o0, 32, %o1 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: mov %g0, %o0 +; SPARC-VIS3-NEXT: .LBB3_2: +; SPARC-VIS3-NEXT: srl %o0, 0, %o0 +; SPARC-VIS3-NEXT: lzcnt %o0, %o0 +; SPARC-VIS3-NEXT: add %o0, -32, %o1 +; SPARC-VIS3-NEXT: retl +; SPARC-VIS3-NEXT: mov %g0, %o0 +; +; SPARC64-LABEL: i64_poison: +; SPARC64: ! %bb.0: +; SPARC64-NEXT: save %sp, -176, %sp +; SPARC64-NEXT: call __clzdi2 +; SPARC64-NEXT: mov %i0, %o0 +; SPARC64-NEXT: ret +; SPARC64-NEXT: restore %g0, %o0, %o0 +; +; SPARC64-POPC-LABEL: i64_poison: +; SPARC64-POPC: ! %bb.0: +; SPARC64-POPC-NEXT: srlx %o0, 1, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 2, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 4, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 8, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 16, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: srlx %o0, 32, %o1 +; SPARC64-POPC-NEXT: or %o0, %o1, %o0 +; SPARC64-POPC-NEXT: xor %o0, -1, %o0 +; SPARC64-POPC-NEXT: retl +; SPARC64-POPC-NEXT: popc %o0, %o0 +; +; SPARC64-VIS3-LABEL: i64_poison: +; SPARC64-VIS3: ! %bb.0: +; SPARC64-VIS3-NEXT: retl +; SPARC64-VIS3-NEXT: lzcnt %o0, %o0 + %ret = call i64 @llvm.ctlz.i64(i64 %x, i1 true) + ret i64 %ret +}