Index: include/llvm/IR/Intrinsics.h =================================================================== --- include/llvm/IR/Intrinsics.h +++ include/llvm/IR/Intrinsics.h @@ -80,12 +80,20 @@ /// the intrinsic. Function *getDeclaration(Module *M, ID id, ArrayRef Tys = None); + /// Looks up Name in NameTable via binary search. NameTable must be sorted. + /// If NameTable contains an exact match for Name or a prefix of Name followed + /// by a dot, its index in NameTable is returned. Otherwise, -1 is returned. + int lookupIntrinsicByName(ArrayRef NameTable, StringRef Name); + /// Looks up Name in NameTable via binary search. NameTable must be sorted /// and all entries must start with "llvm.". If NameTable contains an exact /// match for Name or a prefix of Name followed by a dot, its index in /// NameTable is returned. Otherwise, -1 is returned. - int lookupLLVMIntrinsicByName(ArrayRef NameTable, - StringRef Name); + inline int lookupLLVMIntrinsicByName(ArrayRef NameTable, + StringRef Name) { + assert(Name.startswith("llvm.")); + return lookupIntrinsicByName(NameTable, Name); + } /// Map a GCC builtin name to an intrinsic ID. ID getIntrinsicForGCCBuiltin(const char *Prefix, StringRef BuiltinName); Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -264,6 +264,7 @@ list IntrProperties = properties; bit isTarget = 0; + bit SkipLLVMPrefix = 0; } /// GCCBuiltin - If this intrinsic exactly corresponds to a GCC builtin, this Index: lib/IR/IntrinsicInst.cpp =================================================================== --- lib/IR/IntrinsicInst.cpp +++ lib/IR/IntrinsicInst.cpp @@ -48,25 +48,22 @@ return nullptr; } -int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef NameTable, - StringRef Name) { - assert(Name.startswith("llvm.")); - +int llvm::Intrinsic::lookupIntrinsicByName(ArrayRef NameTable, + StringRef Name) { // Do successive binary searches of the dotted name components. For // "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of // intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then // "llvm.gc.experimental.statepoint", and then we will stop as the range is - // size 1. During the search, we can skip the prefix that we already know is - // identical. By using strncmp we consider names with differing suffixes to + // size 1. By using strncmp we consider names with differing suffixes to // be part of the equal range. size_t CmpStart = 0; - size_t CmpEnd = 4; // Skip the "llvm" component. + size_t CmpEnd = 0; const char *const *Low = NameTable.begin(); const char *const *High = NameTable.end(); const char *const *LastLow = Low; while (CmpEnd < Name.size() && High - Low > 0) { CmpStart = CmpEnd; - CmpEnd = Name.find('.', CmpStart + 1); + CmpEnd = Name.find('.', CmpStart == 0 ? 0 : CmpStart + 1); CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd; auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) { return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0; Index: test/TableGen/intrinsic-skip-llvm-prefix.td =================================================================== --- /dev/null +++ test/TableGen/intrinsic-skip-llvm-prefix.td @@ -0,0 +1,54 @@ +// RUN: llvm-tblgen -gen-tgt-intrinsic %s | FileCheck %s +// XFAIL: vg_leak + +class IntrinsicProperty; + +class ValueType { + string Namespace = "MVT"; + int Size = size; + int Value = value; +} + +class LLVMType { + ValueType VT = vt; +} + +class Intrinsic { + string LLVMName = name; + string TargetPrefix = ""; + list RetTypes = []; + list ParamTypes = []; + list IntrProperties = []; + bit isTarget = 0; + bit SkipLLVMPrefix = 0; +} + + +// CHECK-DAG: intrinsic_for_target{{,?}} // llvm.intrinsic.for.target +// CHECK-DAG: explicitly_named_intrinsic_1{{,?}} // llvm.intrinsic.with.explicit.name +// CHECK-DAG: target_other_intrinsic{{,?}} // llvm.target.other.intrinsic +// CHECK-DAG: explicitly_named_intrinsic_3{{,?}} // llvm.target.intrinsic.with.explicit.name +// CHECK-DAG: no_llvm_prefix{{,?}} // no.llvm.prefix +// CHECK-DAG: explicitly_named_intrinsic_2{{,?}} // intrinsic.without.llvm.prefix +// CHECK-DAG: target_intrinsic{{,?}} // target.intrinsic +// CHECK-DAG: explicitly_named_intrinsic_4{{,?}} // target.intrinsic.without.llvm.prefix + +let isTarget = 1 in { + def int_intrinsic_for_target : Intrinsic; + def int_explicitly_named_intrinsic_1 : Intrinsic<"llvm.intrinsic.with.explicit.name">; + + let TargetPrefix = "target" in { + def int_target_other_intrinsic : Intrinsic; + def int_explicitly_named_intrinsic_3 : Intrinsic<"llvm.target.intrinsic.with.explicit.name">; + } + + let SkipLLVMPrefix = 1 in { + def int_no_llvm_prefix : Intrinsic; + def int_explicitly_named_intrinsic_2 : Intrinsic<"intrinsic.without.llvm.prefix">; + } + + let TargetPrefix = "target", SkipLLVMPrefix = 1 in { + def int_target_intrinsic : Intrinsic; + def int_explicitly_named_intrinsic_4 : Intrinsic<"target.intrinsic.without.llvm.prefix">; + } +} Index: unittests/IR/IntrinsicsTest.cpp =================================================================== --- unittests/IR/IntrinsicsTest.cpp +++ unittests/IR/IntrinsicsTest.cpp @@ -37,4 +37,60 @@ EXPECT_EQ(4, I); } +TEST(IntrinNameLookup, DontAssumeLLVMPrefix) { + int I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo"); + EXPECT_EQ(0, I); + I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo.f64"); + EXPECT_EQ(0, I); + I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo.b"); + EXPECT_EQ(2, I); + I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo.b.a"); + EXPECT_EQ(3, I); + I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo.c"); + EXPECT_EQ(4, I); + I = Intrinsic::lookupIntrinsicByName(NameTable1, "llvm.foo.c.f64"); + EXPECT_EQ(4, I); +} + +static const char *const NameTable2[] = { + "p1.foo", + "p1.foo.a", + "p1.foo.b", + "p1.foo.b.a", + "p1.foo.c", + "p2.foo", + "p2.foo.a", + "p2.foo.b", + "p2.foo.b.a", + "p2.foo.c", +}; + +TEST(IntrinNameLookup, OtherPrefixes) { + int I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo"); + EXPECT_EQ(0, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo.f64"); + EXPECT_EQ(0, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo.b"); + EXPECT_EQ(2, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo.b.a"); + EXPECT_EQ(3, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo.c"); + EXPECT_EQ(4, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p1.foo.c.f64"); + EXPECT_EQ(4, I); + + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo"); + EXPECT_EQ(5, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo.f64"); + EXPECT_EQ(5, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo.b"); + EXPECT_EQ(7, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo.b.a"); + EXPECT_EQ(8, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo.c"); + EXPECT_EQ(9, I); + I = Intrinsic::lookupIntrinsicByName(NameTable2, "p2.foo.c.f64"); + EXPECT_EQ(9, I); +} + } // end namespace Index: utils/TableGen/CodeGenTarget.cpp =================================================================== --- utils/TableGen/CodeGenTarget.cpp +++ utils/TableGen/CodeGenTarget.cpp @@ -491,28 +491,28 @@ TargetPrefix = R->getValueAsString("TargetPrefix"); Name = R->getValueAsString("LLVMName"); + bool SkipLLVMPrefix = + R->getValue("SkipLLVMPrefix") && R->getValueAsBit("SkipLLVMPrefix"); + if (SkipLLVMPrefix && !R->getValueAsBit("isTarget")) + PrintFatalError( + "Skipping the `llvm.` prefix is only allowed for target intrinsics."); + + std::string RequiredPrefix = SkipLLVMPrefix ? "" : "llvm."; if (Name == "") { // If an explicit name isn't specified, derive one from the DefName. - Name = "llvm."; + Name = RequiredPrefix; for (unsigned i = 0, e = EnumName.size(); i != e; ++i) Name += (EnumName[i] == '_') ? '.' : EnumName[i]; - } else { - // Verify it starts with "llvm.". - if (Name.size() <= 5 || - std::string(Name.begin(), Name.begin() + 5) != "llvm.") - PrintFatalError("Intrinsic '" + DefName + "'s name does not start with 'llvm.'!"); } - // If TargetPrefix is specified, make sure that Name starts with - // "llvm..". - if (!TargetPrefix.empty()) { - if (Name.size() < 6+TargetPrefix.size() || - std::string(Name.begin() + 5, Name.begin() + 6 + TargetPrefix.size()) - != (TargetPrefix + ".")) - PrintFatalError("Intrinsic '" + DefName + "' does not start with 'llvm." + - TargetPrefix + ".'!"); - } + if (!TargetPrefix.empty()) + RequiredPrefix += TargetPrefix + "."; + + // Check the prefixes. + if (Name.compare(0, RequiredPrefix.size(), RequiredPrefix) != 0) + PrintFatalError("Intrinsic '" + DefName + "'s name does not start with '" + + RequiredPrefix + "'!"); // Parse the list of return types. std::vector OverloadedVTs;