|
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 |
|
9 | 9 | #include "llvm/IR/Intrinsics.h" |
| 10 | +#include "llvm-c/Core.h" |
10 | 11 | #include "llvm/ADT/SmallVector.h" |
11 | 12 | #include "llvm/IR/Constant.h" |
12 | 13 | #include "llvm/IR/IRBuilder.h" |
|
25 | 26 | #include "llvm/IR/IntrinsicsS390.h" |
26 | 27 | #include "llvm/IR/IntrinsicsX86.h" |
27 | 28 | #include "llvm/IR/Module.h" |
| 29 | +#include "llvm/Support/Parallel.h" |
28 | 30 | #include "gtest/gtest.h" |
29 | 31 |
|
30 | 32 | using namespace llvm; |
@@ -127,6 +129,82 @@ TEST(IntrinsicNameLookup, MSBuiltinLookup) { |
127 | 129 | EXPECT_EQ(ID, getIntrinsicForMSBuiltin(Target, Builtin)); |
128 | 130 | } |
129 | 131 |
|
| 132 | +// Test C API to get/copy LLVM intrinsic name. |
| 133 | +TEST(IntrinsicNameLookup, LLVMIntrinsicGetCopyNameSimple) { |
| 134 | + static constexpr struct { |
| 135 | + Intrinsic::ID ID; |
| 136 | + const char *Name; |
| 137 | + } Tests[] = {{Intrinsic::not_intrinsic, "not_intrinsic"}, |
| 138 | + {Intrinsic::assume, "llvm.assume"}, |
| 139 | + {Intrinsic::coro_free, "llvm.coro.free"}, |
| 140 | + {Intrinsic::aarch64_break, "llvm.aarch64.break"}, |
| 141 | + {Intrinsic::x86_int, "llvm.x86.int"}}; |
| 142 | + |
| 143 | + for (auto [ID, ExpectedName] : Tests) { |
| 144 | + size_t NameSize = 0; |
| 145 | + const char *CName = LLVMIntrinsicGetName(ID, &NameSize); |
| 146 | + StringRef Name(CName, NameSize); |
| 147 | + |
| 148 | + // Verify we get correct name. |
| 149 | + EXPECT_EQ(Name, ExpectedName); |
| 150 | + const char *CName1 = LLVMIntrinsicGetName(ID, &NameSize); |
| 151 | + |
| 152 | + // Verify we get the same pointer and length the second time. |
| 153 | + EXPECT_EQ(CName, CName1); |
| 154 | + EXPECT_EQ(NameSize, Name.size()); |
| 155 | + } |
| 156 | + |
| 157 | + for (auto [ID, ExpectedName] : Tests) { |
| 158 | + size_t NameSize = 0; |
| 159 | + // Now test the copy API. |
| 160 | + char *CName = LLVMIntrinsicCopyName(ID, &NameSize); |
| 161 | + StringRef Name(CName, NameSize); |
| 162 | + |
| 163 | + // Verify we get correct name. |
| 164 | + EXPECT_EQ(Name, ExpectedName); |
| 165 | + |
| 166 | + // Verify we get the different pointer and same length the second time. |
| 167 | + char *CName1 = LLVMIntrinsicCopyName(ID, &NameSize); |
| 168 | + EXPECT_NE(CName, CName1); |
| 169 | + EXPECT_EQ(NameSize, Name.size()); |
| 170 | + |
| 171 | + free(CName); |
| 172 | + free(CName1); |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +// Test C API to get/copy LLVM intrinsic name. |
| 177 | +TEST(IntrinsicNameLookup, LLVMIntrinsicGetNameMultiThreaded) { |
| 178 | + constexpr unsigned NUM_TASKS = 16; |
| 179 | + constexpr unsigned STEP = 40; |
| 180 | + std::map<unsigned, StringRef> LookupResults[NUM_TASKS]; |
| 181 | + |
| 182 | + parallelFor(0, NUM_TASKS, [&](size_t Idx) { |
| 183 | + for (unsigned ID = 0; ID < Intrinsic::num_intrinsics; ID += STEP) { |
| 184 | + if (LLVMIntrinsicIsOverloaded(ID)) |
| 185 | + continue; |
| 186 | + size_t NameSize; |
| 187 | + const char *Name = LLVMIntrinsicGetName(ID, &NameSize); |
| 188 | + LookupResults[Idx].insert({ID, StringRef(Name, NameSize)}); |
| 189 | + } |
| 190 | + }); |
| 191 | + |
| 192 | + // Validate data. |
| 193 | + for (unsigned ID = 0; ID < Intrinsic::num_intrinsics; ID += STEP) { |
| 194 | + if (LLVMIntrinsicIsOverloaded(ID)) |
| 195 | + continue; |
| 196 | + size_t NameSize; |
| 197 | + const char *CName = LLVMIntrinsicGetName(ID, &NameSize); |
| 198 | + StringRef Name(CName, NameSize); |
| 199 | + for (unsigned Idx = 0; Idx < NUM_TASKS; ++Idx) { |
| 200 | + auto Iter = LookupResults[Idx].find(ID); |
| 201 | + ASSERT_NE(Iter, LookupResults[Idx].end()); |
| 202 | + EXPECT_EQ(Iter->second.size(), Name.size()); |
| 203 | + EXPECT_EQ(Iter->second.data(), Name.data()); |
| 204 | + } |
| 205 | + } |
| 206 | +} |
| 207 | + |
130 | 208 | TEST_F(IntrinsicsTest, InstrProfInheritance) { |
131 | 209 | auto isInstrProfInstBase = [](const Instruction &I) { |
132 | 210 | return isa<InstrProfInstBase>(I); |
|
0 commit comments