|
14 | 14 | #include "llvm/Analysis/LoopInfo.h"
|
15 | 15 | #include "llvm/AsmParser/Parser.h"
|
16 | 16 | #include "llvm/IR/Argument.h"
|
| 17 | +#include "llvm/IR/BasicBlock.h" |
17 | 18 | #include "llvm/IR/Constant.h"
|
18 | 19 | #include "llvm/IR/DIBuilder.h"
|
19 | 20 | #include "llvm/IR/DebugInfo.h"
|
20 | 21 | #include "llvm/IR/Function.h"
|
21 | 22 | #include "llvm/IR/IRBuilder.h"
|
22 | 23 | #include "llvm/IR/InstIterator.h"
|
| 24 | +#include "llvm/IR/Instruction.h" |
23 | 25 | #include "llvm/IR/Instructions.h"
|
24 | 26 | #include "llvm/IR/IntrinsicInst.h"
|
25 | 27 | #include "llvm/IR/LLVMContext.h"
|
26 | 28 | #include "llvm/IR/Module.h"
|
27 | 29 | #include "llvm/IR/Verifier.h"
|
28 | 30 | #include "llvm/Support/SourceMgr.h"
|
| 31 | +#include "llvm/Transforms/Utils/ValueMapper.h" |
29 | 32 | #include "gtest/gtest.h"
|
30 | 33 |
|
31 | 34 | using namespace llvm;
|
@@ -1162,4 +1165,105 @@ declare i64 @foo(i32 noundef) local_unnamed_addr
|
1162 | 1165 | auto NewM = llvm::CloneModule(*M);
|
1163 | 1166 | EXPECT_FALSE(verifyModule(*NewM, &errs()));
|
1164 | 1167 | }
|
| 1168 | + |
| 1169 | +TEST_F(CloneInstruction, cloneKeyInstructions) { |
| 1170 | + LLVMContext Context; |
| 1171 | + |
| 1172 | + std::unique_ptr<Module> M = parseIR(Context, R"( |
| 1173 | + define void @test(ptr align 4 %dst) !dbg !3 { |
| 1174 | + store i64 1, ptr %dst, align 4, !dbg !6 |
| 1175 | + store i64 2, ptr %dst, align 4, !dbg !7 |
| 1176 | + store i64 3, ptr %dst, align 4, !dbg !8 |
| 1177 | + ret void, !dbg !9 |
| 1178 | + } |
| 1179 | +
|
| 1180 | + !llvm.dbg.cu = !{!0} |
| 1181 | + !llvm.module.flags = !{!2} |
| 1182 | + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1) |
| 1183 | + !1 = !DIFile(filename: "test.cpp", directory: "") |
| 1184 | + !2 = !{i32 1, !"Debug Info Version", i32 3} |
| 1185 | + !3 = distinct !DISubprogram(name: "test", scope: !0, unit: !0) |
| 1186 | + !4 = distinct !DISubprogram(name: "inlined", scope: !0, unit: !0, retainedNodes: !{!5}) |
| 1187 | + !5 = !DILocalVariable(name: "awaitables", scope: !4) |
| 1188 | + !6 = !DILocation(line: 1, scope: !4, inlinedAt: !8, atomGroup: 1, atomRank: 1) |
| 1189 | + !7 = !DILocation(line: 2, scope: !3, atomGroup: 1, atomRank: 1) |
| 1190 | + !8 = !DILocation(line: 3, scope: !3, atomGroup: 1, atomRank: 1) |
| 1191 | + !9 = !DILocation(line: 4, scope: !3, atomGroup: 2, atomRank: 1) |
| 1192 | + )"); |
| 1193 | + |
| 1194 | + ASSERT_FALSE(verifyModule(*M, &errs())); |
| 1195 | + |
| 1196 | +#ifdef EXPERIMENTAL_KEY_INSTRUCTIONS |
| 1197 | +#define EXPECT_ATOM(Inst, G) \ |
| 1198 | + EXPECT_TRUE(Inst->getDebugLoc()); \ |
| 1199 | + EXPECT_EQ(Inst->getDebugLoc()->getAtomGroup(), uint64_t(G)); |
| 1200 | +#else |
| 1201 | +#define EXPECT_ATOM(Inst, G) (void)Inst; |
| 1202 | +#endif |
| 1203 | + |
| 1204 | + Function *F = M->getFunction("test"); |
| 1205 | + BasicBlock *BB = &*F->begin(); |
| 1206 | + ASSERT_TRUE(F); |
| 1207 | + Instruction *Store1 = &*BB->begin(); |
| 1208 | + Instruction *Store2 = Store1->getNextNode(); |
| 1209 | + Instruction *Store3 = Store2->getNextNode(); |
| 1210 | + Instruction *Ret = Store3->getNextNode(); |
| 1211 | + |
| 1212 | + // Test the remapping works as expected outside of cloning. |
| 1213 | + ValueToValueMapTy VM; |
| 1214 | + // Store1 and Store2 have the same atomGroup number, but have different |
| 1215 | + // inlining scopes, so only Store1 should change group. |
| 1216 | + mapAtomInstance(Store1->getDebugLoc(), VM); |
| 1217 | + for (Instruction &I : *BB) |
| 1218 | + RemapSourceAtom(&I, VM); |
| 1219 | + EXPECT_ATOM(Store1, 3); |
| 1220 | + EXPECT_ATOM(Store2, 1); |
| 1221 | + EXPECT_ATOM(Store3, 1); |
| 1222 | + EXPECT_ATOM(Ret, 2); |
| 1223 | + VM.clear(); |
| 1224 | + |
| 1225 | + // Store2 and Store3 have the same group number; both should get remapped. |
| 1226 | + mapAtomInstance(Store2->getDebugLoc(), VM); |
| 1227 | + for (Instruction &I : *BB) |
| 1228 | + RemapSourceAtom(&I, VM); |
| 1229 | + EXPECT_ATOM(Store1, 3); |
| 1230 | + EXPECT_ATOM(Store2, 4); |
| 1231 | + EXPECT_ATOM(Store3, 4); |
| 1232 | + EXPECT_ATOM(Ret, 2); |
| 1233 | + VM.clear(); |
| 1234 | + |
| 1235 | + // Cloning BB with MapAtoms=false should clone the atom numbers. |
| 1236 | + BasicBlock *BB2 = |
| 1237 | + CloneBasicBlock(BB, VM, "", nullptr, nullptr, /*MapAtoms*/ false); |
| 1238 | + for (Instruction &I : *BB2) |
| 1239 | + RemapSourceAtom(&I, VM); |
| 1240 | + Store1 = &*BB2->begin(); |
| 1241 | + Store2 = Store1->getNextNode(); |
| 1242 | + Store3 = Store2->getNextNode(); |
| 1243 | + Ret = Store3->getNextNode(); |
| 1244 | + EXPECT_ATOM(Store1, 3); |
| 1245 | + EXPECT_ATOM(Store2, 4); |
| 1246 | + EXPECT_ATOM(Store3, 4); |
| 1247 | + EXPECT_ATOM(Ret, 2); |
| 1248 | + VM.clear(); |
| 1249 | + delete BB2; |
| 1250 | + |
| 1251 | + // Cloning BB with MapAtoms=true should map the atom numbers. |
| 1252 | + BasicBlock *BB3 = |
| 1253 | + CloneBasicBlock(BB, VM, "", nullptr, nullptr, /*MapAtoms*/ true); |
| 1254 | + for (Instruction &I : *BB3) |
| 1255 | + RemapSourceAtom(&I, VM); |
| 1256 | + Store1 = &*BB3->begin(); |
| 1257 | + Store2 = Store1->getNextNode(); |
| 1258 | + Store3 = Store2->getNextNode(); |
| 1259 | + Ret = Store3->getNextNode(); |
| 1260 | + EXPECT_ATOM(Store1, 5); |
| 1261 | + EXPECT_ATOM(Store2, 6); |
| 1262 | + EXPECT_ATOM(Store3, 6); |
| 1263 | + EXPECT_ATOM(Ret, 7); |
| 1264 | + VM.clear(); |
| 1265 | + delete BB3; |
| 1266 | +#undef EXPECT_ATOM |
| 1267 | +} |
| 1268 | + |
1165 | 1269 | } // namespace
|
0 commit comments