From: Craig Topper Date: Tue, 11 Oct 2011 06:44:02 +0000 (+0000) Subject: Add X86 LZCNT instruction. Including instruction selection support. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=37f2167f15608ff56d202ff21954a456aab6e534;p=oota-llvm.git Add X86 LZCNT instruction. Including instruction selection support. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@141651 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index 85376066da4..133ae7066e9 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This is a target description file for the Intel i386 architecture, referred to -// here as the "X86" architecture. +// This is a target description file for the Intel i386 architecture, referred +// to here as the "X86" architecture. // //===----------------------------------------------------------------------===// @@ -102,6 +102,8 @@ def FeatureRDRAND : SubtargetFeature<"rdrand", "HasRDRAND", "true", "Support RDRAND instruction">; def FeatureF16C : SubtargetFeature<"f16c", "HasF16C", "true", "Support 16-bit floating point conversion instructions">; +def FeatureLZCNT : SubtargetFeature<"lzcnt", "HasLZCNT", "true", + "Support LZCNT instruction">; //===----------------------------------------------------------------------===// // X86 processors supported. diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 5bd3e2b6711..251064b3bb0 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -380,14 +380,19 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) setOperationAction(ISD::FLT_ROUNDS_ , MVT::i32 , Custom); setOperationAction(ISD::CTTZ , MVT::i8 , Custom); - setOperationAction(ISD::CTLZ , MVT::i8 , Custom); setOperationAction(ISD::CTTZ , MVT::i16 , Custom); - setOperationAction(ISD::CTLZ , MVT::i16 , Custom); setOperationAction(ISD::CTTZ , MVT::i32 , Custom); - setOperationAction(ISD::CTLZ , MVT::i32 , Custom); - if (Subtarget->is64Bit()) { + if (Subtarget->is64Bit()) setOperationAction(ISD::CTTZ , MVT::i64 , Custom); - setOperationAction(ISD::CTLZ , MVT::i64 , Custom); + + if (Subtarget->hasLZCNT()) { + setOperationAction(ISD::CTLZ , MVT::i8 , Promote); + } else { + setOperationAction(ISD::CTLZ , MVT::i8 , Custom); + setOperationAction(ISD::CTLZ , MVT::i16 , Custom); + setOperationAction(ISD::CTLZ , MVT::i32 , Custom); + if (Subtarget->is64Bit()) + setOperationAction(ISD::CTLZ , MVT::i64 , Custom); } if (Subtarget->hasPOPCNT()) { diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 2640a90cb77..e3aa964c9d1 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -476,6 +476,7 @@ def HasFMA4 : Predicate<"Subtarget->hasFMA4()">; def HasMOVBE : Predicate<"Subtarget->hasMOVBE()">; def HasRDRAND : Predicate<"Subtarget->hasRDRAND()">; def HasF16C : Predicate<"Subtarget->hasF16C()">; +def HasLZCNT : Predicate<"Subtarget->hasLZCNT()">; def FPStackf32 : Predicate<"!Subtarget->hasXMM()">; def FPStackf64 : Predicate<"!Subtarget->hasXMMInt()">; def HasCmpxchg16b: Predicate<"Subtarget->hasCmpxchg16b()">; @@ -1339,6 +1340,32 @@ let Predicates = [HasRDRAND], Defs = [EFLAGS] in { "rdrand{q}\t$dst", []>, TB; } +//===----------------------------------------------------------------------===// +// LZCNT Instruction +// +let Predicates = [HasLZCNT], Defs = [EFLAGS] in { + def LZCNT16rr : I<0xBD, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src), + "lzcnt{w}\t{$src, $dst|$dst, $src}", + [(set GR16:$dst, (ctlz GR16:$src))]>, XS, OpSize; + def LZCNT16rm : I<0xBD, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src), + "lzcnt{w}\t{$src, $dst|$dst, $src}", + [(set GR16:$dst, (ctlz (loadi16 addr:$src)))]>, XS, OpSize; + + def LZCNT32rr : I<0xBD, MRMSrcReg, (outs GR32:$dst), (ins GR32:$src), + "lzcnt{l}\t{$src, $dst|$dst, $src}", + [(set GR32:$dst, (ctlz GR32:$src))]>, XS; + def LZCNT32rm : I<0xBD, MRMSrcMem, (outs GR32:$dst), (ins i32mem:$src), + "lzcnt{l}\t{$src, $dst|$dst, $src}", + [(set GR32:$dst, (ctlz (loadi32 addr:$src)))]>, XS; + + def LZCNT64rr : RI<0xBD, MRMSrcReg, (outs GR64:$dst), (ins GR64:$src), + "lzcnt{q}\t{$src, $dst|$dst, $src}", + [(set GR64:$dst, (ctlz GR64:$src))]>, XS; + def LZCNT64rm : RI<0xBD, MRMSrcMem, (outs GR64:$dst), (ins i64mem:$src), + "lzcnt{q}\t{$src, $dst|$dst, $src}", + [(set GR64:$dst, (ctlz (loadi64 addr:$src)))]>, XS; +} + //===----------------------------------------------------------------------===// // Subsystems. //===----------------------------------------------------------------------===// diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index db5792a2b28..c2f60be3219 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -255,6 +255,10 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { HasX86_64 = true; ToggleFeature(X86::Feature64Bit); } + if ((ECX >> 5) & 0x1) { + HasLZCNT = true; + ToggleFeature(X86::FeatureLZCNT); + } if (IsAMD && ((ECX >> 6) & 0x1)) { HasSSE4A = true; ToggleFeature(X86::FeatureSSE4A); @@ -285,6 +289,7 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &CPU, , HasMOVBE(false) , HasRDRAND(false) , HasF16C(false) + , HasLZCNT(false) , IsBTMemSlow(false) , IsUAMemFast(false) , HasVectorUAMem(false) diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index 37704dc2343..f67575a94df 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -99,6 +99,9 @@ protected: /// HasF16C - Processor has 16-bit floating point conversion instructions. bool HasF16C; + /// HasLZCNT - Processor has LZCNT instruction. + bool HasLZCNT; + /// IsBTMemSlow - True if BT (bit test) of memory instructions are slow. bool IsBTMemSlow; @@ -184,6 +187,7 @@ public: bool hasMOVBE() const { return HasMOVBE; } bool hasRDRAND() const { return HasRDRAND; } bool hasF16C() const { return HasF16C; } + bool hasLZCNT() const { return HasLZCNT; } bool isBTMemSlow() const { return IsBTMemSlow; } bool isUnalignedMemAccessFast() const { return IsUAMemFast; } bool hasVectorUAMem() const { return HasVectorUAMem; } diff --git a/test/MC/Disassembler/X86/simple-tests.txt b/test/MC/Disassembler/X86/simple-tests.txt index d1d60ef6d04..1540d12a280 100644 --- a/test/MC/Disassembler/X86/simple-tests.txt +++ b/test/MC/Disassembler/X86/simple-tests.txt @@ -488,3 +488,12 @@ # CHECK: popcntq %rax, %rax 0xf3 0x48 0x0f 0xb8 0xc0 + +# CHECK: lzcntl %eax, %eax +0xf3 0x0f 0xbd 0xc0 + +# CHECK: lzcntw %ax, %ax +0x66 0xf3 0x0f 0xbd 0xc0 + +# CHECK: lzcntq %rax, %rax +0xf3 0x48 0x0f 0xbd 0xc0 diff --git a/test/MC/Disassembler/X86/x86-32.txt b/test/MC/Disassembler/X86/x86-32.txt index f8944da9eed..146b6667e51 100644 --- a/test/MC/Disassembler/X86/x86-32.txt +++ b/test/MC/Disassembler/X86/x86-32.txt @@ -471,3 +471,9 @@ # CHECK: popcntw %ax, %ax 0x66 0xf3 0x0f 0xb8 0xc0 + +# CHECK: lzcntl %eax, %eax +0xf3 0x0f 0xbd 0xc0 + +# CHECK: lzcntw %ax, %ax +0x66 0xf3 0x0f 0xbd 0xc0