xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/CGLoopInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "CGLoopInfo.h"
100b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
110b57cec5SDimitry Andric #include "clang/AST/Attr.h"
125ffd83dbSDimitry Andric #include "clang/AST/Expr.h"
135ffd83dbSDimitry Andric #include "clang/Basic/CodeGenOptions.h"
140b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
150b57cec5SDimitry Andric #include "llvm/IR/CFG.h"
160b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
170b57cec5SDimitry Andric #include "llvm/IR/InstrTypes.h"
180b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
190b57cec5SDimitry Andric #include "llvm/IR/Metadata.h"
20bdd1243dSDimitry Andric #include <optional>
210b57cec5SDimitry Andric using namespace clang::CodeGen;
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric MDNode *
createLoopPropertiesMetadata(ArrayRef<Metadata * > LoopProperties)250b57cec5SDimitry Andric LoopInfo::createLoopPropertiesMetadata(ArrayRef<Metadata *> LoopProperties) {
260b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
270b57cec5SDimitry Andric   SmallVector<Metadata *, 4> NewLoopProperties;
28e8d8bef9SDimitry Andric   NewLoopProperties.push_back(nullptr);
290b57cec5SDimitry Andric   NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, NewLoopProperties);
320b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
330b57cec5SDimitry Andric   return LoopID;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
createPipeliningMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)360b57cec5SDimitry Andric MDNode *LoopInfo::createPipeliningMetadata(const LoopAttributes &Attrs,
370b57cec5SDimitry Andric                                            ArrayRef<Metadata *> LoopProperties,
380b57cec5SDimitry Andric                                            bool &HasUserTransforms) {
390b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
400b57cec5SDimitry Andric 
41bdd1243dSDimitry Andric   std::optional<bool> Enabled;
420b57cec5SDimitry Andric   if (Attrs.PipelineDisabled)
430b57cec5SDimitry Andric     Enabled = false;
440b57cec5SDimitry Andric   else if (Attrs.PipelineInitiationInterval != 0)
450b57cec5SDimitry Andric     Enabled = true;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   if (Enabled != true) {
480b57cec5SDimitry Andric     SmallVector<Metadata *, 4> NewLoopProperties;
490b57cec5SDimitry Andric     if (Enabled == false) {
500b57cec5SDimitry Andric       NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
510b57cec5SDimitry Andric       NewLoopProperties.push_back(
520b57cec5SDimitry Andric           MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.pipeline.disable"),
530b57cec5SDimitry Andric                             ConstantAsMetadata::get(ConstantInt::get(
540b57cec5SDimitry Andric                                 llvm::Type::getInt1Ty(Ctx), 1))}));
550b57cec5SDimitry Andric       LoopProperties = NewLoopProperties;
560b57cec5SDimitry Andric     }
570b57cec5SDimitry Andric     return createLoopPropertiesMetadata(LoopProperties);
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
61e8d8bef9SDimitry Andric   Args.push_back(nullptr);
620b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   if (Attrs.PipelineInitiationInterval > 0) {
650b57cec5SDimitry Andric     Metadata *Vals[] = {
660b57cec5SDimitry Andric         MDString::get(Ctx, "llvm.loop.pipeline.initiationinterval"),
670b57cec5SDimitry Andric         ConstantAsMetadata::get(ConstantInt::get(
680b57cec5SDimitry Andric             llvm::Type::getInt32Ty(Ctx), Attrs.PipelineInitiationInterval))};
690b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   // No follow-up: This is the last transformation.
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
750b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
760b57cec5SDimitry Andric   HasUserTransforms = true;
770b57cec5SDimitry Andric   return LoopID;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric MDNode *
createPartialUnrollMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)810b57cec5SDimitry Andric LoopInfo::createPartialUnrollMetadata(const LoopAttributes &Attrs,
820b57cec5SDimitry Andric                                       ArrayRef<Metadata *> LoopProperties,
830b57cec5SDimitry Andric                                       bool &HasUserTransforms) {
840b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
850b57cec5SDimitry Andric 
86bdd1243dSDimitry Andric   std::optional<bool> Enabled;
870b57cec5SDimitry Andric   if (Attrs.UnrollEnable == LoopAttributes::Disable)
880b57cec5SDimitry Andric     Enabled = false;
890b57cec5SDimitry Andric   else if (Attrs.UnrollEnable == LoopAttributes::Full)
90bdd1243dSDimitry Andric     Enabled = std::nullopt;
910b57cec5SDimitry Andric   else if (Attrs.UnrollEnable != LoopAttributes::Unspecified ||
920b57cec5SDimitry Andric            Attrs.UnrollCount != 0)
930b57cec5SDimitry Andric     Enabled = true;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   if (Enabled != true) {
960b57cec5SDimitry Andric     // createFullUnrollMetadata will already have added llvm.loop.unroll.disable
970b57cec5SDimitry Andric     // if unrolling is disabled.
980b57cec5SDimitry Andric     return createPipeliningMetadata(Attrs, LoopProperties, HasUserTransforms);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   SmallVector<Metadata *, 4> FollowupLoopProperties;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // Apply all loop properties to the unrolled loop.
1040b57cec5SDimitry Andric   FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // Don't unroll an already unrolled loop.
1070b57cec5SDimitry Andric   FollowupLoopProperties.push_back(
1080b57cec5SDimitry Andric       MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.disable")));
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   bool FollowupHasTransforms = false;
1110b57cec5SDimitry Andric   MDNode *Followup = createPipeliningMetadata(Attrs, FollowupLoopProperties,
1120b57cec5SDimitry Andric                                               FollowupHasTransforms);
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
115e8d8bef9SDimitry Andric   Args.push_back(nullptr);
1160b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   // Setting unroll.count
1190b57cec5SDimitry Andric   if (Attrs.UnrollCount > 0) {
1200b57cec5SDimitry Andric     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"),
1210b57cec5SDimitry Andric                         ConstantAsMetadata::get(ConstantInt::get(
1220b57cec5SDimitry Andric                             llvm::Type::getInt32Ty(Ctx), Attrs.UnrollCount))};
1230b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   // Setting unroll.full or unroll.disable
1270b57cec5SDimitry Andric   if (Attrs.UnrollEnable == LoopAttributes::Enable) {
1280b57cec5SDimitry Andric     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.enable")};
1290b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   if (FollowupHasTransforms)
1330b57cec5SDimitry Andric     Args.push_back(MDNode::get(
1340b57cec5SDimitry Andric         Ctx, {MDString::get(Ctx, "llvm.loop.unroll.followup_all"), Followup}));
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
1370b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
1380b57cec5SDimitry Andric   HasUserTransforms = true;
1390b57cec5SDimitry Andric   return LoopID;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric MDNode *
createUnrollAndJamMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)1430b57cec5SDimitry Andric LoopInfo::createUnrollAndJamMetadata(const LoopAttributes &Attrs,
1440b57cec5SDimitry Andric                                      ArrayRef<Metadata *> LoopProperties,
1450b57cec5SDimitry Andric                                      bool &HasUserTransforms) {
1460b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
1470b57cec5SDimitry Andric 
148bdd1243dSDimitry Andric   std::optional<bool> Enabled;
1490b57cec5SDimitry Andric   if (Attrs.UnrollAndJamEnable == LoopAttributes::Disable)
1500b57cec5SDimitry Andric     Enabled = false;
1510b57cec5SDimitry Andric   else if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable ||
1520b57cec5SDimitry Andric            Attrs.UnrollAndJamCount != 0)
1530b57cec5SDimitry Andric     Enabled = true;
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   if (Enabled != true) {
1560b57cec5SDimitry Andric     SmallVector<Metadata *, 4> NewLoopProperties;
1570b57cec5SDimitry Andric     if (Enabled == false) {
1580b57cec5SDimitry Andric       NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
1590b57cec5SDimitry Andric       NewLoopProperties.push_back(MDNode::get(
1600b57cec5SDimitry Andric           Ctx, MDString::get(Ctx, "llvm.loop.unroll_and_jam.disable")));
1610b57cec5SDimitry Andric       LoopProperties = NewLoopProperties;
1620b57cec5SDimitry Andric     }
1630b57cec5SDimitry Andric     return createPartialUnrollMetadata(Attrs, LoopProperties,
1640b57cec5SDimitry Andric                                        HasUserTransforms);
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   SmallVector<Metadata *, 4> FollowupLoopProperties;
1680b57cec5SDimitry Andric   FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
1690b57cec5SDimitry Andric   FollowupLoopProperties.push_back(
1700b57cec5SDimitry Andric       MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll_and_jam.disable")));
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   bool FollowupHasTransforms = false;
1730b57cec5SDimitry Andric   MDNode *Followup = createPartialUnrollMetadata(Attrs, FollowupLoopProperties,
1740b57cec5SDimitry Andric                                                  FollowupHasTransforms);
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
177e8d8bef9SDimitry Andric   Args.push_back(nullptr);
1780b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   // Setting unroll_and_jam.count
1810b57cec5SDimitry Andric   if (Attrs.UnrollAndJamCount > 0) {
1820b57cec5SDimitry Andric     Metadata *Vals[] = {
1830b57cec5SDimitry Andric         MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"),
1840b57cec5SDimitry Andric         ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
1850b57cec5SDimitry Andric                                                  Attrs.UnrollAndJamCount))};
1860b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable) {
1900b57cec5SDimitry Andric     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.enable")};
1910b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   if (FollowupHasTransforms)
1950b57cec5SDimitry Andric     Args.push_back(MDNode::get(
1960b57cec5SDimitry Andric         Ctx, {MDString::get(Ctx, "llvm.loop.unroll_and_jam.followup_outer"),
1970b57cec5SDimitry Andric               Followup}));
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   if (UnrollAndJamInnerFollowup)
2000b57cec5SDimitry Andric     Args.push_back(MDNode::get(
2010b57cec5SDimitry Andric         Ctx, {MDString::get(Ctx, "llvm.loop.unroll_and_jam.followup_inner"),
2020b57cec5SDimitry Andric               UnrollAndJamInnerFollowup}));
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
2050b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
2060b57cec5SDimitry Andric   HasUserTransforms = true;
2070b57cec5SDimitry Andric   return LoopID;
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric MDNode *
createLoopVectorizeMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)2110b57cec5SDimitry Andric LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
2120b57cec5SDimitry Andric                                       ArrayRef<Metadata *> LoopProperties,
2130b57cec5SDimitry Andric                                       bool &HasUserTransforms) {
2140b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
2150b57cec5SDimitry Andric 
216bdd1243dSDimitry Andric   std::optional<bool> Enabled;
2170b57cec5SDimitry Andric   if (Attrs.VectorizeEnable == LoopAttributes::Disable)
2180b57cec5SDimitry Andric     Enabled = false;
2190b57cec5SDimitry Andric   else if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
220a7dea167SDimitry Andric            Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified ||
221e8d8bef9SDimitry Andric            Attrs.InterleaveCount != 0 || Attrs.VectorizeWidth != 0 ||
222e8d8bef9SDimitry Andric            Attrs.VectorizeScalable != LoopAttributes::Unspecified)
2230b57cec5SDimitry Andric     Enabled = true;
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   if (Enabled != true) {
2260b57cec5SDimitry Andric     SmallVector<Metadata *, 4> NewLoopProperties;
2270b57cec5SDimitry Andric     if (Enabled == false) {
2280b57cec5SDimitry Andric       NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
2290b57cec5SDimitry Andric       NewLoopProperties.push_back(
2300b57cec5SDimitry Andric           MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
2310b57cec5SDimitry Andric                             ConstantAsMetadata::get(ConstantInt::get(
2320b57cec5SDimitry Andric                                 llvm::Type::getInt1Ty(Ctx), 0))}));
2330b57cec5SDimitry Andric       LoopProperties = NewLoopProperties;
2340b57cec5SDimitry Andric     }
2350b57cec5SDimitry Andric     return createUnrollAndJamMetadata(Attrs, LoopProperties, HasUserTransforms);
2360b57cec5SDimitry Andric   }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   // Apply all loop properties to the vectorized loop.
2390b57cec5SDimitry Andric   SmallVector<Metadata *, 4> FollowupLoopProperties;
2400b57cec5SDimitry Andric   FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   // Don't vectorize an already vectorized loop.
2430b57cec5SDimitry Andric   FollowupLoopProperties.push_back(
2440b57cec5SDimitry Andric       MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized")));
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   bool FollowupHasTransforms = false;
2470b57cec5SDimitry Andric   MDNode *Followup = createUnrollAndJamMetadata(Attrs, FollowupLoopProperties,
2480b57cec5SDimitry Andric                                                 FollowupHasTransforms);
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
251e8d8bef9SDimitry Andric   Args.push_back(nullptr);
2520b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
2530b57cec5SDimitry Andric 
254fe6060f1SDimitry Andric   // Setting vectorize.predicate when it has been specified and vectorization
255fe6060f1SDimitry Andric   // has not been disabled.
256a7dea167SDimitry Andric   bool IsVectorPredicateEnabled = false;
257fe6060f1SDimitry Andric   if (Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified) {
258a7dea167SDimitry Andric     IsVectorPredicateEnabled =
259a7dea167SDimitry Andric         (Attrs.VectorizePredicateEnable == LoopAttributes::Enable);
260a7dea167SDimitry Andric 
261a7dea167SDimitry Andric     Metadata *Vals[] = {
262a7dea167SDimitry Andric         MDString::get(Ctx, "llvm.loop.vectorize.predicate.enable"),
263a7dea167SDimitry Andric         ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt1Ty(Ctx),
264a7dea167SDimitry Andric                                                  IsVectorPredicateEnabled))};
265a7dea167SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
266a7dea167SDimitry Andric   }
267a7dea167SDimitry Andric 
2680b57cec5SDimitry Andric   // Setting vectorize.width
2690b57cec5SDimitry Andric   if (Attrs.VectorizeWidth > 0) {
2700b57cec5SDimitry Andric     Metadata *Vals[] = {
2710b57cec5SDimitry Andric         MDString::get(Ctx, "llvm.loop.vectorize.width"),
2720b57cec5SDimitry Andric         ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
2730b57cec5SDimitry Andric                                                  Attrs.VectorizeWidth))};
274e8d8bef9SDimitry Andric 
275e8d8bef9SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
276e8d8bef9SDimitry Andric   }
277e8d8bef9SDimitry Andric 
278e8d8bef9SDimitry Andric   if (Attrs.VectorizeScalable != LoopAttributes::Unspecified) {
279e8d8bef9SDimitry Andric     bool IsScalable = Attrs.VectorizeScalable == LoopAttributes::Enable;
280e8d8bef9SDimitry Andric     Metadata *Vals[] = {
281e8d8bef9SDimitry Andric         MDString::get(Ctx, "llvm.loop.vectorize.scalable.enable"),
282e8d8bef9SDimitry Andric         ConstantAsMetadata::get(
283e8d8bef9SDimitry Andric             ConstantInt::get(llvm::Type::getInt1Ty(Ctx), IsScalable))};
2840b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   // Setting interleave.count
2880b57cec5SDimitry Andric   if (Attrs.InterleaveCount > 0) {
2890b57cec5SDimitry Andric     Metadata *Vals[] = {
2900b57cec5SDimitry Andric         MDString::get(Ctx, "llvm.loop.interleave.count"),
2910b57cec5SDimitry Andric         ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
2920b57cec5SDimitry Andric                                                  Attrs.InterleaveCount))};
2930b57cec5SDimitry Andric     Args.push_back(MDNode::get(Ctx, Vals));
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric 
296480093f4SDimitry Andric   // vectorize.enable is set if:
297480093f4SDimitry Andric   // 1) loop hint vectorize.enable is set, or
298480093f4SDimitry Andric   // 2) it is implied when vectorize.predicate is set, or
299e8d8bef9SDimitry Andric   // 3) it is implied when vectorize.width is set to a value > 1
300e8d8bef9SDimitry Andric   // 4) it is implied when vectorize.scalable.enable is true
301e8d8bef9SDimitry Andric   // 5) it is implied when vectorize.width is unset (0) and the user
302e8d8bef9SDimitry Andric   //    explicitly requested fixed-width vectorization, i.e.
303e8d8bef9SDimitry Andric   //    vectorize.scalable.enable is false.
304a7dea167SDimitry Andric   if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
305fe6060f1SDimitry Andric       (IsVectorPredicateEnabled && Attrs.VectorizeWidth != 1) ||
306fe6060f1SDimitry Andric       Attrs.VectorizeWidth > 1 ||
307e8d8bef9SDimitry Andric       Attrs.VectorizeScalable == LoopAttributes::Enable ||
308e8d8bef9SDimitry Andric       (Attrs.VectorizeScalable == LoopAttributes::Disable &&
309e8d8bef9SDimitry Andric        Attrs.VectorizeWidth != 1)) {
310480093f4SDimitry Andric     bool AttrVal = Attrs.VectorizeEnable != LoopAttributes::Disable;
311480093f4SDimitry Andric     Args.push_back(
312480093f4SDimitry Andric         MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
3130b57cec5SDimitry Andric                           ConstantAsMetadata::get(ConstantInt::get(
314480093f4SDimitry Andric                               llvm::Type::getInt1Ty(Ctx), AttrVal))}));
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   if (FollowupHasTransforms)
3180b57cec5SDimitry Andric     Args.push_back(MDNode::get(
3190b57cec5SDimitry Andric         Ctx,
3200b57cec5SDimitry Andric         {MDString::get(Ctx, "llvm.loop.vectorize.followup_all"), Followup}));
3210b57cec5SDimitry Andric 
322e8d8bef9SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
3230b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
3240b57cec5SDimitry Andric   HasUserTransforms = true;
3250b57cec5SDimitry Andric   return LoopID;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric MDNode *
createLoopDistributeMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)3290b57cec5SDimitry Andric LoopInfo::createLoopDistributeMetadata(const LoopAttributes &Attrs,
3300b57cec5SDimitry Andric                                        ArrayRef<Metadata *> LoopProperties,
3310b57cec5SDimitry Andric                                        bool &HasUserTransforms) {
3320b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
3330b57cec5SDimitry Andric 
334bdd1243dSDimitry Andric   std::optional<bool> Enabled;
3350b57cec5SDimitry Andric   if (Attrs.DistributeEnable == LoopAttributes::Disable)
3360b57cec5SDimitry Andric     Enabled = false;
3370b57cec5SDimitry Andric   if (Attrs.DistributeEnable == LoopAttributes::Enable)
3380b57cec5SDimitry Andric     Enabled = true;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   if (Enabled != true) {
3410b57cec5SDimitry Andric     SmallVector<Metadata *, 4> NewLoopProperties;
3420b57cec5SDimitry Andric     if (Enabled == false) {
3430b57cec5SDimitry Andric       NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
3440b57cec5SDimitry Andric       NewLoopProperties.push_back(
3450b57cec5SDimitry Andric           MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.distribute.enable"),
3460b57cec5SDimitry Andric                             ConstantAsMetadata::get(ConstantInt::get(
3470b57cec5SDimitry Andric                                 llvm::Type::getInt1Ty(Ctx), 0))}));
3480b57cec5SDimitry Andric       LoopProperties = NewLoopProperties;
3490b57cec5SDimitry Andric     }
3500b57cec5SDimitry Andric     return createLoopVectorizeMetadata(Attrs, LoopProperties,
3510b57cec5SDimitry Andric                                        HasUserTransforms);
3520b57cec5SDimitry Andric   }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   bool FollowupHasTransforms = false;
3550b57cec5SDimitry Andric   MDNode *Followup =
3560b57cec5SDimitry Andric       createLoopVectorizeMetadata(Attrs, LoopProperties, FollowupHasTransforms);
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
359e8d8bef9SDimitry Andric   Args.push_back(nullptr);
3600b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
3630b57cec5SDimitry Andric                       ConstantAsMetadata::get(ConstantInt::get(
3640b57cec5SDimitry Andric                           llvm::Type::getInt1Ty(Ctx),
3650b57cec5SDimitry Andric                           (Attrs.DistributeEnable == LoopAttributes::Enable)))};
3660b57cec5SDimitry Andric   Args.push_back(MDNode::get(Ctx, Vals));
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   if (FollowupHasTransforms)
3690b57cec5SDimitry Andric     Args.push_back(MDNode::get(
3700b57cec5SDimitry Andric         Ctx,
3710b57cec5SDimitry Andric         {MDString::get(Ctx, "llvm.loop.distribute.followup_all"), Followup}));
3720b57cec5SDimitry Andric 
373e8d8bef9SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
3740b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
3750b57cec5SDimitry Andric   HasUserTransforms = true;
3760b57cec5SDimitry Andric   return LoopID;
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric 
createFullUnrollMetadata(const LoopAttributes & Attrs,ArrayRef<Metadata * > LoopProperties,bool & HasUserTransforms)3790b57cec5SDimitry Andric MDNode *LoopInfo::createFullUnrollMetadata(const LoopAttributes &Attrs,
3800b57cec5SDimitry Andric                                            ArrayRef<Metadata *> LoopProperties,
3810b57cec5SDimitry Andric                                            bool &HasUserTransforms) {
3820b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
3830b57cec5SDimitry Andric 
384bdd1243dSDimitry Andric   std::optional<bool> Enabled;
3850b57cec5SDimitry Andric   if (Attrs.UnrollEnable == LoopAttributes::Disable)
3860b57cec5SDimitry Andric     Enabled = false;
3870b57cec5SDimitry Andric   else if (Attrs.UnrollEnable == LoopAttributes::Full)
3880b57cec5SDimitry Andric     Enabled = true;
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   if (Enabled != true) {
3910b57cec5SDimitry Andric     SmallVector<Metadata *, 4> NewLoopProperties;
3920b57cec5SDimitry Andric     if (Enabled == false) {
3930b57cec5SDimitry Andric       NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
3940b57cec5SDimitry Andric       NewLoopProperties.push_back(
3950b57cec5SDimitry Andric           MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.disable")));
3960b57cec5SDimitry Andric       LoopProperties = NewLoopProperties;
3970b57cec5SDimitry Andric     }
3980b57cec5SDimitry Andric     return createLoopDistributeMetadata(Attrs, LoopProperties,
3990b57cec5SDimitry Andric                                         HasUserTransforms);
4000b57cec5SDimitry Andric   }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric   SmallVector<Metadata *, 4> Args;
403e8d8bef9SDimitry Andric   Args.push_back(nullptr);
4040b57cec5SDimitry Andric   Args.append(LoopProperties.begin(), LoopProperties.end());
4050b57cec5SDimitry Andric   Args.push_back(MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.full")));
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   // No follow-up: there is no loop after full unrolling.
4080b57cec5SDimitry Andric   // TODO: Warn if there are transformations after full unrolling.
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   MDNode *LoopID = MDNode::getDistinct(Ctx, Args);
4110b57cec5SDimitry Andric   LoopID->replaceOperandWith(0, LoopID);
4120b57cec5SDimitry Andric   HasUserTransforms = true;
4130b57cec5SDimitry Andric   return LoopID;
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
createMetadata(const LoopAttributes & Attrs,llvm::ArrayRef<llvm::Metadata * > AdditionalLoopProperties,bool & HasUserTransforms)4160b57cec5SDimitry Andric MDNode *LoopInfo::createMetadata(
4170b57cec5SDimitry Andric     const LoopAttributes &Attrs,
4180b57cec5SDimitry Andric     llvm::ArrayRef<llvm::Metadata *> AdditionalLoopProperties,
4190b57cec5SDimitry Andric     bool &HasUserTransforms) {
4200b57cec5SDimitry Andric   SmallVector<Metadata *, 3> LoopProperties;
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   // If we have a valid start debug location for the loop, add it.
4230b57cec5SDimitry Andric   if (StartLoc) {
4240b57cec5SDimitry Andric     LoopProperties.push_back(StartLoc.getAsMDNode());
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric     // If we also have a valid end debug location for the loop, add it.
4270b57cec5SDimitry Andric     if (EndLoc)
4280b57cec5SDimitry Andric       LoopProperties.push_back(EndLoc.getAsMDNode());
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric 
431e8d8bef9SDimitry Andric   LLVMContext &Ctx = Header->getContext();
432e8d8bef9SDimitry Andric   if (Attrs.MustProgress)
433e8d8bef9SDimitry Andric     LoopProperties.push_back(
434e8d8bef9SDimitry Andric         MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.mustprogress")));
435e8d8bef9SDimitry Andric 
4360b57cec5SDimitry Andric   assert(!!AccGroup == Attrs.IsParallel &&
4370b57cec5SDimitry Andric          "There must be an access group iff the loop is parallel");
4380b57cec5SDimitry Andric   if (Attrs.IsParallel) {
4390b57cec5SDimitry Andric     LoopProperties.push_back(MDNode::get(
4400b57cec5SDimitry Andric         Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup}));
4410b57cec5SDimitry Andric   }
4420b57cec5SDimitry Andric 
4435f757f3fSDimitry Andric   // Setting clang::code_align attribute.
4445f757f3fSDimitry Andric   if (Attrs.CodeAlign > 0) {
4455f757f3fSDimitry Andric     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.align"),
4465f757f3fSDimitry Andric                         ConstantAsMetadata::get(ConstantInt::get(
4475f757f3fSDimitry Andric                             llvm::Type::getInt32Ty(Ctx), Attrs.CodeAlign))};
4485f757f3fSDimitry Andric     LoopProperties.push_back(MDNode::get(Ctx, Vals));
4495f757f3fSDimitry Andric   }
4505f757f3fSDimitry Andric 
4510b57cec5SDimitry Andric   LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(),
4520b57cec5SDimitry Andric                         AdditionalLoopProperties.end());
4530b57cec5SDimitry Andric   return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric 
LoopAttributes(bool IsParallel)4560b57cec5SDimitry Andric LoopAttributes::LoopAttributes(bool IsParallel)
4570b57cec5SDimitry Andric     : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
4580b57cec5SDimitry Andric       UnrollEnable(LoopAttributes::Unspecified),
459a7dea167SDimitry Andric       UnrollAndJamEnable(LoopAttributes::Unspecified),
460a7dea167SDimitry Andric       VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
461e8d8bef9SDimitry Andric       VectorizeScalable(LoopAttributes::Unspecified), InterleaveCount(0),
462e8d8bef9SDimitry Andric       UnrollCount(0), UnrollAndJamCount(0),
4630b57cec5SDimitry Andric       DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
4645f757f3fSDimitry Andric       PipelineInitiationInterval(0), CodeAlign(0), MustProgress(false) {}
4650b57cec5SDimitry Andric 
clear()4660b57cec5SDimitry Andric void LoopAttributes::clear() {
4670b57cec5SDimitry Andric   IsParallel = false;
4680b57cec5SDimitry Andric   VectorizeWidth = 0;
469e8d8bef9SDimitry Andric   VectorizeScalable = LoopAttributes::Unspecified;
4700b57cec5SDimitry Andric   InterleaveCount = 0;
4710b57cec5SDimitry Andric   UnrollCount = 0;
4720b57cec5SDimitry Andric   UnrollAndJamCount = 0;
4730b57cec5SDimitry Andric   VectorizeEnable = LoopAttributes::Unspecified;
4740b57cec5SDimitry Andric   UnrollEnable = LoopAttributes::Unspecified;
4750b57cec5SDimitry Andric   UnrollAndJamEnable = LoopAttributes::Unspecified;
476a7dea167SDimitry Andric   VectorizePredicateEnable = LoopAttributes::Unspecified;
4770b57cec5SDimitry Andric   DistributeEnable = LoopAttributes::Unspecified;
4780b57cec5SDimitry Andric   PipelineDisabled = false;
4790b57cec5SDimitry Andric   PipelineInitiationInterval = 0;
4805f757f3fSDimitry Andric   CodeAlign = 0;
481e8d8bef9SDimitry Andric   MustProgress = false;
4820b57cec5SDimitry Andric }
4830b57cec5SDimitry Andric 
LoopInfo(BasicBlock * Header,const LoopAttributes & Attrs,const llvm::DebugLoc & StartLoc,const llvm::DebugLoc & EndLoc,LoopInfo * Parent)4840b57cec5SDimitry Andric LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
4850b57cec5SDimitry Andric                    const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc,
4860b57cec5SDimitry Andric                    LoopInfo *Parent)
4870b57cec5SDimitry Andric     : Header(Header), Attrs(Attrs), StartLoc(StartLoc), EndLoc(EndLoc),
4880b57cec5SDimitry Andric       Parent(Parent) {
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   if (Attrs.IsParallel) {
4910b57cec5SDimitry Andric     // Create an access group for this loop.
4920b57cec5SDimitry Andric     LLVMContext &Ctx = Header->getContext();
4930b57cec5SDimitry Andric     AccGroup = MDNode::getDistinct(Ctx, {});
4940b57cec5SDimitry Andric   }
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric   if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
497e8d8bef9SDimitry Andric       Attrs.VectorizeScalable == LoopAttributes::Unspecified &&
4980b57cec5SDimitry Andric       Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
4990b57cec5SDimitry Andric       Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
5000b57cec5SDimitry Andric       Attrs.PipelineInitiationInterval == 0 &&
501a7dea167SDimitry Andric       Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified &&
5020b57cec5SDimitry Andric       Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
5030b57cec5SDimitry Andric       Attrs.UnrollEnable == LoopAttributes::Unspecified &&
5040b57cec5SDimitry Andric       Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
5055f757f3fSDimitry Andric       Attrs.DistributeEnable == LoopAttributes::Unspecified &&
5065f757f3fSDimitry Andric       Attrs.CodeAlign == 0 && !StartLoc && !EndLoc && !Attrs.MustProgress)
5070b57cec5SDimitry Andric     return;
5080b57cec5SDimitry Andric 
509bdd1243dSDimitry Andric   TempLoopID = MDNode::getTemporary(Header->getContext(), std::nullopt);
5100b57cec5SDimitry Andric }
5110b57cec5SDimitry Andric 
finish()5120b57cec5SDimitry Andric void LoopInfo::finish() {
5130b57cec5SDimitry Andric   // We did not annotate the loop body instructions because there are no
5140b57cec5SDimitry Andric   // attributes for this loop.
5150b57cec5SDimitry Andric   if (!TempLoopID)
5160b57cec5SDimitry Andric     return;
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   MDNode *LoopID;
5190b57cec5SDimitry Andric   LoopAttributes CurLoopAttr = Attrs;
5200b57cec5SDimitry Andric   LLVMContext &Ctx = Header->getContext();
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   if (Parent && (Parent->Attrs.UnrollAndJamEnable ||
5230b57cec5SDimitry Andric                  Parent->Attrs.UnrollAndJamCount != 0)) {
5240b57cec5SDimitry Andric     // Parent unroll-and-jams this loop.
5250b57cec5SDimitry Andric     // Split the transformations in those that happens before the unroll-and-jam
5260b57cec5SDimitry Andric     // and those after.
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric     LoopAttributes BeforeJam, AfterJam;
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric     BeforeJam.IsParallel = AfterJam.IsParallel = Attrs.IsParallel;
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric     BeforeJam.VectorizeWidth = Attrs.VectorizeWidth;
533e8d8bef9SDimitry Andric     BeforeJam.VectorizeScalable = Attrs.VectorizeScalable;
5340b57cec5SDimitry Andric     BeforeJam.InterleaveCount = Attrs.InterleaveCount;
5350b57cec5SDimitry Andric     BeforeJam.VectorizeEnable = Attrs.VectorizeEnable;
5360b57cec5SDimitry Andric     BeforeJam.DistributeEnable = Attrs.DistributeEnable;
537a7dea167SDimitry Andric     BeforeJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable;
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric     switch (Attrs.UnrollEnable) {
5400b57cec5SDimitry Andric     case LoopAttributes::Unspecified:
5410b57cec5SDimitry Andric     case LoopAttributes::Disable:
5420b57cec5SDimitry Andric       BeforeJam.UnrollEnable = Attrs.UnrollEnable;
5430b57cec5SDimitry Andric       AfterJam.UnrollEnable = Attrs.UnrollEnable;
5440b57cec5SDimitry Andric       break;
5450b57cec5SDimitry Andric     case LoopAttributes::Full:
5460b57cec5SDimitry Andric       BeforeJam.UnrollEnable = LoopAttributes::Full;
5470b57cec5SDimitry Andric       break;
5480b57cec5SDimitry Andric     case LoopAttributes::Enable:
5490b57cec5SDimitry Andric       AfterJam.UnrollEnable = LoopAttributes::Enable;
5500b57cec5SDimitry Andric       break;
5510b57cec5SDimitry Andric     }
5520b57cec5SDimitry Andric 
553a7dea167SDimitry Andric     AfterJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable;
5540b57cec5SDimitry Andric     AfterJam.UnrollCount = Attrs.UnrollCount;
5550b57cec5SDimitry Andric     AfterJam.PipelineDisabled = Attrs.PipelineDisabled;
5560b57cec5SDimitry Andric     AfterJam.PipelineInitiationInterval = Attrs.PipelineInitiationInterval;
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric     // If this loop is subject of an unroll-and-jam by the parent loop, and has
5590b57cec5SDimitry Andric     // an unroll-and-jam annotation itself, we have to decide whether to first
5600b57cec5SDimitry Andric     // apply the parent's unroll-and-jam or this loop's unroll-and-jam. The
5610b57cec5SDimitry Andric     // UnrollAndJam pass processes loops from inner to outer, so we apply the
5620b57cec5SDimitry Andric     // inner first.
5630b57cec5SDimitry Andric     BeforeJam.UnrollAndJamCount = Attrs.UnrollAndJamCount;
5640b57cec5SDimitry Andric     BeforeJam.UnrollAndJamEnable = Attrs.UnrollAndJamEnable;
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric     // Set the inner followup metadata to process by the outer loop. Only
5670b57cec5SDimitry Andric     // consider the first inner loop.
5680b57cec5SDimitry Andric     if (!Parent->UnrollAndJamInnerFollowup) {
5690b57cec5SDimitry Andric       // Splitting the attributes into a BeforeJam and an AfterJam part will
5700b57cec5SDimitry Andric       // stop 'llvm.loop.isvectorized' (generated by vectorization in BeforeJam)
5710b57cec5SDimitry Andric       // to be forwarded to the AfterJam part. We detect the situation here and
5720b57cec5SDimitry Andric       // add it manually.
5730b57cec5SDimitry Andric       SmallVector<Metadata *, 1> BeforeLoopProperties;
5740b57cec5SDimitry Andric       if (BeforeJam.VectorizeEnable != LoopAttributes::Unspecified ||
575a7dea167SDimitry Andric           BeforeJam.VectorizePredicateEnable != LoopAttributes::Unspecified ||
576e8d8bef9SDimitry Andric           BeforeJam.InterleaveCount != 0 || BeforeJam.VectorizeWidth != 0 ||
577e8d8bef9SDimitry Andric           BeforeJam.VectorizeScalable == LoopAttributes::Enable)
5780b57cec5SDimitry Andric         BeforeLoopProperties.push_back(
5790b57cec5SDimitry Andric             MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized")));
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric       bool InnerFollowupHasTransform = false;
5820b57cec5SDimitry Andric       MDNode *InnerFollowup = createMetadata(AfterJam, BeforeLoopProperties,
5830b57cec5SDimitry Andric                                              InnerFollowupHasTransform);
5840b57cec5SDimitry Andric       if (InnerFollowupHasTransform)
5850b57cec5SDimitry Andric         Parent->UnrollAndJamInnerFollowup = InnerFollowup;
5860b57cec5SDimitry Andric     }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric     CurLoopAttr = BeforeJam;
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric   bool HasUserTransforms = false;
5920b57cec5SDimitry Andric   LoopID = createMetadata(CurLoopAttr, {}, HasUserTransforms);
5930b57cec5SDimitry Andric   TempLoopID->replaceAllUsesWith(LoopID);
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric 
push(BasicBlock * Header,const llvm::DebugLoc & StartLoc,const llvm::DebugLoc & EndLoc)5960b57cec5SDimitry Andric void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc,
5970b57cec5SDimitry Andric                          const llvm::DebugLoc &EndLoc) {
598a7dea167SDimitry Andric   Active.emplace_back(
599a7dea167SDimitry Andric       new LoopInfo(Header, StagedAttrs, StartLoc, EndLoc,
600a7dea167SDimitry Andric                    Active.empty() ? nullptr : Active.back().get()));
6010b57cec5SDimitry Andric   // Clear the attributes so nested loops do not inherit them.
6020b57cec5SDimitry Andric   StagedAttrs.clear();
6030b57cec5SDimitry Andric }
6040b57cec5SDimitry Andric 
push(BasicBlock * Header,clang::ASTContext & Ctx,const clang::CodeGenOptions & CGOpts,ArrayRef<const clang::Attr * > Attrs,const llvm::DebugLoc & StartLoc,const llvm::DebugLoc & EndLoc,bool MustProgress)6050b57cec5SDimitry Andric void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
6065ffd83dbSDimitry Andric                          const clang::CodeGenOptions &CGOpts,
6070b57cec5SDimitry Andric                          ArrayRef<const clang::Attr *> Attrs,
6080b57cec5SDimitry Andric                          const llvm::DebugLoc &StartLoc,
609e8d8bef9SDimitry Andric                          const llvm::DebugLoc &EndLoc, bool MustProgress) {
6100b57cec5SDimitry Andric   // Identify loop hint attributes from Attrs.
6110b57cec5SDimitry Andric   for (const auto *Attr : Attrs) {
6120b57cec5SDimitry Andric     const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
6130b57cec5SDimitry Andric     const OpenCLUnrollHintAttr *OpenCLHint =
6140b57cec5SDimitry Andric         dyn_cast<OpenCLUnrollHintAttr>(Attr);
615*0fca6ea1SDimitry Andric     const HLSLLoopHintAttr *HLSLLoopHint = dyn_cast<HLSLLoopHintAttr>(Attr);
6160b57cec5SDimitry Andric     // Skip non loop hint attributes
617*0fca6ea1SDimitry Andric     if (!LH && !OpenCLHint && !HLSLLoopHint) {
6180b57cec5SDimitry Andric       continue;
6190b57cec5SDimitry Andric     }
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric     LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
6220b57cec5SDimitry Andric     LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
6230b57cec5SDimitry Andric     unsigned ValueInt = 1;
6240b57cec5SDimitry Andric     // Translate opencl_unroll_hint attribute argument to
6250b57cec5SDimitry Andric     // equivalent LoopHintAttr enums.
6260b57cec5SDimitry Andric     // OpenCL v2.0 s6.11.5:
6270b57cec5SDimitry Andric     // 0 - enable unroll (no argument).
6280b57cec5SDimitry Andric     // 1 - disable unroll.
6290b57cec5SDimitry Andric     // other positive integer n - unroll by n.
6300b57cec5SDimitry Andric     if (OpenCLHint) {
6310b57cec5SDimitry Andric       ValueInt = OpenCLHint->getUnrollHint();
6320b57cec5SDimitry Andric       if (ValueInt == 0) {
6330b57cec5SDimitry Andric         State = LoopHintAttr::Enable;
6340b57cec5SDimitry Andric       } else if (ValueInt != 1) {
6350b57cec5SDimitry Andric         Option = LoopHintAttr::UnrollCount;
6360b57cec5SDimitry Andric         State = LoopHintAttr::Numeric;
6370b57cec5SDimitry Andric       }
638*0fca6ea1SDimitry Andric     } else if (HLSLLoopHint) {
639*0fca6ea1SDimitry Andric       ValueInt = HLSLLoopHint->getDirective();
640*0fca6ea1SDimitry Andric       if (HLSLLoopHint->getSemanticSpelling() ==
641*0fca6ea1SDimitry Andric           HLSLLoopHintAttr::Spelling::Microsoft_unroll) {
642*0fca6ea1SDimitry Andric         if (ValueInt == 0)
643*0fca6ea1SDimitry Andric           State = LoopHintAttr::Enable;
644*0fca6ea1SDimitry Andric         if (ValueInt > 0) {
645*0fca6ea1SDimitry Andric           Option = LoopHintAttr::UnrollCount;
646*0fca6ea1SDimitry Andric           State = LoopHintAttr::Numeric;
647*0fca6ea1SDimitry Andric         }
648*0fca6ea1SDimitry Andric       }
6490b57cec5SDimitry Andric     } else if (LH) {
6500b57cec5SDimitry Andric       auto *ValueExpr = LH->getValue();
6510b57cec5SDimitry Andric       if (ValueExpr) {
6520b57cec5SDimitry Andric         llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
6530b57cec5SDimitry Andric         ValueInt = ValueAPS.getSExtValue();
6540b57cec5SDimitry Andric       }
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric       Option = LH->getOption();
6570b57cec5SDimitry Andric       State = LH->getState();
6580b57cec5SDimitry Andric     }
6590b57cec5SDimitry Andric     switch (State) {
6600b57cec5SDimitry Andric     case LoopHintAttr::Disable:
6610b57cec5SDimitry Andric       switch (Option) {
6620b57cec5SDimitry Andric       case LoopHintAttr::Vectorize:
6630b57cec5SDimitry Andric         // Disable vectorization by specifying a width of 1.
6640b57cec5SDimitry Andric         setVectorizeWidth(1);
665e8d8bef9SDimitry Andric         setVectorizeScalable(LoopAttributes::Unspecified);
6660b57cec5SDimitry Andric         break;
6670b57cec5SDimitry Andric       case LoopHintAttr::Interleave:
6680b57cec5SDimitry Andric         // Disable interleaving by speciyfing a count of 1.
6690b57cec5SDimitry Andric         setInterleaveCount(1);
6700b57cec5SDimitry Andric         break;
6710b57cec5SDimitry Andric       case LoopHintAttr::Unroll:
6720b57cec5SDimitry Andric         setUnrollState(LoopAttributes::Disable);
6730b57cec5SDimitry Andric         break;
6740b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJam:
6750b57cec5SDimitry Andric         setUnrollAndJamState(LoopAttributes::Disable);
6760b57cec5SDimitry Andric         break;
677a7dea167SDimitry Andric       case LoopHintAttr::VectorizePredicate:
678a7dea167SDimitry Andric         setVectorizePredicateState(LoopAttributes::Disable);
679a7dea167SDimitry Andric         break;
6800b57cec5SDimitry Andric       case LoopHintAttr::Distribute:
6810b57cec5SDimitry Andric         setDistributeState(false);
6820b57cec5SDimitry Andric         break;
6830b57cec5SDimitry Andric       case LoopHintAttr::PipelineDisabled:
6840b57cec5SDimitry Andric         setPipelineDisabled(true);
6850b57cec5SDimitry Andric         break;
6860b57cec5SDimitry Andric       case LoopHintAttr::UnrollCount:
6870b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJamCount:
6880b57cec5SDimitry Andric       case LoopHintAttr::VectorizeWidth:
6890b57cec5SDimitry Andric       case LoopHintAttr::InterleaveCount:
6900b57cec5SDimitry Andric       case LoopHintAttr::PipelineInitiationInterval:
6910b57cec5SDimitry Andric         llvm_unreachable("Options cannot be disabled.");
6920b57cec5SDimitry Andric         break;
6930b57cec5SDimitry Andric       }
6940b57cec5SDimitry Andric       break;
6950b57cec5SDimitry Andric     case LoopHintAttr::Enable:
6960b57cec5SDimitry Andric       switch (Option) {
6970b57cec5SDimitry Andric       case LoopHintAttr::Vectorize:
6980b57cec5SDimitry Andric       case LoopHintAttr::Interleave:
6990b57cec5SDimitry Andric         setVectorizeEnable(true);
7000b57cec5SDimitry Andric         break;
7010b57cec5SDimitry Andric       case LoopHintAttr::Unroll:
7020b57cec5SDimitry Andric         setUnrollState(LoopAttributes::Enable);
7030b57cec5SDimitry Andric         break;
7040b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJam:
7050b57cec5SDimitry Andric         setUnrollAndJamState(LoopAttributes::Enable);
7060b57cec5SDimitry Andric         break;
707a7dea167SDimitry Andric       case LoopHintAttr::VectorizePredicate:
708a7dea167SDimitry Andric         setVectorizePredicateState(LoopAttributes::Enable);
709a7dea167SDimitry Andric         break;
7100b57cec5SDimitry Andric       case LoopHintAttr::Distribute:
7110b57cec5SDimitry Andric         setDistributeState(true);
7120b57cec5SDimitry Andric         break;
7130b57cec5SDimitry Andric       case LoopHintAttr::UnrollCount:
7140b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJamCount:
7150b57cec5SDimitry Andric       case LoopHintAttr::VectorizeWidth:
7160b57cec5SDimitry Andric       case LoopHintAttr::InterleaveCount:
7170b57cec5SDimitry Andric       case LoopHintAttr::PipelineDisabled:
7180b57cec5SDimitry Andric       case LoopHintAttr::PipelineInitiationInterval:
7190b57cec5SDimitry Andric         llvm_unreachable("Options cannot enabled.");
7200b57cec5SDimitry Andric         break;
7210b57cec5SDimitry Andric       }
7220b57cec5SDimitry Andric       break;
7230b57cec5SDimitry Andric     case LoopHintAttr::AssumeSafety:
7240b57cec5SDimitry Andric       switch (Option) {
7250b57cec5SDimitry Andric       case LoopHintAttr::Vectorize:
7260b57cec5SDimitry Andric       case LoopHintAttr::Interleave:
7270b57cec5SDimitry Andric         // Apply "llvm.mem.parallel_loop_access" metadata to load/stores.
7280b57cec5SDimitry Andric         setParallel(true);
7290b57cec5SDimitry Andric         setVectorizeEnable(true);
7300b57cec5SDimitry Andric         break;
7310b57cec5SDimitry Andric       case LoopHintAttr::Unroll:
7320b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJam:
733a7dea167SDimitry Andric       case LoopHintAttr::VectorizePredicate:
7340b57cec5SDimitry Andric       case LoopHintAttr::UnrollCount:
7350b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJamCount:
7360b57cec5SDimitry Andric       case LoopHintAttr::VectorizeWidth:
7370b57cec5SDimitry Andric       case LoopHintAttr::InterleaveCount:
7380b57cec5SDimitry Andric       case LoopHintAttr::Distribute:
7390b57cec5SDimitry Andric       case LoopHintAttr::PipelineDisabled:
7400b57cec5SDimitry Andric       case LoopHintAttr::PipelineInitiationInterval:
7410b57cec5SDimitry Andric         llvm_unreachable("Options cannot be used to assume mem safety.");
7420b57cec5SDimitry Andric         break;
7430b57cec5SDimitry Andric       }
7440b57cec5SDimitry Andric       break;
7450b57cec5SDimitry Andric     case LoopHintAttr::Full:
7460b57cec5SDimitry Andric       switch (Option) {
7470b57cec5SDimitry Andric       case LoopHintAttr::Unroll:
7480b57cec5SDimitry Andric         setUnrollState(LoopAttributes::Full);
7490b57cec5SDimitry Andric         break;
7500b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJam:
7510b57cec5SDimitry Andric         setUnrollAndJamState(LoopAttributes::Full);
7520b57cec5SDimitry Andric         break;
7530b57cec5SDimitry Andric       case LoopHintAttr::Vectorize:
7540b57cec5SDimitry Andric       case LoopHintAttr::Interleave:
7550b57cec5SDimitry Andric       case LoopHintAttr::UnrollCount:
7560b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJamCount:
7570b57cec5SDimitry Andric       case LoopHintAttr::VectorizeWidth:
7580b57cec5SDimitry Andric       case LoopHintAttr::InterleaveCount:
7590b57cec5SDimitry Andric       case LoopHintAttr::Distribute:
7600b57cec5SDimitry Andric       case LoopHintAttr::PipelineDisabled:
7610b57cec5SDimitry Andric       case LoopHintAttr::PipelineInitiationInterval:
762a7dea167SDimitry Andric       case LoopHintAttr::VectorizePredicate:
7630b57cec5SDimitry Andric         llvm_unreachable("Options cannot be used with 'full' hint.");
7640b57cec5SDimitry Andric         break;
7650b57cec5SDimitry Andric       }
7660b57cec5SDimitry Andric       break;
767e8d8bef9SDimitry Andric     case LoopHintAttr::FixedWidth:
768e8d8bef9SDimitry Andric     case LoopHintAttr::ScalableWidth:
7690b57cec5SDimitry Andric       switch (Option) {
7700b57cec5SDimitry Andric       case LoopHintAttr::VectorizeWidth:
771e8d8bef9SDimitry Andric         setVectorizeScalable(State == LoopHintAttr::ScalableWidth
772e8d8bef9SDimitry Andric                                  ? LoopAttributes::Enable
773e8d8bef9SDimitry Andric                                  : LoopAttributes::Disable);
774e8d8bef9SDimitry Andric         if (LH->getValue())
7750b57cec5SDimitry Andric           setVectorizeWidth(ValueInt);
7760b57cec5SDimitry Andric         break;
777e8d8bef9SDimitry Andric       default:
778e8d8bef9SDimitry Andric         llvm_unreachable("Options cannot be used with 'scalable' hint.");
779e8d8bef9SDimitry Andric         break;
780e8d8bef9SDimitry Andric       }
781e8d8bef9SDimitry Andric       break;
782e8d8bef9SDimitry Andric     case LoopHintAttr::Numeric:
783e8d8bef9SDimitry Andric       switch (Option) {
7840b57cec5SDimitry Andric       case LoopHintAttr::InterleaveCount:
7850b57cec5SDimitry Andric         setInterleaveCount(ValueInt);
7860b57cec5SDimitry Andric         break;
7870b57cec5SDimitry Andric       case LoopHintAttr::UnrollCount:
7880b57cec5SDimitry Andric         setUnrollCount(ValueInt);
7890b57cec5SDimitry Andric         break;
7900b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJamCount:
7910b57cec5SDimitry Andric         setUnrollAndJamCount(ValueInt);
7920b57cec5SDimitry Andric         break;
7930b57cec5SDimitry Andric       case LoopHintAttr::PipelineInitiationInterval:
7940b57cec5SDimitry Andric         setPipelineInitiationInterval(ValueInt);
7950b57cec5SDimitry Andric         break;
7960b57cec5SDimitry Andric       case LoopHintAttr::Unroll:
7970b57cec5SDimitry Andric       case LoopHintAttr::UnrollAndJam:
798a7dea167SDimitry Andric       case LoopHintAttr::VectorizePredicate:
7990b57cec5SDimitry Andric       case LoopHintAttr::Vectorize:
800e8d8bef9SDimitry Andric       case LoopHintAttr::VectorizeWidth:
8010b57cec5SDimitry Andric       case LoopHintAttr::Interleave:
8020b57cec5SDimitry Andric       case LoopHintAttr::Distribute:
8030b57cec5SDimitry Andric       case LoopHintAttr::PipelineDisabled:
8040b57cec5SDimitry Andric         llvm_unreachable("Options cannot be assigned a value.");
8050b57cec5SDimitry Andric         break;
8060b57cec5SDimitry Andric       }
8070b57cec5SDimitry Andric       break;
8080b57cec5SDimitry Andric     }
8090b57cec5SDimitry Andric   }
8100b57cec5SDimitry Andric 
8115f757f3fSDimitry Andric   // Identify loop attribute 'code_align' from Attrs.
8125f757f3fSDimitry Andric   // For attribute code_align:
8135f757f3fSDimitry Andric   // n - 'llvm.loop.align i32 n' metadata will be emitted.
8145f757f3fSDimitry Andric   if (const auto *CodeAlign = getSpecificAttr<const CodeAlignAttr>(Attrs)) {
8155f757f3fSDimitry Andric     const auto *CE = cast<ConstantExpr>(CodeAlign->getAlignment());
8165f757f3fSDimitry Andric     llvm::APSInt ArgVal = CE->getResultAsAPSInt();
8175f757f3fSDimitry Andric     setCodeAlign(ArgVal.getSExtValue());
8185f757f3fSDimitry Andric   }
8195f757f3fSDimitry Andric 
820e8d8bef9SDimitry Andric   setMustProgress(MustProgress);
821e8d8bef9SDimitry Andric 
8225ffd83dbSDimitry Andric   if (CGOpts.OptimizationLevel > 0)
8235ffd83dbSDimitry Andric     // Disable unrolling for the loop, if unrolling is disabled (via
8245ffd83dbSDimitry Andric     // -fno-unroll-loops) and no pragmas override the decision.
8255ffd83dbSDimitry Andric     if (!CGOpts.UnrollLoops &&
8265ffd83dbSDimitry Andric         (StagedAttrs.UnrollEnable == LoopAttributes::Unspecified &&
8275ffd83dbSDimitry Andric          StagedAttrs.UnrollCount == 0))
8285ffd83dbSDimitry Andric       setUnrollState(LoopAttributes::Disable);
8295ffd83dbSDimitry Andric 
8300b57cec5SDimitry Andric   /// Stage the attributes.
8310b57cec5SDimitry Andric   push(Header, StartLoc, EndLoc);
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric 
pop()8340b57cec5SDimitry Andric void LoopInfoStack::pop() {
8350b57cec5SDimitry Andric   assert(!Active.empty() && "No active loops to pop");
836a7dea167SDimitry Andric   Active.back()->finish();
8370b57cec5SDimitry Andric   Active.pop_back();
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
InsertHelper(Instruction * I) const8400b57cec5SDimitry Andric void LoopInfoStack::InsertHelper(Instruction *I) const {
8410b57cec5SDimitry Andric   if (I->mayReadOrWriteMemory()) {
8420b57cec5SDimitry Andric     SmallVector<Metadata *, 4> AccessGroups;
843a7dea167SDimitry Andric     for (const auto &AL : Active) {
8440b57cec5SDimitry Andric       // Here we assume that every loop that has an access group is parallel.
845a7dea167SDimitry Andric       if (MDNode *Group = AL->getAccessGroup())
8460b57cec5SDimitry Andric         AccessGroups.push_back(Group);
8470b57cec5SDimitry Andric     }
8480b57cec5SDimitry Andric     MDNode *UnionMD = nullptr;
8490b57cec5SDimitry Andric     if (AccessGroups.size() == 1)
8500b57cec5SDimitry Andric       UnionMD = cast<MDNode>(AccessGroups[0]);
8510b57cec5SDimitry Andric     else if (AccessGroups.size() >= 2)
8520b57cec5SDimitry Andric       UnionMD = MDNode::get(I->getContext(), AccessGroups);
8530b57cec5SDimitry Andric     I->setMetadata("llvm.access.group", UnionMD);
8540b57cec5SDimitry Andric   }
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric   if (!hasInfo())
8570b57cec5SDimitry Andric     return;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   const LoopInfo &L = getInfo();
8600b57cec5SDimitry Andric   if (!L.getLoopID())
8610b57cec5SDimitry Andric     return;
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   if (I->isTerminator()) {
8640b57cec5SDimitry Andric     for (BasicBlock *Succ : successors(I))
8650b57cec5SDimitry Andric       if (Succ == L.getHeader()) {
8660b57cec5SDimitry Andric         I->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID());
8670b57cec5SDimitry Andric         break;
8680b57cec5SDimitry Andric       }
8690b57cec5SDimitry Andric     return;
8700b57cec5SDimitry Andric   }
8710b57cec5SDimitry Andric }
872