LLVM: lib/Transforms/IPO/IROutliner.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
28#include
29#include
30
31#define DEBUG_TYPE "iroutliner"
32
33using namespace llvm;
35
36
37
38namespace llvm {
40
41
42
44
45
46
48
49}
50
51
52
53
54
55
57 "enable-linkonceodr-ir-outlining", cl::Hidden,
58 cl::desc("Enable the IR outliner on linkonceodr functions"),
60
61
62
65 cl::desc("Debug option to outline greedily, without restriction that "
66 "calculated benefit outweighs cost"));
67
68
69
70
71
72
74
75 std::vector<OutlinableRegion *> Regions;
76
77
78
80
82
84
85
86
88
89
91
92
93
95
96
97
98
100
101
102
104
105
106
108
109
110
112
113
114
116
117
118
119
121
126
127
128
130
131
133
134
135
137
138
139
140
141
142
144
145
146
147
148
149
151};
152
153
154
155
156
158 TargetBB.splice(TargetBB.end(), &SourceBB);
159}
160
161
162
163
164
165
168 for (auto &VtoBB : Map)
169 SortedKeys.push_back(VtoBB.first);
170
171
172
173 if (SortedKeys.size() == 1) {
174 assert(!SortedKeys[0] && "Expected a single void value.");
175 return;
176 }
177
179 assert(LHS && RHS && "Expected non void values.");
182
184 });
185}
186
189 std::optional GVN = Candidate->getGVN(V);
190 assert(GVN && "No GVN for incoming value");
191 std::optional CanonNum = Candidate->getCanonicalNum(*GVN);
192 std::optional FirstGVN =
193 Other.Candidate->fromCanonicalNum(*CanonNum);
194 std::optional<Value *> FoundValueOpt = Other.Candidate->fromGVN(*FirstGVN);
195 return FoundValueOpt.value_or(nullptr);
196}
197
202 assert(FirstNonPHI && "block is empty?");
204 if (!CorrespondingVal)
205 return nullptr;
208 return CorrespondingBlock;
209}
210
211
212
213
214
215
216
217
218
219
220
225 for (unsigned Idx = 0, PNEnd = PN.getNumIncomingValues(); Idx != PNEnd;
226 ++Idx) {
227
228
231 continue;
232
234 assert(BI && "Not a branch instruction?");
235
236
237 for (unsigned Succ = 0, End = BI->getNumSuccessors(); Succ != End;
238 Succ++) {
239
241 continue;
243 }
244 }
245 }
246}
247
248
251
253
255
256
257
258
259
262 EndInst = Candidate->end()->Inst;
263 assert(EndInst && "Expected an end instruction?");
264 }
265
266
267
268
269
271 return;
272
274 assert(StartInst && "Expected a start instruction?");
277
279 Candidate->getBasicBlocks(BBSet);
280
281
282
283
284
285
286
287
292 bool EndBBTermAndBackInstDifferent = EndBB->getTerminator() != BackInst;
294 unsigned NumPredsOutsideRegion = 0;
295 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
296 if (!BBSet.contains(PN->getIncomingBlock(i))) {
297 PHIPredBlock = PN->getIncomingBlock(i);
298 ++NumPredsOutsideRegion;
299 continue;
300 }
301
302
303
304
305 IBlock = PN->getIncomingBlock(i);
306 if (IBlock == EndBB && EndBBTermAndBackInstDifferent) {
307 PHIPredBlock = PN->getIncomingBlock(i);
308 ++NumPredsOutsideRegion;
309 }
310 }
311
312 if (NumPredsOutsideRegion > 1)
313 return;
314
315 It++;
316 }
317
318
319
321 return;
322
323
324
326 BackInst != &*std::prev(EndBB->getFirstInsertionPt()))
327 return;
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 std::string OriginalName = PrevBB->getName().str();
345
346 StartBB = PrevBB->splitBasicBlock(StartInst, OriginalName + "_to_outline");
348
349
350 if (PHIPredBlock)
351 PrevBB->replaceSuccessorsPhiUsesWith(PHIPredBlock, PrevBB);
352
356 FollowBB = EndBB->splitBasicBlock(EndInst, OriginalName + "_after_outline");
359 } else {
363 }
364
365
367 Candidate->getBasicBlocks(BBSet);
368
369
373}
374
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392 assert(StartBB != nullptr && "StartBB for Candidate is not defined!");
393
394 assert(PrevBB->getTerminator() && "Terminator removed from PrevBB!");
395
396
397
398
399
400
401
402
403
404
405
406
410 "PrevBB has more than one predecessor. Should be 0 or 1.");
412 PrevBB->replaceSuccessorsPhiUsesWith(PrevBB, BeforePrevBB);
413 }
414 PrevBB->getTerminator()->eraseFromParent();
415
416
417
418
421 Candidate->getBasicBlocks(BBSet);
422
426 }
427
429
432 PlacementBB = EndBB;
434 assert(FollowBB != nullptr && "FollowBB for Candidate is not defined!");
435 assert(PlacementBB->getTerminator() && "Terminator removed from EndBB!");
440 }
441
443 StartBB->eraseFromParent();
444
445
450
452}
453
454
455
456
457
458
459
460
461
462static std::optional
465
467 if (!CST)
468 return std::nullopt;
469
470
472 bool Inserted;
473
474
475
476 std::tie(GVNToConstantIt, Inserted) =
477 GVNToConstant.insert(std::make_pair(GVN, CST));
478
479
480 if (Inserted || (GVNToConstantIt->second == CST))
481 return true;
482
483 return false;
484}
485
488
489
490
491
492
493
494
495
496
497
498
499
500
503 switch (I->getOpcode()) {
504 case Instruction::FDiv:
505 case Instruction::FRem:
506 case Instruction::SDiv:
507 case Instruction::SRem:
508 case Instruction::UDiv:
509 case Instruction::URem:
510 Benefit += 1;
511 break;
512 default:
514 break;
515 }
516 }
517
518 return Benefit;
519}
520
521
522
523
524
525
526
527
528
529
534 if (OutputMapping != OutputMappings.end())
535 return OutputMapping->second;
537}
538
539
540
541
542
543
544
545
546
547
548static bool
552 bool ConstantsTheSame = true;
553
556
557
558
559
560 for (Value *V : ID.OperVals) {
561 std::optional GVNOpt = C.getGVN(V);
562 assert(GVNOpt && "Expected a GVN for operand?");
563 unsigned GVN = *GVNOpt;
564
565
568 ConstantsTheSame = false;
569 continue;
570 }
571
572
573
574
575
576 std::optional ConstantMatches =
578 if (ConstantMatches) {
579 if (*ConstantMatches)
580 continue;
581 else
582 ConstantsTheSame = false;
583 }
584
585
586
587
588 if (GVNToConstant.contains(GVN))
589 ConstantsTheSame = false;
590
592 }
593 }
594
595 return ConstantsTheSame;
596}
597
604
615
616
617
618
619
624 return SP;
625
626 return nullptr;
627}
628
629Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group,
630 unsigned FunctionNameSuffix) {
632
634
635
636
637
638
639
640
641
642 for (OutlinableRegion *R : Group.Regions) {
643 Type *ExtractedFuncType = R->ExtractedFunction->getReturnType();
646 RetTy = ExtractedFuncType;
647 }
648
651
652
653
656 "outlined_ir_func_" + std::to_string(FunctionNameSuffix), M);
657
658
661 Attribute::SwiftError);
662
665
666
667
670
671 DICompileUnit *CU = SP->getUnit();
672 DIBuilder DB(M, true, CU);
673 DIFile *Unit = SP->getFile();
674 Mangler Mg;
675
676 std::string Dummy;
677 llvm::raw_string_ostream MangledNameStream(Dummy);
679
680 DISubprogram *OutlinedSP = DB.createFunction(
681 Unit , F->getName(), Dummy, Unit ,
682 0 ,
683 DB.createSubroutineType(DB.getOrCreateTypeArray({})),
684 0,
685 DINode::DIFlags::FlagArtificial ,
686
687 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
688
689
690 F->setSubprogram(OutlinedSP);
691
692 DB.finalize();
693 }
694
696}
697
698
699
700
701
702
706 CurrBB.removeFromParent();
707 CurrBB.insertInto(&New);
709
710
711
712
714 NewEnds.insert(std::make_pair(RI->getReturnValue(), &CurrBB));
715
717
718
719
720
721 Val.dropDbgRecords();
722
723
724
726
728
729
730
731
732 auto updateLoopInfoLoc = [&New](Metadata *MD) -> Metadata * {
736 Loc->getColumn(), SP, nullptr);
737 return MD;
738 };
740 continue;
741 }
742
743
744 if (DISubprogram *SP = New.getSubprogram()) {
746 Val.setDebugLoc(DI);
747 }
748 }
749 }
750}
751
752
753
754
755
756
757
758
759
760
762 std::vector &Inputs) {
764
765
766 for (IRInstructionDataList::iterator IDIt = C.begin(), EndIDIt = C.end();
767 IDIt != EndIDIt; IDIt++) {
768 for (Value *V : (*IDIt).OperVals) {
769
770
771 unsigned GVN = *C.getGVN(V);
773 if (NotSame.contains(GVN) && Seen.insert(GVN).second)
774 Inputs.push_back(GVN);
775 }
776 }
777}
778
779
780
781
782
783
784
785
786
787
788
792 std::vector &EndInputNumbers) {
793
794
795
797 assert(Input && "Have a nullptr as an input");
798 auto It = OutputMappings.find(Input);
799 if (It != OutputMappings.end())
800 Input = It->second;
801 assert(C.getGVN(Input) && "Could not find a numbering for the given input");
802 EndInputNumbers.push_back(*C.getGVN(Input));
803 }
804}
805
806
807
808
809
810
811
812
813
814static void
818
819
821 auto It = OutputMappings.find(Input);
822 if (It != OutputMappings.end())
823 Input = It->second;
825 }
826}
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
851
852
853
854
855
856
857
858
859
860
861 SetVector<Value *> OverallInputs, PremappedInputs, SinkCands, HoistCands,
862 DummyOutputs;
863
864
865
867 CE->findInputsOutputs(OverallInputs, DummyOutputs, SinkCands);
868 assert(Region.StartBB && "Region must have a start BasicBlock!");
872
873
874
875 if (!CE->isEligible()) {
876 Region.IgnoreRegion = true;
877 return;
878 }
879
880
881 CE->findAllocas(CEAC, SinkCands, HoistCands, Dummy);
882 CE->findInputsOutputs(PremappedInputs, Outputs, SinkCands);
883
884
885
886
887
888
889 if (OverallInputs.size() != PremappedInputs.size()) {
890 Region.IgnoreRegion = true;
891 return;
892 }
893
895
896 mapInputsToGVNs(C, OverallInputs, OutputMappings, InputGVNs);
897
899 ArgInputs);
900
901
902
904}
905
906
907
908
909
910
911
912
913
914
915
916static void
918 std::vector &InputGVNs,
920
923
924
925 unsigned TypeIndex = 0;
926
927
928 unsigned OriginalIndex = 0;
929
930
931
932
933
934
935
936
937
938
939 for (unsigned InputVal : InputGVNs) {
940 std::optional CanonicalNumberOpt = C.getCanonicalNum(InputVal);
941 assert(CanonicalNumberOpt && "Canonical number not found?");
942 unsigned CanonicalNumber = *CanonicalNumberOpt;
943
944 std::optional<Value *> InputOpt = C.fromGVN(InputVal);
945 assert(InputOpt && "Global value number not found?");
947
950
953
954
955 if (Input->isSwiftError()) {
958 "Argument already marked with swifterr for this OutlinableGroup!");
960 }
961 }
962
963
964
967 Region.AggArgToConstant.insert(std::make_pair(AggArgIt->second, CST));
968 else {
970 std::make_pair(CanonicalNumber, TypeIndex));
971 Region.AggArgToConstant.insert(std::make_pair(TypeIndex, CST));
972 }
973 TypeIndex++;
974 continue;
975 }
976
977
978
980
982 if (OriginalIndex != AggArgIt->second)
983 Region.ChangedArgOrder = true;
984 Region.ExtractedArgToAgg.insert(
985 std::make_pair(OriginalIndex, AggArgIt->second));
986 Region.AggArgToExtracted.insert(
987 std::make_pair(AggArgIt->second, OriginalIndex));
988 } else {
990 std::make_pair(CanonicalNumber, TypeIndex));
991 Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex));
992 Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex));
993 }
994 OriginalIndex++;
995 TypeIndex++;
996 }
997
998
999
1000
1001
1005 }
1006
1007 Region.NumExtractedInputs = OriginalIndex;
1008}
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1022
1023
1024
1026 [PHILoc, &PN, V, &BlocksInRegion](unsigned Idx) {
1027 return (Idx != PHILoc && V == PN.getIncomingValue(Idx) &&
1028 !BlocksInRegion.contains(PN.getIncomingBlock(Idx)));
1029 }))
1030 return true;
1031
1032
1033 return any_of(V->users(), [&Exits, &BlocksInRegion](User *U) {
1034 Instruction *I = dyn_cast(U);
1035 if (!I)
1036 return false;
1037
1038
1039
1040
1041 BasicBlock *Parent = I->getParent();
1042 if (BlocksInRegion.contains(Parent))
1043 return false;
1044
1045
1046
1047
1048 if (!isa(I))
1049 return true;
1050
1051
1052
1053
1054
1055 if (!Exits.contains(Parent))
1056 return true;
1057
1058 return false;
1059 });
1060}
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1082 for (PHINode &PN : CurrentExitFromRegion->phis()) {
1083
1085 for (unsigned I = 0, E = PN.getNumIncomingValues(); I < E; ++I)
1086 if (RegionBlocks.contains(PN.getIncomingBlock(I)))
1088
1089
1090 unsigned NumIncomingVals = IncomingVals.size();
1091 if (NumIncomingVals == 0)
1092 continue;
1093
1094
1095
1096 if (NumIncomingVals == 1) {
1097 Value *V = PN.getIncomingValue(*IncomingVals.begin());
1098 OutputsWithNonPhiUses.insert(V);
1099 OutputsReplacedByPHINode.erase(V);
1100 continue;
1101 }
1102
1103
1104 Outputs.insert(&PN);
1105
1106
1107
1108
1109 for (unsigned Idx : IncomingVals) {
1110 Value *V = PN.getIncomingValue(Idx);
1112 outputHasNonPHI(V, Idx, PN, PotentialExitsFromRegion, RegionBlocks)) {
1113 OutputsWithNonPhiUses.insert(V);
1114 OutputsReplacedByPHINode.erase(V);
1115 continue;
1116 }
1117 if (!OutputsWithNonPhiUses.contains(V))
1118 OutputsReplacedByPHINode.insert(V);
1119 }
1120 }
1121}
1122
1123
1124
1126
1128
1129
1130using PHINodeData = std::pair<ArgLocWithBBCanon, CanonList>;
1131
1132
1133
1134
1135
1136
1137
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1161 unsigned AggArgIdx) {
1168 for (unsigned Idx = 0, EIdx = PN->getNumIncomingValues(); Idx < EIdx; Idx++) {
1171
1172
1173 if (!Blocks.contains(IncomingBlock))
1174 continue;
1175
1176
1177
1178
1179
1180
1181 std::optional OGVN = Cand.getGVN(Incoming);
1182 if (!OGVN) {
1183 Region.IgnoreRegion = true;
1184 return std::nullopt;
1185 }
1186
1187
1188 unsigned GVN = *OGVN;
1190 assert(OGVN && "No GVN found for incoming value?");
1192
1193
1194
1195 OGVN = Cand.getGVN(IncomingBlock);
1196
1197
1198
1199
1200 if (!OGVN) {
1202 "Unknown basic block used in exit path PHINode.");
1203
1205
1206
1207
1208
1210 if (!Blocks.contains(Pred)) {
1211 PrevBlock = Pred;
1212 break;
1213 }
1214 assert(PrevBlock && "Expected a predecessor not in the reigon!");
1215 OGVN = Cand.getGVN(PrevBlock);
1216 }
1217 GVN = *OGVN;
1219 assert(OGVN && "No GVN found for incoming block?");
1221 }
1222
1223
1224
1225
1228 std::optional BBGVN = Cand.getGVN(PHIBB);
1229 assert(BBGVN && "Could not find GVN for the incoming block!");
1230
1232 assert(BBGVN && "Could not find canonical number for the incoming block!");
1233
1234
1235
1237 std::make_pair(std::make_pair(*BBGVN, AggArgIdx), PHIGVNs);
1239
1240
1241
1244 bool Inserted = false;
1245 std::tie(PHIToGVNIt, Inserted) = Group.PHINodeGVNToGVNs.insert(
1247 std::tie(GVNToPHIIt, Inserted) = Group.GVNsToPHINodeGVN.insert(
1249 }
1250
1251 return GVNToPHIIt->second;
1252}
1253
1254
1255
1256
1257
1258
1259static void
1264
1267 C.getBasicBlocks(BlocksInRegion, BE);
1268
1269
1273 if (!BlocksInRegion.contains(Succ))
1275
1276
1277
1278
1283 OutputsReplacedByPHINode,
1284 OutputsWithNonPhiUses);
1285
1286
1287 unsigned OriginalIndex = Region.NumExtractedInputs;
1288
1289
1291 bool TypeFound;
1293
1294
1295
1296
1297
1298
1299
1300 for (Value *Output : Outputs) {
1301 TypeFound = false;
1302
1303
1304
1305
1306
1307 unsigned ArgumentSize = Group.ArgumentTypes.size();
1308
1309
1310 if (OutputsReplacedByPHINode.contains(Output))
1311 continue;
1312
1313 unsigned AggArgIdx = 0;
1314 for (unsigned Jdx = TypeIndex; Jdx < ArgumentSize; Jdx++) {
1316 continue;
1317
1318 if (!AggArgsUsed.insert(Jdx).second)
1319 continue;
1320
1321 TypeFound = true;
1322 Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, Jdx));
1323 Region.AggArgToExtracted.insert(std::make_pair(Jdx, OriginalIndex));
1324 AggArgIdx = Jdx;
1325 break;
1326 }
1327
1328
1329
1330
1331 if (!TypeFound) {
1333 M.getDataLayout().getAllocaAddrSpace()));
1334
1335
1336 unsigned ArgTypeIdx = Group.ArgumentTypes.size() - 1;
1337 AggArgsUsed.insert(ArgTypeIdx);
1338 Region.ExtractedArgToAgg.insert(
1339 std::make_pair(OriginalIndex, ArgTypeIdx));
1340 Region.AggArgToExtracted.insert(
1341 std::make_pair(ArgTypeIdx, OriginalIndex));
1342 AggArgIdx = ArgTypeIdx;
1343 }
1344
1345
1347
1348 std::optional GVN;
1350
1351
1352
1353
1354
1355
1356
1357
1358
1360 if (!GVN)
1361 return;
1362 } else {
1363
1364
1365
1366 GVN = C.getGVN(Output);
1367 GVN = C.getCanonicalNum(*GVN);
1368 }
1369
1370
1371
1372
1373 Region.GVNStores.push_back(*GVN);
1374
1375 OriginalIndex++;
1376 TypeIndex++;
1377 }
1378
1379
1380
1382}
1383
1386 std::vector Inputs;
1387 SetVector<Value *> ArgInputs, Outputs;
1388
1390 Outputs);
1391
1392 if (Region.IgnoreRegion)
1393 return;
1394
1395
1396
1398
1399
1400
1402}
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1414 std::vector<Value *> NewCallArgs;
1416
1419 assert(Call && "Call to replace is nullptr?");
1421 assert(AggFunc && "Function to replace with is nullptr?");
1422
1423
1424
1425
1426
1427 if (.ChangedArgOrder && AggFunc->arg_size() == Call->arg_size()) {
1428 LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to "
1429 << *AggFunc << " with same number of arguments\n");
1430 Call->setCalledFunction(AggFunc);
1431 return Call;
1432 }
1433
1434
1435
1436
1437
1438 for (unsigned AggArgIdx = 0; AggArgIdx < AggFunc->arg_size(); AggArgIdx++) {
1439
1440 if (AggArgIdx == AggFunc->arg_size() - 1 &&
1442
1443
1444
1445 LLVM_DEBUG(dbgs() << "Set switch block argument to "
1446 << Region.OutputBlockNum << "\n");
1447 NewCallArgs.push_back(ConstantInt::get(Type::getInt32Ty(M.getContext()),
1448 Region.OutputBlockNum));
1449 continue;
1450 }
1451
1452 ArgPair = Region.AggArgToExtracted.find(AggArgIdx);
1453 if (ArgPair != Region.AggArgToExtracted.end()) {
1454 Value *ArgumentValue = Call->getArgOperand(ArgPair->second);
1455
1456
1457
1458 LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value "
1459 << *ArgumentValue << "\n");
1460 NewCallArgs.push_back(ArgumentValue);
1461 continue;
1462 }
1463
1464
1465 if (auto It = Region.AggArgToConstant.find(AggArgIdx);
1466 It != Region.AggArgToConstant.end()) {
1468 LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value "
1469 << *CST << "\n");
1470 NewCallArgs.push_back(CST);
1471 continue;
1472 }
1473
1474
1475
1476
1477 LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to nullptr\n");
1480 }
1481
1482 LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to "
1483 << *AggFunc << " with new set of arguments\n");
1484
1486 Call->getIterator());
1487
1488
1489
1490
1491
1493 if (Region.NewFront->Inst == OldCall)
1495 if (Region.NewBack->Inst == OldCall)
1497
1498
1499 Call->setDebugLoc(Region.Call->getDebugLoc());
1500
1501
1503
1504
1507
1508
1509
1512
1513 return Call;
1514}
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1526
1527
1528 auto [PhiBlockForRetVal, Inserted] = Group.PHIBlocks.try_emplace(RetVal);
1529 if (!Inserted)
1530 return PhiBlockForRetVal->second;
1531
1532 auto ReturnBlockForRetVal = Group.EndBBs.find(RetVal);
1533 assert(ReturnBlockForRetVal != Group.EndBBs.end() &&
1534 "Could not find output value!");
1535 BasicBlock *ReturnBB = ReturnBlockForRetVal->second;
1536
1537
1538
1541 PhiBlockForRetVal->second = PHIBlock;
1542
1543
1544
1545
1549
1550
1551
1552 for (BranchInst *BI : BranchesToChange)
1553 for (unsigned Succ = 0, End = BI->getNumSuccessors(); Succ < End; Succ++) {
1554 if (BI->getSuccessor(Succ) != ReturnBB)
1555 continue;
1556 BI->setSuccessor(Succ, PHIBlock);
1557 }
1558
1560
1561 return PhiBlockForRetVal->second;
1562}
1563
1564
1565
1566
1567
1568
1569
1570
1571
1575
1576
1577
1578 return Region.Call->getArgOperand(A->getArgNo());
1579}
1580
1581
1582
1583
1584
1585
1586
1587
1591 unsigned ArgNum = A->getArgNo();
1592
1593
1594
1595 if (auto It = Region.AggArgToConstant.find(ArgNum);
1596 It != Region.AggArgToConstant.end())
1597 return It->second;
1598
1599
1600
1601 ArgNum = Region.AggArgToExtracted.find(ArgNum)->second;
1602 return Region.Call->getArgOperand(ArgNum);
1603}
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1618 SmallVector<std::pair<unsigned, BasicBlock *>> &CanonNums,
1619 bool ReplacedWithOutlinedCall = true) {
1620
1621 for (unsigned Idx = 0, EIdx = PN->getNumIncomingValues(); Idx < EIdx; Idx++) {
1624
1625
1627 if (ReplacedWithOutlinedCall)
1629 else
1631 }
1632
1633
1635
1636
1637 std::optional GVN = Region.Candidate->getGVN(IVal);
1638 assert(GVN && "No GVN for incoming value");
1639 std::optional CanonNum = Region.Candidate->getCanonicalNum(*GVN);
1640 assert(CanonNum && "No Canonical Number for GVN");
1641 CanonNums.push_back(std::make_pair(*CanonNum, IBlock));
1642 }
1643}
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1664
1665
1666
1667
1669
1670
1671
1672
1673
1675 false);
1676
1678
1679
1680
1681
1683
1684
1685
1686 for (PHINode &CurrPN : OverallPhiBlock->phis()) {
1687
1688
1689 if (UsedPHIs.contains(&CurrPN))
1690 continue;
1691
1692 CurrentCanonNums.clear();
1693 findCanonNumsForPHI(&CurrPN, *FirstRegion, OutputMappings, CurrentCanonNums,
1694 true);
1695
1696
1697
1698 if (PNCanonNums.size() != CurrentCanonNums.size())
1699 continue;
1700
1701 bool FoundMatch = true;
1702
1703
1704
1705
1706
1707
1708
1709
1710 for (unsigned Idx = 0, Edx = PNCanonNums.size(); Idx < Edx; ++Idx) {
1711 std::pair<unsigned, BasicBlock *> ToCompareTo = CurrentCanonNums[Idx];
1712 std::pair<unsigned, BasicBlock *> ToAdd = PNCanonNums[Idx];
1713 if (ToCompareTo.first != ToAdd.first) {
1714 FoundMatch = false;
1715 break;
1716 }
1717
1719 Region.findCorrespondingBlockIn(*FirstRegion, ToAdd.second);
1720 assert(CorrespondingBlock && "Found block is nullptr");
1721 if (CorrespondingBlock != ToCompareTo.second) {
1722 FoundMatch = false;
1723 break;
1724 }
1725 }
1726
1727
1728
1729 if (FoundMatch) {
1730 UsedPHIs.insert(&CurrPN);
1731 return &CurrPN;
1732 }
1733 }
1734
1735
1736
1740 Idx++) {
1743
1744
1745
1747 Region.findCorrespondingBlockIn(*FirstRegion, IncomingBlock);
1749
1750
1751
1755 continue;
1756 }
1757
1758
1760 Value *Val = Region.findCorrespondingValueIn(*FirstRegion, IncomingVal);
1761 assert(Val && "Value is nullptr?");
1765 Val = RemappedIt->second;
1767 }
1768 return NewPN;
1769}
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780static void
1784 bool FirstFunction = false) {
1786 assert(Region.ExtractedFunction && "Region has no extracted function?");
1787
1788 Function *DominatingFunction = Region.ExtractedFunction;
1789 if (FirstFunction)
1793
1794 for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size();
1795 ArgIdx++) {
1797 "No mapping from extracted to outlined?");
1798 unsigned AggArgIdx = Region.ExtractedArgToAgg.find(ArgIdx)->second;
1800 Argument *Arg = Region.ExtractedFunction->getArg(ArgIdx);
1801
1802
1803 if (ArgIdx < Region.NumExtractedInputs) {
1804 LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function "
1805 << *Region.ExtractedFunction << " with " << *AggArg
1808 Value *V = Region.Call->getArgOperand(ArgIdx);
1809 Region.RemappedArguments.insert(std::make_pair(V, AggArg));
1810 continue;
1811 }
1812
1813
1814
1815
1816 assert(Arg->hasOneUse() && "Output argument can only have one use");
1818 assert(InstAsUser && "User is nullptr!");
1819
1824 bool EdgeAdded = false;
1825 if (Descendants.size() == 0) {
1826 EdgeAdded = true;
1829 }
1830
1831
1832
1833
1834 for (BasicBlock *DescendBB : Descendants) {
1836 if (!RI)
1837 continue;
1839 auto VBBIt = OutputBBs.find(RetVal);
1840 assert(VBBIt != OutputBBs.end() && "Could not find output value!");
1841
1842
1843
1845
1846 Value *ValueOperand = SI->getValueOperand();
1847
1850 BasicBlock *OutputBB = VBBIt->second;
1852 LLVM_DEBUG(dbgs() << "Move store for instruction " << *I << " to "
1853 << *OutputBB << "\n");
1854
1855
1856
1858 Region.Candidate->getGVN(ValueOperand).has_value()) {
1859 if (FirstFunction)
1860 continue;
1861 Value *CorrVal =
1862 Region.findCorrespondingValueIn(*Group.Regions[0], ValueOperand);
1863 assert(CorrVal && "Value is nullptr?");
1865 continue;
1866 }
1868
1869
1870 if (Region.Candidate->getGVN(PN))
1871 continue;
1872
1873
1874
1875 Region.PHIBlocks.insert(std::make_pair(RetVal, PN->getParent()));
1876
1877
1878
1879
1880 if (FirstFunction) {
1882 Group.PHIBlocks.insert(std::make_pair(RetVal, PHIBlock));
1883 continue;
1884 }
1885
1886
1887
1889
1890
1891
1892
1894 OutputMappings, UsedPHIs);
1896 }
1897
1898
1899
1900 if (EdgeAdded)
1902 I->eraseFromParent();
1903
1904 LLVM_DEBUG(dbgs() << "Replacing uses of output " << *Arg << " in function "
1905 << *Region.ExtractedFunction << " with " << *AggArg
1908 }
1909}
1910
1911
1912
1913
1914
1919
1920
1921 for (std::pair<unsigned, Constant *> &Const : Region.AggArgToConstant) {
1922 unsigned AggArgIdx = Const.first;
1923 assert(OutlinedFunction && "Overall Function is not defined?");
1924 Constant *CST = Const.second;
1926
1927
1928 VMap[CST] = Arg;
1929 LLVM_DEBUG(dbgs() << "Replacing uses of constant " << *CST
1930 << " in function " << *OutlinedFunction << " with "
1931 << *Arg << '\n');
1932 }
1933
1936}
1937
1938
1939
1940
1941
1942
1943
1947
1948 bool Mismatch = false;
1949 unsigned MatchingNum = 0;
1950
1951
1952
1954 Mismatch = false;
1955 for (std::pair<Value *, BasicBlock *> &VToB : CompBBs) {
1957 OutputBBs.find(VToB.first);
1958 if (OutputBBIt == OutputBBs.end()) {
1959 Mismatch = true;
1960 break;
1961 }
1962
1964 BasicBlock *OutputBB = OutputBBIt->second;
1965 if (CompBB->size() - 1 != OutputBB->size()) {
1966 Mismatch = true;
1967 break;
1968 }
1969
1973 continue;
1974
1975 if (.isIdenticalTo(&(*NIt))) {
1976 Mismatch = true;
1977 break;
1978 }
1979
1980 NIt++;
1981 }
1982 }
1983
1984 if (!Mismatch)
1985 return MatchingNum;
1986
1987 MatchingNum++;
1988 }
1989
1990 return std::nullopt;
1991}
1992
1993
1994
1995
1996
1997
1998static bool
2001 bool AllRemoved = true;
2002 Value *RetValueForBB;
2005
2006 for (std::pair<Value *, BasicBlock *> &VtoBB : BlocksToPrune) {
2007 RetValueForBB = VtoBB.first;
2008 NewBB = VtoBB.second;
2009
2010
2011
2012 if (NewBB->size() == 0) {
2014 ToRemove.push_back(RetValueForBB);
2015 continue;
2016 }
2017
2018
2019
2020 AllRemoved = false;
2021 }
2022
2023
2025 BlocksToPrune.erase(V);
2026
2027
2028 if (AllRemoved)
2029 Region.OutputBlockNum = -1;
2030
2031 return AllRemoved;
2032}
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2052
2053
2054
2056 return;
2057
2058
2059 std::optional MatchingBB =
2061
2062
2063
2064 if (MatchingBB) {
2065 LLVM_DEBUG(dbgs() << "Set output block for region in function"
2066 << Region.ExtractedFunction << " to " << *MatchingBB);
2067
2068 Region.OutputBlockNum = *MatchingBB;
2069 for (std::pair<Value *, BasicBlock *> &VtoBB : OutputBBs)
2070 VtoBB.second->eraseFromParent();
2071 return;
2072 }
2073
2074 Region.OutputBlockNum = OutputStoreBBs.size();
2075
2076 Value *RetValueForBB;
2079 for (std::pair<Value *, BasicBlock *> &VtoBB : OutputBBs) {
2080 RetValueForBB = VtoBB.first;
2081 NewBB = VtoBB.second;
2083 EndBBs.find(RetValueForBB);
2084 LLVM_DEBUG(dbgs() << "Create output block for region in"
2085 << Region.ExtractedFunction << " to "
2086 << *NewBB);
2088 OutputStoreBBs.back().insert(std::make_pair(RetValueForBB, NewBB));
2089 }
2090}
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2104 unsigned Idx = 0;
2105 std::vector<Value *> SortedKeys;
2106
2108
2109 for (Value *RetVal : SortedKeys) {
2112 ParentFunc);
2113 NewMap.insert(std::make_pair(RetVal, NewBB));
2114 }
2115}
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2129
2130
2131
2132
2133
2134
2135
2138
2141
2142 for (std::pair<Value *, BasicBlock *> &RetBlockPair : ReturnBBs) {
2143 std::pair<Value *, BasicBlock *> &OutputBlock =
2144 *OG.EndBBs.find(RetBlockPair.first);
2145 BasicBlock *ReturnBlock = RetBlockPair.second;
2146 BasicBlock *EndBB = OutputBlock.second;
2148
2149
2150 Term->moveBefore(*ReturnBlock, ReturnBlock->end());
2151
2152
2153 LLVM_DEBUG(dbgs() << "Create switch statement in " << *AggFunc << " for "
2154 << OutputStoreBBs.size() << "\n");
2157 ReturnBlock, OutputStoreBBs.size(), EndBB);
2158
2159 unsigned Idx = 0;
2162 OutputStoreBB.find(OutputBlock.first);
2163
2164 if (OSBBIt == OutputStoreBB.end())
2165 continue;
2166
2169 ConstantInt::get(Type::getInt32Ty(M.getContext()), Idx), BB);
2171 Term->setSuccessor(0, ReturnBlock);
2172 Idx++;
2173 }
2174 }
2175 return;
2176 }
2177
2178 assert(OutputStoreBBs.size() < 2 && "Different store sets not handled!");
2179
2180
2181
2182
2183
2184
2185
2186 if (OutputStoreBBs.size() == 1) {
2187 LLVM_DEBUG(dbgs() << "Move store instructions to the end block in "
2190 for (std::pair<Value *, BasicBlock *> &VBPair : OutputBlocks) {
2192 EndBBs.find(VBPair.first);
2193 assert(EndBBIt != EndBBs.end() && "Could not find end block");
2194 BasicBlock *EndBB = EndBBIt->second;
2195 BasicBlock *OutputBB = VBPair.second;
2197 Term->eraseFromParent();
2200 Term->moveBefore(*EndBB, EndBB->end());
2202 }
2203 }
2204}
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2222 std::vector<Function *> &FuncsToRemove,
2225
2226
2232
2233
2236
2237
2242
2245
2246
2247
2248
2251 for (std::pair<Value *, BasicBlock *> &VToBB : NewBBs) {
2253 CurrentGroup.EndBBs.find(VToBB.first);
2256 OutputStoreBBs.back().insert(VToBB);
2257 }
2258 }
2259
2260
2262
2263
2264
2266}
2267
2268void IROutliner::deduplicateExtractedSections(
2269 Module &M, OutlinableGroup &CurrentGroup,
2270 std::vector<Function *> &FuncsToRemove, unsigned &OutlinedFunctionNum) {
2271 createFunction(M, CurrentGroup, OutlinedFunctionNum);
2272
2273 std::vector<DenseMap<Value *, BasicBlock *>> OutputStoreBBs;
2274
2275 OutlinableRegion *CurrentOS;
2276
2278 OutputMappings);
2279
2280 for (unsigned Idx = 1; Idx < CurrentGroup.Regions.size(); Idx++) {
2281 CurrentOS = CurrentGroup.Regions[Idx];
2282 AttributeFuncs::mergeAttributesForOutlining(*CurrentGroup.OutlinedFunction,
2284
2285
2286
2287 DenseMap<Value *, BasicBlock *> NewBBs;
2290 "output_block_" + Twine(Idx));
2293 CurrentGroup.EndBBs, OutputMappings,
2294 OutputStoreBBs);
2295
2298 }
2299
2300
2302
2303 OutlinedFunctionNum++;
2304}
2305
2306
2307
2308
2309
2310
2311
2313
2314
2315
2316
2317
2318
2319
2320 IRInstructionDataList::iterator NextIDIt = std::next(ID.getIterator());
2321 Instruction *NextIDLInst = NextIDIt->Inst;
2323 if (.Inst->isTerminator())
2324 NextModuleInst = ID.Inst->getNextNode();
2325 else if (NextIDLInst != nullptr)
2326 NextModuleInst =
2327 &*NextIDIt->Inst->getParent()->instructionsWithoutDebug().begin();
2328
2329 if (NextIDLInst && NextIDLInst != NextModuleInst)
2330 return false;
2331
2332 return true;
2333}
2334
2335bool IROutliner::isCompatibleWithAlreadyOutlinedCode(
2337 IRSimilarityCandidate *IRSC = Region.Candidate;
2338 unsigned StartIdx = IRSC->getStartIdx();
2339 unsigned EndIdx = IRSC->getEndIdx();
2340
2341
2342
2343 for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)
2344 if (Outlined.contains(Idx))
2345 return false;
2346
2347
2348
2349 if (.Candidate->backInstruction()->isTerminator()) {
2351 Region.Candidate->backInstruction()->getNextNode();
2352 assert(NewEndInst && "Next instruction is a nullptr?");
2353 if (Region.Candidate->end()->Inst != NewEndInst) {
2354 IRInstructionDataList *IDL = Region.Candidate->front()->IDL;
2355 IRInstructionData *NewEndIRID = new (InstDataAllocator.Allocate())
2356 IRInstructionData(*NewEndInst,
2357 InstructionClassifier.visit(*NewEndInst), *IDL);
2358
2359
2360
2361 IDL->insert(Region.Candidate->end(), *NewEndIRID);
2362 }
2363 }
2364
2365 return none_of(*IRSC, [this](IRInstructionData &ID) {
2367 return true;
2368
2369 return !this->InstructionClassifier.visit(ID.Inst);
2370 });
2371}
2372
2373void IROutliner::pruneIncompatibleRegions(
2374 std::vector &CandidateVec,
2375 OutlinableGroup &CurrentGroup) {
2376 bool PreviouslyOutlined;
2377
2378
2379 stable_sort(CandidateVec, [](const IRSimilarityCandidate &LHS,
2380 const IRSimilarityCandidate &RHS) {
2381 return LHS.getStartIdx() < RHS.getStartIdx();
2382 });
2383
2384 IRSimilarityCandidate &FirstCandidate = CandidateVec[0];
2385
2386
2387 if (FirstCandidate.getLength() == 2) {
2388 if (isa(FirstCandidate.front()->Inst) &&
2390 return;
2391 }
2392
2393 unsigned CurrentEndIdx = 0;
2394 for (IRSimilarityCandidate &IRSC : CandidateVec) {
2395 PreviouslyOutlined = false;
2397 unsigned EndIdx = IRSC.getEndIdx();
2399
2400 for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)
2401 if (Outlined.contains(Idx)) {
2402 PreviouslyOutlined = true;
2403 break;
2404 }
2405
2406 if (PreviouslyOutlined)
2407 continue;
2408
2409
2410
2411 bool BBHasAddressTaken = any_of(IRSC, [](IRInstructionData &ID){
2412 return ID.Inst->getParent()->hasAddressTaken();
2413 });
2414
2415 if (BBHasAddressTaken)
2416 continue;
2417
2419 continue;
2420
2423 dbgs() << "... Skipping function with nooutline attribute: "
2424 << FnForCurrCand.getName() << "\n";
2425 });
2426 continue;
2427 }
2428
2430 !OutlineFromLinkODRs)
2431 continue;
2432
2433
2434
2435 if (CurrentEndIdx != 0 && StartIdx <= CurrentEndIdx)
2436 continue;
2437
2438 bool BadInst = any_of(IRSC, [this](IRInstructionData &ID) {
2440 return true;
2441
2442 return !this->InstructionClassifier.visit(ID.Inst);
2443 });
2444
2445 if (BadInst)
2446 continue;
2447
2448 OutlinableRegion *OS = new (RegionAllocator.Allocate())
2449 OutlinableRegion(IRSC, CurrentGroup);
2450 CurrentGroup.Regions.push_back(OS);
2451
2452 CurrentEndIdx = EndIdx;
2453 }
2454}
2455
2457IROutliner::findBenefitFromAllRegions(OutlinableGroup &CurrentGroup) {
2459 for (OutlinableRegion *Region : CurrentGroup.Regions) {
2460 TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());
2461
2462
2463 RegionBenefit += Region->getBenefit(TTI);
2465 << " saved instructions to overfall benefit.\n");
2466 }
2467
2468 return RegionBenefit;
2469}
2470
2471
2472
2473
2474
2475
2476
2477
2478
2480 unsigned OutputCanon) {
2482
2483
2484
2488 "Could not find GVN set for PHINode number!");
2489 assert(It->second.second.size() > 0 && "PHINode does not have any values!");
2490 OutputCanon = *It->second.second.begin();
2491 }
2492 std::optional OGVN =
2493 Region.Candidate->fromCanonicalNum(OutputCanon);
2494 assert(OGVN && "Could not find GVN for Canonical Number?");
2495 std::optional<Value *> OV = Region.Candidate->fromGVN(*OGVN);
2496 assert(OV && "Could not find value for GVN?");
2497 return *OV;
2498}
2499
2501IROutliner::findCostOutputReloads(OutlinableGroup &CurrentGroup) {
2503 for (OutlinableRegion *Region : CurrentGroup.Regions) {
2504 TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());
2505
2506
2507 for (unsigned OutputCanon : Region->GVNStores) {
2512
2514 << " instructions to cost for output of type "
2515 << *V->getType() << "\n");
2516 OverallCost += LoadCost;
2517 }
2518 }
2519
2520 return OverallCost;
2521}
2522
2523
2524
2525
2526
2527
2528
2529
2530
2535 unsigned NumOutputBranches = 0;
2536
2541
2542
2543
2547 continue;
2548
2549 for (Value *V : ID.OperVals) {
2551 if (!CandidateBlocks.contains(BB) && FoundBlocks.insert(BB).second)
2552 NumOutputBranches++;
2553 }
2554 }
2555
2557
2560 for (unsigned OutputCanon : OutputUse) {
2563 TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0,
2565
2566
2567
2568
2570 << " instructions to cost for output of type "
2571 << *V->getType() << "\n");
2572 OutputCost += StoreCost * NumOutputBranches;
2573 }
2574
2577 LLVM_DEBUG(dbgs() << "Adding " << BranchCost << " to the current cost for"
2578 << " a branch instruction\n");
2579 OutputCost += BranchCost * NumOutputBranches;
2580 }
2581
2582
2583
2591
2593 InstructionCost TotalCost = ComparisonCost * BranchCost * DifferentBlocks;
2594
2596 << " instructions for each switch case for each different"
2597 << " output path in a function\n");
2598 OutputCost += TotalCost * NumOutputBranches;
2599 }
2600
2601 return OutputCost;
2602}
2603
2604void IROutliner::findCostBenefit(Module &M, OutlinableGroup &CurrentGroup) {
2605 InstructionCost RegionBenefit = findBenefitFromAllRegions(CurrentGroup);
2606 CurrentGroup.Benefit += RegionBenefit;
2608
2609 InstructionCost OutputReloadCost = findCostOutputReloads(CurrentGroup);
2610 CurrentGroup.Cost += OutputReloadCost;
2611 LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
2612
2614 RegionBenefit / CurrentGroup.Regions.size();
2615 unsigned OverallArgumentNum = CurrentGroup.ArgumentTypes.size();
2616 unsigned NumRegions = CurrentGroup.Regions.size();
2617 TargetTransformInfo &TTI =
2618 getTTI(*CurrentGroup.Regions[0]->Candidate->getFunction());
2619
2620
2621
2622 LLVM_DEBUG(dbgs() << "Adding: " << AverageRegionBenefit
2623 << " instructions to cost for body of new function.\n");
2624 CurrentGroup.Cost += AverageRegionBenefit;
2625 LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
2626
2627
2628
2629 LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum
2630 << " instructions to cost for each argument in the new"
2631 << " function.\n");
2632 CurrentGroup.Cost +=
2634 LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
2635
2636
2637
2638
2639 LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum
2640 << " instructions to cost for each argument in the new"
2641 << " function " << NumRegions << " times for the "
2642 << "needed argument handling at the call site.\n");
2643 CurrentGroup.Cost +=
2645 LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
2646
2648 LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
2649}
2650
2654
2656 std::optional OutputIdx;
2657
2658 for (unsigned ArgIdx = Region.NumExtractedInputs;
2659 ArgIdx < Region.Call->arg_size(); ArgIdx++) {
2660 if (Operand == Region.Call->getArgOperand(ArgIdx)) {
2661 OutputIdx = ArgIdx - Region.NumExtractedInputs;
2662 break;
2663 }
2664 }
2665
2666
2667
2668 if (!OutputIdx)
2669 return;
2670
2671 auto It = OutputMappings.find(Outputs[*OutputIdx]);
2672 if (It == OutputMappings.end()) {
2673 LLVM_DEBUG(dbgs() << "Mapping extracted output " << *LI << " to "
2674 << *Outputs[*OutputIdx] << "\n");
2675 OutputMappings.insert(std::make_pair(LI, Outputs[*OutputIdx]));
2676 } else {
2677 Value *Orig = It->second;
2678 LLVM_DEBUG(dbgs() << "Mapping extracted output " << *Orig << " to "
2679 << *Outputs[*OutputIdx] << "\n");
2680 OutputMappings.insert(std::make_pair(LI, Orig));
2681 }
2682}
2683
2685 SetVector<Value *> ArgInputs, Outputs;
2686 assert(Region.StartBB && "StartBB for the OutlinableRegion is nullptr!");
2689 CodeExtractorAnalysisCache CEAC(*OrigF);
2690 Region.ExtractedFunction =
2691 Region.CE->extractCodeRegion(CEAC, ArgInputs, Outputs);
2692
2693
2694
2695 if (.ExtractedFunction) {
2697 << "\n");
2698 Region.reattachCandidate();
2699 return false;
2700 }
2701
2702
2703
2704
2705
2706 User *InstAsUser = Region.ExtractedFunction->user_back();
2709 assert(Region.PrevBB && "PrevBB is nullptr?");
2710 if (Region.PrevBB == InitialStart) {
2715 Region.PrevBB = NewPrev;
2717 }
2718
2719 Region.StartBB = RewrittenBB;
2720 Region.EndBB = RewrittenBB;
2721
2722
2723
2724
2725
2726
2727 IRInstructionDataList *IDL = Region.Candidate->front()->IDL;
2730 Region.NewFront = new (InstDataAllocator.Allocate()) IRInstructionData(
2731 *BeginRewritten, InstructionClassifier.visit(*BeginRewritten), *IDL);
2732 Region.NewBack = new (InstDataAllocator.Allocate()) IRInstructionData(
2733 *EndRewritten, InstructionClassifier.visit(*EndRewritten), *IDL);
2734
2735
2736
2738
2739
2741
2742 IDL->erase(Region.Candidate->begin(), std::prev(Region.Candidate->end()));
2743
2744 assert(RewrittenBB != nullptr &&
2745 "Could not find a predecessor after extraction!");
2746
2747
2748
2749 for (Instruction &I : *RewrittenBB)
2751 if (Region.ExtractedFunction == CI->getCalledFunction())
2754 updateOutputMapping(Region, Outputs.getArrayRef(), LI);
2755 Region.reattachCandidate();
2756 return true;
2757}
2758
2759unsigned IROutliner::doOutline(Module &M) {
2760
2761 InstructionClassifier.EnableBranches = ;
2764
2765 IRSimilarityIdentifier &Identifier = getIRSI(M);
2767
2768
2769 unsigned OutlinedFunctionNum = 0;
2770
2771
2772 if (SimilarityCandidates.size() > 1)
2774 [](const std::vector &LHS,
2775 const std::vector &RHS) {
2776 return LHS[0].getLength() * LHS.size() >
2777 RHS[0].getLength() * RHS.size();
2778 });
2779
2780
2781 std::vector PotentialGroups(SimilarityCandidates.size());
2782
2783 DenseSet NotSame;
2784 std::vector<OutlinableGroup *> NegativeCostGroups;
2785 std::vector<OutlinableRegion *> OutlinedRegions;
2786
2787 unsigned PotentialGroupIdx = 0;
2788 for (SimilarityGroup &CandidateVec : SimilarityCandidates) {
2789 OutlinableGroup &CurrentGroup = PotentialGroups[PotentialGroupIdx++];
2790
2791
2792 pruneIncompatibleRegions(CandidateVec, CurrentGroup);
2793
2794
2795
2796
2797 if (CurrentGroup.Regions.size() < 2)
2798 continue;
2799
2800
2801
2802 NotSame.clear();
2804
2806 continue;
2807
2808
2809
2810
2811 OutlinedRegions.clear();
2812 for (OutlinableRegion *OS : CurrentGroup.Regions) {
2813
2814
2816
2817
2818
2819
2821 continue;
2822
2824 DenseSet<BasicBlock *> BlocksInRegion;
2826 OS->CE = new (ExtractorAllocator.Allocate())
2827 CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
2828 false, nullptr, "outlined");
2829 findAddInputsOutputs(M, *OS, NotSame);
2831 OutlinedRegions.push_back(OS);
2832
2833
2834
2836 }
2837
2838 CurrentGroup.Regions = std::move(OutlinedRegions);
2839
2840 if (CurrentGroup.Regions.empty())
2841 continue;
2842
2844
2845 if (CostModel)
2846 findCostBenefit(M, CurrentGroup);
2847
2848
2849
2850 if (CurrentGroup.Cost >= CurrentGroup.Benefit && CostModel) {
2851 OptimizationRemarkEmitter &ORE =
2852 getORE(*CurrentGroup.Regions[0]->Candidate->getFunction());
2853 ORE.emit([&]() {
2854 IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate;
2855 OptimizationRemarkMissed R(DEBUG_TYPE, "WouldNotDecreaseSize",
2856 C->frontInstruction());
2857 R << "did not outline "
2858 << ore::NV(std::to_string(CurrentGroup.Regions.size()))
2859 << " regions due to estimated increase of "
2860 << ore::NV("InstructionIncrease",
2861 CurrentGroup.Cost - CurrentGroup.Benefit)
2862 << " instructions at locations ";
2864 CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(),
2865 [&R](OutlinableRegion *Region) {
2866 R << ore::NV(
2867 "DebugLoc",
2868 Region->Candidate->frontInstruction()->getDebugLoc());
2869 },
2870 [&R]() { R << " "; });
2871 return R;
2872 });
2873 continue;
2874 }
2875
2876 NegativeCostGroups.push_back(&CurrentGroup);
2877 }
2878
2879 ExtractorAllocator.DestroyAll();
2880
2881 if (NegativeCostGroups.size() > 1)
2883 [](const OutlinableGroup *LHS, const OutlinableGroup *RHS) {
2884 return LHS->Benefit - LHS->Cost > RHS->Benefit - RHS->Cost;
2885 });
2886
2887 std::vector<Function *> FuncsToRemove;
2888 for (OutlinableGroup *CG : NegativeCostGroups) {
2889 OutlinableGroup &CurrentGroup = *CG;
2890
2891 OutlinedRegions.clear();
2892 for (OutlinableRegion *Region : CurrentGroup.Regions) {
2893
2894
2895 if (!isCompatibleWithAlreadyOutlinedCode(*Region))
2896 continue;
2897 OutlinedRegions.push_back(Region);
2898 }
2899
2900 if (OutlinedRegions.size() < 2)
2901 continue;
2902
2903
2904
2905 CurrentGroup.Regions = std::move(OutlinedRegions);
2906 if (CostModel) {
2907 CurrentGroup.Benefit = 0;
2908 CurrentGroup.Cost = 0;
2909 findCostBenefit(M, CurrentGroup);
2910 if (CurrentGroup.Cost >= CurrentGroup.Benefit)
2911 continue;
2912 }
2913 OutlinedRegions.clear();
2914 for (OutlinableRegion *Region : CurrentGroup.Regions) {
2915 Region->splitCandidate();
2916 if (->CandidateSplit)
2917 continue;
2918 OutlinedRegions.push_back(Region);
2919 }
2920
2921 CurrentGroup.Regions = std::move(OutlinedRegions);
2922 if (CurrentGroup.Regions.size() < 2) {
2923 for (OutlinableRegion *R : CurrentGroup.Regions)
2924 R->reattachCandidate();
2925 continue;
2926 }
2927
2928 LLVM_DEBUG(dbgs() << "Outlining regions with cost " << CurrentGroup.Cost
2929 << " and benefit " << CurrentGroup.Benefit << "\n");
2930
2931
2932 OutlinedRegions.clear();
2933 for (OutlinableRegion *OS : CurrentGroup.Regions) {
2935 DenseSet<BasicBlock *> BlocksInRegion;
2937 OS->CE = new (ExtractorAllocator.Allocate())
2938 CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,
2939 false, nullptr, "outlined");
2940 bool FunctionOutlined = extractSection(*OS);
2941 if (FunctionOutlined) {
2944 for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)
2945 Outlined.insert(Idx);
2946
2947 OutlinedRegions.push_back(OS);
2948 }
2949 }
2950
2951 LLVM_DEBUG(dbgs() << "Outlined " << OutlinedRegions.size()
2952 << " with benefit " << CurrentGroup.Benefit
2953 << " and cost " << CurrentGroup.Cost << "\n");
2954
2955 CurrentGroup.Regions = std::move(OutlinedRegions);
2956
2957 if (CurrentGroup.Regions.empty())
2958 continue;
2959
2960 OptimizationRemarkEmitter &ORE =
2961 getORE(*CurrentGroup.Regions[0]->Call->getFunction());
2962 ORE.emit([&]() {
2963 IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate;
2964 OptimizationRemark R(DEBUG_TYPE, "Outlined", C->front()->Inst);
2965 R << "outlined " << ore::NV(std::to_string(CurrentGroup.Regions.size()))
2966 << " regions with decrease of "
2968 << " instructions at locations ";
2970 CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(),
2971 [&R](OutlinableRegion *Region) {
2972 R << ore::NV("DebugLoc",
2973 Region->Candidate->frontInstruction()->getDebugLoc());
2974 },
2975 [&R]() { R << " "; });
2976 return R;
2977 });
2978
2979 deduplicateExtractedSections(M, CurrentGroup, FuncsToRemove,
2980 OutlinedFunctionNum);
2981 }
2982
2983 for (Function *F : FuncsToRemove)
2984 F->eraseFromParent();
2985
2986 return OutlinedFunctionNum;
2987}
2988
2992
2993 return doOutline(M) > 0;
2994}
2995
2998
3002 };
3003
3007 };
3008
3009 std::unique_ptr ORE;
3013 return *ORE;
3014 };
3015
3019}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::pair< ArgLocWithBBCanon, CanonList > PHINodeData
Definition IROutliner.cpp:1130
static void remapExtractedInputs(const ArrayRef< Value * > ArgInputs, const DenseMap< Value *, Value * > &OutputMappings, SetVector< Value * > &RemappedArgInputs)
Find the original value for the ArgInput values if any one of them was replaced during a previous ext...
Definition IROutliner.cpp:815
static std::optional< unsigned > getGVNForPHINode(OutlinableRegion &Region, PHINode *PN, DenseSet< BasicBlock * > &Blocks, unsigned AggArgIdx)
Create a special GVN for PHINodes that will be used outside of the region.
Definition IROutliner.cpp:1158
static Value * getPassedArgumentAndAdjustArgumentLocation(const Argument *A, const OutlinableRegion &Region)
For the function call now representing the Region, find the passed value to that call that represents...
Definition IROutliner.cpp:1589
static void findCanonNumsForPHI(PHINode *PN, OutlinableRegion &Region, const DenseMap< Value *, Value * > &OutputMappings, SmallVector< std::pair< unsigned, BasicBlock * > > &CanonNums, bool ReplacedWithOutlinedCall=true)
Find the canonical numbering for the incoming Values into the PHINode PN.
Definition IROutliner.cpp:1615
static cl::opt< bool > NoCostModel("ir-outlining-no-cost", cl::init(false), cl::ReallyHidden, cl::desc("Debug option to outline greedily, without restriction that " "calculated benefit outweighs cost"))
static void moveBBContents(BasicBlock &SourceBB, BasicBlock &TargetBB)
Move the contents of SourceBB to before the last instruction of TargetBB.
Definition IROutliner.cpp:157
static bool nextIRInstructionDataMatchesNextInst(IRInstructionData &ID)
Checks that the next instruction in the InstructionDataList matches the next instruction in the modul...
Definition IROutliner.cpp:2312
static void moveFunctionData(Function &Old, Function &New, DenseMap< Value *, BasicBlock * > &NewEnds)
Move each BasicBlock in Old to New.
Definition IROutliner.cpp:703
static cl::opt< bool > EnableLinkOnceODRIROutlining("enable-linkonceodr-ir-outlining", cl::Hidden, cl::desc("Enable the IR outliner on linkonceodr functions"), cl::init(false))
static void getCodeExtractorArguments(OutlinableRegion &Region, std::vector< unsigned > &InputGVNs, DenseSet< unsigned > &NotSame, DenseMap< Value *, Value * > &OutputMappings, SetVector< Value * > &ArgInputs, SetVector< Value * > &Outputs)
Find the input GVNs and the output values for a region of Instructions.
Definition IROutliner.cpp:846
static void fillOverallFunction(Module &M, OutlinableGroup &CurrentGroup, std::vector< DenseMap< Value *, BasicBlock * > > &OutputStoreBBs, std::vector< Function * > &FuncsToRemove, const DenseMap< Value *, Value * > &OutputMappings)
Fill the new function that will serve as the replacement function for all of the extracted regions of...
Definition IROutliner.cpp:2219
static void findExtractedOutputToOverallOutputMapping(Module &M, OutlinableRegion &Region, SetVector< Value * > &Outputs)
Create a mapping of the output arguments for the Region to the output arguments of the overall outlin...
Definition IROutliner.cpp:1260
static void alignOutputBlockWithAggFunc(OutlinableGroup &OG, OutlinableRegion &Region, DenseMap< Value *, BasicBlock * > &OutputBBs, DenseMap< Value *, BasicBlock * > &EndBBs, const DenseMap< Value *, Value * > &OutputMappings, std::vector< DenseMap< Value *, BasicBlock * > > &OutputStoreBBs)
For the outlined section, move needed the StoreInsts for the output registers into their own block.
Definition IROutliner.cpp:2046
static bool collectRegionsConstants(OutlinableRegion &Region, DenseMap< unsigned, Constant * > &GVNToConstant, DenseSet< unsigned > &NotSame)
Find whether Region matches the global value numbering to Constant mapping found so far.
Definition IROutliner.cpp:549
static PHINode * findOrCreatePHIInBlock(PHINode &PN, OutlinableRegion &Region, BasicBlock *OverallPhiBlock, const DenseMap< Value *, Value * > &OutputMappings, DenseSet< PHINode * > &UsedPHIs)
Find, or add PHINode PN to the combined PHINode Block OverallPHIBlock in order to condense the number...
Definition IROutliner.cpp:1659
static bool analyzeAndPruneOutputBlocks(DenseMap< Value *, BasicBlock * > &BlocksToPrune, OutlinableRegion &Region)
Remove empty output blocks from the outlined region.
Definition IROutliner.cpp:1999
static hash_code encodePHINodeData(PHINodeData &PND)
Encode PND as an integer for easy lookup based on the argument location, the parent BasicBlock canoni...
Definition IROutliner.cpp:1138
SmallVector< unsigned, 2 > CanonList
Definition IROutliner.cpp:1127
CallInst * replaceCalledFunction(Module &M, OutlinableRegion &Region)
Replace the extracted function in the Region with a call to the overall function constructed from the...
Definition IROutliner.cpp:1413
static void createAndInsertBasicBlocks(DenseMap< Value *, BasicBlock * > &OldMap, DenseMap< Value *, BasicBlock * > &NewMap, Function *ParentFunc, Twine BaseName)
Takes in a mapping, OldMap of ConstantValues to BasicBlocks, sorts keys, before creating a basic bloc...
Definition IROutliner.cpp:2101
static bool outputHasNonPHI(Value *V, unsigned PHILoc, PHINode &PN, SmallPtrSet< BasicBlock *, 1 > &Exits, DenseSet< BasicBlock * > &BlocksInRegion)
Check if the V has any uses outside of the region other than PN.
Definition IROutliner.cpp:1019
static void analyzeExitPHIsForOutputUses(BasicBlock *CurrentExitFromRegion, SmallPtrSet< BasicBlock *, 1 > &PotentialExitsFromRegion, DenseSet< BasicBlock * > &RegionBlocks, SetVector< Value * > &Outputs, DenseSet< Value * > &OutputsReplacedByPHINode, DenseSet< Value * > &OutputsWithNonPhiUses)
Test whether CurrentExitFromRegion contains any PhiNodes that should be considered outputs.
Definition IROutliner.cpp:1076
static void getSortedConstantKeys(std::vector< Value * > &SortedKeys, DenseMap< Value *, BasicBlock * > &Map)
A function to sort the keys of Map, which must be a mapping of constant values to basic blocks and re...
Definition IROutliner.cpp:166
static InstructionCost findCostForOutputBlocks(Module &M, OutlinableGroup &CurrentGroup, TargetTransformInfo &TTI)
Find the extra instructions needed to handle any output values for the region.
Definition IROutliner.cpp:2531
static void replaceTargetsFromPHINode(BasicBlock *PHIBlock, BasicBlock *Find, BasicBlock *Replace, DenseSet< BasicBlock * > &Included)
Rewrite the BranchInsts in the incoming blocks to PHIBlock that are found in Included to branch to Ba...
Definition IROutliner.cpp:221
static void findExtractedInputToOverallInputMapping(OutlinableRegion &Region, std::vector< unsigned > &InputGVNs, SetVector< Value * > &ArgInputs)
Look over the inputs and map each input argument to an argument in the overall function for the Outli...
Definition IROutliner.cpp:917
static void mapInputsToGVNs(IRSimilarityCandidate &C, SetVector< Value * > &CurrentInputs, const DenseMap< Value *, Value * > &OutputMappings, std::vector< unsigned > &EndInputNumbers)
Find the GVN for the inputs that have been found by the CodeExtractor.
Definition IROutliner.cpp:789
static void replaceArgumentUses(OutlinableRegion &Region, DenseMap< Value *, BasicBlock * > &OutputBBs, const DenseMap< Value *, Value * > &OutputMappings, bool FirstFunction=false)
Definition IROutliner.cpp:1781
static DISubprogram * getSubprogramOrNull(OutlinableGroup &Group)
Get the subprogram if it exists for one of the outlined regions.
Definition IROutliner.cpp:620
static Value * findOutputMapping(const DenseMap< Value *, Value * > OutputMappings, Value *Input)
Check the OutputMappings structure for value Input, if it exists it has been used as an output for ou...
Definition IROutliner.cpp:530
static Value * findOutputValueInRegion(OutlinableRegion &Region, unsigned OutputCanon)
For the OutputCanon number passed in find the value represented by this canonical number.
Definition IROutliner.cpp:2479
static std::optional< bool > constantMatches(Value *V, unsigned GVN, DenseMap< unsigned, Constant * > &GVNToConstant)
Find whether V matches the Constants previously found for the GVN.
Definition IROutliner.cpp:463
static void findConstants(IRSimilarityCandidate &C, DenseSet< unsigned > &NotSame, std::vector< unsigned > &Inputs)
Find the constants that will need to be lifted into arguments as they are not the same in each instan...
Definition IROutliner.cpp:761
void replaceConstants(OutlinableRegion &Region)
Within an extracted function, replace the constants that need to be lifted into arguments with the ac...
Definition IROutliner.cpp:1915
std::pair< unsigned, unsigned > ArgLocWithBBCanon
Definition IROutliner.cpp:1125
static Value * getPassedArgumentInAlreadyOutlinedFunction(const Argument *A, const OutlinableRegion &Region)
For the function call now representing the Region, find the passed value to that call that represents...
Definition IROutliner.cpp:1573
void createSwitchStatement(Module &M, OutlinableGroup &OG, DenseMap< Value *, BasicBlock * > &EndBBs, std::vector< DenseMap< Value *, BasicBlock * > > &OutputStoreBBs)
Create the switch statement for outlined function to differentiate between all the output blocks.
Definition IROutliner.cpp:2126
static BasicBlock * findOrCreatePHIBlock(OutlinableGroup &Group, Value *RetVal)
Find or create a BasicBlock in the outlined function containing PhiBlocks for RetVal.
Definition IROutliner.cpp:1525
std::optional< unsigned > findDuplicateOutputBlock(DenseMap< Value *, BasicBlock * > &OutputBBs, std::vector< DenseMap< Value *, BasicBlock * > > &OutputStoreBBs)
It is possible that there is a basic block that already performs the same stores.
Definition IROutliner.cpp:1944
This header defines various interfaces for pass management in LLVM.
static const T * Find(StringRef S, ArrayRef< T > A)
Find KV in array using binary search.
FunctionAnalysisManager FAM
This pass exposes codegen information to IR-level passes.
The Input class is used to parse a yaml document into in-memory structs and vectors.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Functions, function parameters, and return types can have attributes to indicate how they should be t...
LLVM Basic Block Representation.
LLVM_ABI void replaceSuccessorsPhiUsesWith(BasicBlock *Old, BasicBlock *New)
Update all phi nodes in this basic block's successors to refer to basic block New instead of basic bl...
iterator begin()
Instruction iterator methods.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI InstListType::const_iterator getFirstNonPHIOrDbg(bool SkipPseudoOp=true) const
Returns a pointer to the first instruction in this block that is not a PHINode or a debug intrinsic,...
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
LLVM_ABI const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
LLVM_ABI SymbolTableList< BasicBlock >::iterator eraseFromParent()
Unlink 'this' from the containing function and delete it.
InstListType::iterator iterator
Instruction iterators...
LLVM_ABI LLVMContext & getContext() const
Get the context in which this basic block lives.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
void splice(BasicBlock::iterator ToIt, BasicBlock *FromBB)
Transfer all instructions from FromBB to this basic block at ToIt.
Conditional or Unconditional Branch instruction.
unsigned getNumSuccessors() const
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
BasicBlock * getSuccessor(unsigned i) const
void setSuccessor(unsigned idx, BasicBlock *NewSucc)
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
This is the shared class of boolean and integer constants.
uint64_t getLimitedValue(uint64_t Limit=~0ULL) const
getLimitedValue - If the value is smaller than the specified limit, return it, otherwise return the l...
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
Subprogram description. Uses SubclassData1.
static DebugLoc getDropped()
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
void getDescendants(NodeT *R, SmallVectorImpl< NodeT * > &Result) const
Get all nodes dominated by R, including R itself.
void insertEdge(NodeT *From, NodeT *To)
Inform the dominator tree about a CFG edge insertion and update the tree.
void deleteEdge(NodeT *From, NodeT *To)
Inform the dominator tree about a CFG edge deletion and update the tree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Class to represent function types.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
const BasicBlock & getEntryBlock() const
FunctionType * getFunctionType() const
Returns the FunctionType for me.
const BasicBlock & back() const
AttributeList getAttributes() const
Return the attribute list for this Function.
bool hasOptNone() const
Do not optimize this function (-O0).
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
adds the attribute to the list of attributes for the given arg.
Argument * getArg(unsigned i) const
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
bool hasLinkOnceODRLinkage() const
@ InternalLinkage
Rename collisions when linking (static functions).
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition IROutliner.cpp:2996
This class is a pass that identifies similarity in a Module, extracts instances of the similarity,...
bool run(Module &M)
Definition IROutliner.cpp:2989
An analysis pass that runs and returns the IRSimilarityIdentifier run on the Module.
This is a class that wraps a range of IRInstructionData from one point to another in the vector of IR...
std::optional< unsigned > getGVN(Value *V)
Finds the positive number associated with V if it has been mapped.
unsigned getEndIdx() const
void getBasicBlocks(DenseSet< BasicBlock * > &BBSet) const
unsigned getStartIdx() const
BasicBlock * getStartBB()
std::optional< unsigned > getCanonicalNum(unsigned N)
Find the canonical number from the global value number N stored in the candidate.
IRInstructionData * front() const
This class puts all the pieces of the IRInstructionData, IRInstructionMapper, IRSimilarityCandidate t...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
bool isTerminator() const
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
LLVM_ABI InstListType::iterator insertInto(BasicBlock *ParentBB, InstListType::iterator It)
Inserts an unlinked instruction into ParentBB at position It and returns the iterator of the inserted...
An instruction for reading from memory.
Value * getPointerOperand()
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
LLVM_ABI void getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV, bool CannotUsePrivateLabel) const
Print the appropriate prefix and the specified global variable's name.
A Module instance is used to store all the information related to an LLVM module.
void setIncomingBlock(unsigned i, BasicBlock *BB)
void setIncomingValue(unsigned i, Value *V)
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool contains(const BlockT *BB) const
Check if the region contains a BasicBlock.
RegionT * getParent() const
Get the parent of the Region.
Return a value (possibly void), from a function.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
A vector that has set insertion semantics.
ArrayRef< value_type > getArrayRef() const
size_type size() const
Determine the number of elements in the SetVector.
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
static SwitchInst * Create(Value *Value, BasicBlock *Default, unsigned NumCases, InsertPosition InsertBefore=nullptr)
LLVM_ABI void addCase(ConstantInt *OnVal, BasicBlock *Dest)
Add an entry to the switch instruction.
Analysis pass providing the TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
LLVM_ABI InstructionCost getMemoryOpCost(unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind=TTI::TCK_RecipThroughput, OperandValueInfo OpdInfo={OK_AnyValue, OP_None}, const Instruction *I=nullptr) const
@ TCK_CodeSize
Instruction code size.
@ TCC_Basic
The cost of a typical 'add' instruction.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
void setOperand(unsigned i, Value *Val)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
bool erase(const ValueT &V)
An opaque object representing a hash code.
const ParentTy * getParent() const
self_iterator getIterator()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
iterator erase(iterator I)
Remove a node by iterator; never deletes.
iterator insert(iterator I, reference Node)
Insert a node by reference; never copies.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
std::vector< SimilarityGroup > SimilarityGroupList
std::vector< IRSimilarityCandidate > SimilarityGroup
@ BasicBlock
Various leaf nodes.
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
DiagnosticInfoOptimizationBase::Argument NV
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
void stable_sort(R &&Range)
hash_code hash_value(const FixedPointSemantics &Val)
void interleave(ForwardIterator begin, ForwardIterator end, UnaryFunctor each_fn, NullaryFunctor between_fn)
An STL-style algorithm similar to std::for_each that applies a second functor between every pair of e...
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
cl::opt< bool > DisableIndirectCalls("no-ir-sim-indirect-calls", cl::init(false), cl::ReallyHidden, cl::desc("disable outlining indirect calls."))
Definition IROutliner.cpp:43
auto dyn_cast_or_null(const Y &Val)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
@ RF_IgnoreMissingLocals
If this flag is set, the remapper ignores missing function-local entries (Argument,...
@ RF_NoModuleLevelChanges
If this flag is set, the remapper knows that only local values within a function (such as an instruct...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
cl::opt< bool > DisableBranches("no-ir-sim-branch-matching", cl::init(false), cl::ReallyHidden, cl::desc("disable similarity matching, and outlining, " "across branches for debugging purposes."))
Definition IROutliner.cpp:39
cl::opt< bool > DisableIntrinsics("no-ir-sim-intrinsics", cl::init(false), cl::ReallyHidden, cl::desc("Don't match or outline intrinsics"))
Definition IROutliner.cpp:47
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
void RemapFunction(Function &F, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Remap the operands, metadata, arguments, and instructions of a function.
auto predecessors(const MachineBasicBlock *BB)
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
LLVM_ABI void updateLoopMetadataDebugLocations(Instruction &I, function_ref< Metadata *(Metadata *)> Updater)
Update the debug locations contained within the MD_loop metadata attached to the instruction I,...
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
The OutlinableGroup holds all the overarching information for outlining a set of regions that are str...
Definition IROutliner.cpp:73
std::optional< unsigned > SwiftErrorArgument
The argument that needs to be marked with the swifterr attribute.
Definition IROutliner.cpp:136
std::vector< Type * > ArgumentTypes
The argument types for the function created as the overall function to replace the extracted function...
Definition IROutliner.cpp:79
DenseSet< ArrayRef< unsigned > > OutputGVNCombinations
A set containing the different GVN store sets needed.
Definition IROutliner.cpp:99
void findSameConstants(DenseSet< unsigned > &NotSame)
For the Regions, we look at every Value.
Definition IROutliner.cpp:598
InstructionCost Cost
The number of added instructions needed for the outlining of the Regions.
Definition IROutliner.cpp:132
DenseMap< unsigned, std::pair< std::pair< unsigned, unsigned >, SmallVector< unsigned, 2 > > > PHINodeGVNToGVNs
Definition IROutliner.cpp:124
unsigned PHINodeGVNTracker
Tracker counting backwards from the highest unsigned value possible to avoid conflicting with the GVN...
Definition IROutliner.cpp:120
std::vector< OutlinableRegion * > Regions
The sections that could be outlined.
Definition IROutliner.cpp:75
DenseMap< hash_code, unsigned > GVNsToPHINodeGVN
Definition IROutliner.cpp:125
bool IgnoreGroup
Flag for whether we should not consider this group of OutlinableRegions for extraction.
Definition IROutliner.cpp:87
DenseMap< Value *, BasicBlock * > EndBBs
The return blocks for the overall function.
Definition IROutliner.cpp:90
unsigned BranchesToOutside
The number of branches in the region target a basic block that is outside of the region.
Definition IROutliner.cpp:115
Function * OutlinedFunction
The Function for the collective overall function.
Definition IROutliner.cpp:83
bool InputTypesSet
Flag for whether the ArgumentTypes have been defined after the extraction of the first region.
Definition IROutliner.cpp:103
DenseMap< Value *, BasicBlock * > PHIBlocks
The PHIBlocks with their corresponding return block based on the return value as the key.
Definition IROutliner.cpp:94
FunctionType * OutlinedFunctionType
The FunctionType for the overall function.
Definition IROutliner.cpp:81
DenseMap< unsigned, unsigned > CanonicalNumberToAggArg
The mapping of the canonical numbering of the values in outlined sections to specific arguments.
Definition IROutliner.cpp:111
void collectGVNStoreSets(Module &M)
For the regions, look at each set of GVN stores needed and account for each combination.
Definition IROutliner.cpp:605
InstructionCost Benefit
The number of instructions that will be outlined by extracting Regions.
Definition IROutliner.cpp:129
unsigned NumAggregateInputs
The number of input values in ArgumentTypes.
Definition IROutliner.cpp:107
This struct is a compact representation of a valid (non-zero power of two) alignment.
This provides the utilities for hashing an Instruction to an unsigned integer.
Instruction * Inst
The source Instruction that is being wrapped.
Incoming for lane maks phi as machine instruction, incoming register Reg and incoming block Block are...
The OutlinableRegion holds all the information for a specific region, or sequence of instructions.
CallInst * Call
The call site of the extracted region.
CodeExtractor * CE
Used to create an outlined function.
InstructionCost getBenefit(TargetTransformInfo &TTI)
Get the size of the code removed from the region.
Definition IROutliner.cpp:486
BasicBlock * FollowBB
The BasicBlock that is after the start of the region BasicBlock, only defined when the region has bee...
unsigned OutputBlockNum
The corresponding BasicBlock with the appropriate stores for this OutlinableRegion in the overall fun...
bool CandidateSplit
Flag for whether we have split out the IRSimilarityCanidate.
bool IgnoreRegion
Flag for whether we should not consider this region for extraction.
void splitCandidate()
For the contained region, split the parent BasicBlock at the starting and ending instructions of the ...
Definition IROutliner.cpp:249
Value * findCorrespondingValueIn(const OutlinableRegion &Other, Value *V)
Find a corresponding value for V in similar OutlinableRegion Other.
Definition IROutliner.cpp:187
BasicBlock * findCorrespondingBlockIn(const OutlinableRegion &Other, BasicBlock *BB)
Find a corresponding BasicBlock for BB in similar OutlinableRegion Other.
Definition IROutliner.cpp:199
BasicBlock * PrevBB
The BasicBlock that is before the start of the region BasicBlock, only defined when the region has be...
BasicBlock * EndBB
The BasicBlock that contains the ending instruction of the region.
IRSimilarityCandidate * Candidate
Describes the region of code.
DenseMap< Value *, Value * > RemappedArguments
Values in the outlined functions will often be replaced by arguments.
OutlinableRegion(IRSimilarityCandidate &C, OutlinableGroup &Group)
Function * ExtractedFunction
The function for the extracted region.
bool EndsInBranch
Marks whether this region ends in a branch, there is special handling required for the following basi...
BasicBlock * StartBB
The BasicBlock that contains the starting instruction of the region.
void reattachCandidate()
For the contained region, reattach the BasicBlock at the starting and ending instructions of the cont...
Definition IROutliner.cpp:375