|  | //===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "CGLoopInfo.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/Attr.h" | 
|  | #include "clang/AST/Expr.h" | 
|  | #include "clang/Basic/CodeGenOptions.h" | 
|  | #include "llvm/IR/BasicBlock.h" | 
|  | #include "llvm/IR/CFG.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/InstrTypes.h" | 
|  | #include "llvm/IR/Instructions.h" | 
|  | #include "llvm/IR/Metadata.h" | 
|  | using namespace clang::CodeGen; | 
|  | using namespace llvm; | 
|  |  | 
|  | MDNode * | 
|  | LoopInfo::createLoopPropertiesMetadata(ArrayRef<Metadata *> LoopProperties) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | NewLoopProperties.push_back(TempNode.get()); | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | MDNode *LoopID = MDNode::getDistinct(Ctx, NewLoopProperties); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode *LoopInfo::createPipeliningMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.PipelineDisabled) | 
|  | Enabled = false; | 
|  | else if (Attrs.PipelineInitiationInterval != 0) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | if (Enabled == false) { | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | NewLoopProperties.push_back( | 
|  | MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.pipeline.disable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt1Ty(Ctx), 1))})); | 
|  | LoopProperties = NewLoopProperties; | 
|  | } | 
|  | return createLoopPropertiesMetadata(LoopProperties); | 
|  | } | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | if (Attrs.PipelineInitiationInterval > 0) { | 
|  | Metadata *Vals[] = { | 
|  | MDString::get(Ctx, "llvm.loop.pipeline.initiationinterval"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt32Ty(Ctx), Attrs.PipelineInitiationInterval))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | // No follow-up: This is the last transformation. | 
|  |  | 
|  | MDNode *LoopID = MDNode::getDistinct(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode * | 
|  | LoopInfo::createPartialUnrollMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.UnrollEnable == LoopAttributes::Disable) | 
|  | Enabled = false; | 
|  | else if (Attrs.UnrollEnable == LoopAttributes::Full) | 
|  | Enabled = None; | 
|  | else if (Attrs.UnrollEnable != LoopAttributes::Unspecified || | 
|  | Attrs.UnrollCount != 0) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | // createFullUnrollMetadata will already have added llvm.loop.unroll.disable | 
|  | // if unrolling is disabled. | 
|  | return createPipeliningMetadata(Attrs, LoopProperties, HasUserTransforms); | 
|  | } | 
|  |  | 
|  | SmallVector<Metadata *, 4> FollowupLoopProperties; | 
|  |  | 
|  | // Apply all loop properties to the unrolled loop. | 
|  | FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | // Don't unroll an already unrolled loop. | 
|  | FollowupLoopProperties.push_back( | 
|  | MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.disable"))); | 
|  |  | 
|  | bool FollowupHasTransforms = false; | 
|  | MDNode *Followup = createPipeliningMetadata(Attrs, FollowupLoopProperties, | 
|  | FollowupHasTransforms); | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | // Setting unroll.count | 
|  | if (Attrs.UnrollCount > 0) { | 
|  | Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt32Ty(Ctx), Attrs.UnrollCount))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | // Setting unroll.full or unroll.disable | 
|  | if (Attrs.UnrollEnable == LoopAttributes::Enable) { | 
|  | Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.enable")}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | if (FollowupHasTransforms) | 
|  | Args.push_back(MDNode::get( | 
|  | Ctx, {MDString::get(Ctx, "llvm.loop.unroll.followup_all"), Followup})); | 
|  |  | 
|  | MDNode *LoopID = MDNode::getDistinct(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode * | 
|  | LoopInfo::createUnrollAndJamMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.UnrollAndJamEnable == LoopAttributes::Disable) | 
|  | Enabled = false; | 
|  | else if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable || | 
|  | Attrs.UnrollAndJamCount != 0) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | if (Enabled == false) { | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | NewLoopProperties.push_back(MDNode::get( | 
|  | Ctx, MDString::get(Ctx, "llvm.loop.unroll_and_jam.disable"))); | 
|  | LoopProperties = NewLoopProperties; | 
|  | } | 
|  | return createPartialUnrollMetadata(Attrs, LoopProperties, | 
|  | HasUserTransforms); | 
|  | } | 
|  |  | 
|  | SmallVector<Metadata *, 4> FollowupLoopProperties; | 
|  | FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | FollowupLoopProperties.push_back( | 
|  | MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll_and_jam.disable"))); | 
|  |  | 
|  | bool FollowupHasTransforms = false; | 
|  | MDNode *Followup = createPartialUnrollMetadata(Attrs, FollowupLoopProperties, | 
|  | FollowupHasTransforms); | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | // Setting unroll_and_jam.count | 
|  | if (Attrs.UnrollAndJamCount > 0) { | 
|  | Metadata *Vals[] = { | 
|  | MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"), | 
|  | ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), | 
|  | Attrs.UnrollAndJamCount))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable) { | 
|  | Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.enable")}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | if (FollowupHasTransforms) | 
|  | Args.push_back(MDNode::get( | 
|  | Ctx, {MDString::get(Ctx, "llvm.loop.unroll_and_jam.followup_outer"), | 
|  | Followup})); | 
|  |  | 
|  | if (UnrollAndJamInnerFollowup) | 
|  | Args.push_back(MDNode::get( | 
|  | Ctx, {MDString::get(Ctx, "llvm.loop.unroll_and_jam.followup_inner"), | 
|  | UnrollAndJamInnerFollowup})); | 
|  |  | 
|  | MDNode *LoopID = MDNode::getDistinct(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode * | 
|  | LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.VectorizeEnable == LoopAttributes::Disable) | 
|  | Enabled = false; | 
|  | else if (Attrs.VectorizeEnable != LoopAttributes::Unspecified || | 
|  | Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified || | 
|  | Attrs.InterleaveCount != 0 || Attrs.VectorizeWidth != 0) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | if (Enabled == false) { | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | NewLoopProperties.push_back( | 
|  | MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt1Ty(Ctx), 0))})); | 
|  | LoopProperties = NewLoopProperties; | 
|  | } | 
|  | return createUnrollAndJamMetadata(Attrs, LoopProperties, HasUserTransforms); | 
|  | } | 
|  |  | 
|  | // Apply all loop properties to the vectorized loop. | 
|  | SmallVector<Metadata *, 4> FollowupLoopProperties; | 
|  | FollowupLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | // Don't vectorize an already vectorized loop. | 
|  | FollowupLoopProperties.push_back( | 
|  | MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized"))); | 
|  |  | 
|  | bool FollowupHasTransforms = false; | 
|  | MDNode *Followup = createUnrollAndJamMetadata(Attrs, FollowupLoopProperties, | 
|  | FollowupHasTransforms); | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | // Setting vectorize.predicate | 
|  | bool IsVectorPredicateEnabled = false; | 
|  | if (Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified && | 
|  | Attrs.VectorizeEnable != LoopAttributes::Disable && | 
|  | Attrs.VectorizeWidth < 1) { | 
|  |  | 
|  | IsVectorPredicateEnabled = | 
|  | (Attrs.VectorizePredicateEnable == LoopAttributes::Enable); | 
|  |  | 
|  | Metadata *Vals[] = { | 
|  | MDString::get(Ctx, "llvm.loop.vectorize.predicate.enable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt1Ty(Ctx), | 
|  | IsVectorPredicateEnabled))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | // Setting vectorize.width | 
|  | if (Attrs.VectorizeWidth > 0) { | 
|  | Metadata *Vals[] = { | 
|  | MDString::get(Ctx, "llvm.loop.vectorize.width"), | 
|  | ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), | 
|  | Attrs.VectorizeWidth))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | // Setting interleave.count | 
|  | if (Attrs.InterleaveCount > 0) { | 
|  | Metadata *Vals[] = { | 
|  | MDString::get(Ctx, "llvm.loop.interleave.count"), | 
|  | ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), | 
|  | Attrs.InterleaveCount))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  | } | 
|  |  | 
|  | // vectorize.enable is set if: | 
|  | // 1) loop hint vectorize.enable is set, or | 
|  | // 2) it is implied when vectorize.predicate is set, or | 
|  | // 3) it is implied when vectorize.width is set. | 
|  | if (Attrs.VectorizeEnable != LoopAttributes::Unspecified || | 
|  | IsVectorPredicateEnabled || | 
|  | Attrs.VectorizeWidth > 1 ) { | 
|  | bool AttrVal = Attrs.VectorizeEnable != LoopAttributes::Disable; | 
|  | Args.push_back( | 
|  | MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt1Ty(Ctx), AttrVal))})); | 
|  | } | 
|  |  | 
|  | if (FollowupHasTransforms) | 
|  | Args.push_back(MDNode::get( | 
|  | Ctx, | 
|  | {MDString::get(Ctx, "llvm.loop.vectorize.followup_all"), Followup})); | 
|  |  | 
|  | MDNode *LoopID = MDNode::get(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode * | 
|  | LoopInfo::createLoopDistributeMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.DistributeEnable == LoopAttributes::Disable) | 
|  | Enabled = false; | 
|  | if (Attrs.DistributeEnable == LoopAttributes::Enable) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | if (Enabled == false) { | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | NewLoopProperties.push_back( | 
|  | MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.distribute.enable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt1Ty(Ctx), 0))})); | 
|  | LoopProperties = NewLoopProperties; | 
|  | } | 
|  | return createLoopVectorizeMetadata(Attrs, LoopProperties, | 
|  | HasUserTransforms); | 
|  | } | 
|  |  | 
|  | bool FollowupHasTransforms = false; | 
|  | MDNode *Followup = | 
|  | createLoopVectorizeMetadata(Attrs, LoopProperties, FollowupHasTransforms); | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  |  | 
|  | Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"), | 
|  | ConstantAsMetadata::get(ConstantInt::get( | 
|  | llvm::Type::getInt1Ty(Ctx), | 
|  | (Attrs.DistributeEnable == LoopAttributes::Enable)))}; | 
|  | Args.push_back(MDNode::get(Ctx, Vals)); | 
|  |  | 
|  | if (FollowupHasTransforms) | 
|  | Args.push_back(MDNode::get( | 
|  | Ctx, | 
|  | {MDString::get(Ctx, "llvm.loop.distribute.followup_all"), Followup})); | 
|  |  | 
|  | MDNode *LoopID = MDNode::get(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode *LoopInfo::createFullUnrollMetadata(const LoopAttributes &Attrs, | 
|  | ArrayRef<Metadata *> LoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | Optional<bool> Enabled; | 
|  | if (Attrs.UnrollEnable == LoopAttributes::Disable) | 
|  | Enabled = false; | 
|  | else if (Attrs.UnrollEnable == LoopAttributes::Full) | 
|  | Enabled = true; | 
|  |  | 
|  | if (Enabled != true) { | 
|  | SmallVector<Metadata *, 4> NewLoopProperties; | 
|  | if (Enabled == false) { | 
|  | NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | NewLoopProperties.push_back( | 
|  | MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.disable"))); | 
|  | LoopProperties = NewLoopProperties; | 
|  | } | 
|  | return createLoopDistributeMetadata(Attrs, LoopProperties, | 
|  | HasUserTransforms); | 
|  | } | 
|  |  | 
|  | SmallVector<Metadata *, 4> Args; | 
|  | TempMDTuple TempNode = MDNode::getTemporary(Ctx, None); | 
|  | Args.push_back(TempNode.get()); | 
|  | Args.append(LoopProperties.begin(), LoopProperties.end()); | 
|  | Args.push_back(MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.unroll.full"))); | 
|  |  | 
|  | // No follow-up: there is no loop after full unrolling. | 
|  | // TODO: Warn if there are transformations after full unrolling. | 
|  |  | 
|  | MDNode *LoopID = MDNode::getDistinct(Ctx, Args); | 
|  | LoopID->replaceOperandWith(0, LoopID); | 
|  | HasUserTransforms = true; | 
|  | return LoopID; | 
|  | } | 
|  |  | 
|  | MDNode *LoopInfo::createMetadata( | 
|  | const LoopAttributes &Attrs, | 
|  | llvm::ArrayRef<llvm::Metadata *> AdditionalLoopProperties, | 
|  | bool &HasUserTransforms) { | 
|  | SmallVector<Metadata *, 3> LoopProperties; | 
|  |  | 
|  | // If we have a valid start debug location for the loop, add it. | 
|  | if (StartLoc) { | 
|  | LoopProperties.push_back(StartLoc.getAsMDNode()); | 
|  |  | 
|  | // If we also have a valid end debug location for the loop, add it. | 
|  | if (EndLoc) | 
|  | LoopProperties.push_back(EndLoc.getAsMDNode()); | 
|  | } | 
|  |  | 
|  | assert(!!AccGroup == Attrs.IsParallel && | 
|  | "There must be an access group iff the loop is parallel"); | 
|  | if (Attrs.IsParallel) { | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  | LoopProperties.push_back(MDNode::get( | 
|  | Ctx, {MDString::get(Ctx, "llvm.loop.parallel_accesses"), AccGroup})); | 
|  | } | 
|  |  | 
|  | LoopProperties.insert(LoopProperties.end(), AdditionalLoopProperties.begin(), | 
|  | AdditionalLoopProperties.end()); | 
|  | return createFullUnrollMetadata(Attrs, LoopProperties, HasUserTransforms); | 
|  | } | 
|  |  | 
|  | LoopAttributes::LoopAttributes(bool IsParallel) | 
|  | : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified), | 
|  | UnrollEnable(LoopAttributes::Unspecified), | 
|  | UnrollAndJamEnable(LoopAttributes::Unspecified), | 
|  | VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0), | 
|  | InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0), | 
|  | DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false), | 
|  | PipelineInitiationInterval(0) {} | 
|  |  | 
|  | void LoopAttributes::clear() { | 
|  | IsParallel = false; | 
|  | VectorizeWidth = 0; | 
|  | InterleaveCount = 0; | 
|  | UnrollCount = 0; | 
|  | UnrollAndJamCount = 0; | 
|  | VectorizeEnable = LoopAttributes::Unspecified; | 
|  | UnrollEnable = LoopAttributes::Unspecified; | 
|  | UnrollAndJamEnable = LoopAttributes::Unspecified; | 
|  | VectorizePredicateEnable = LoopAttributes::Unspecified; | 
|  | DistributeEnable = LoopAttributes::Unspecified; | 
|  | PipelineDisabled = false; | 
|  | PipelineInitiationInterval = 0; | 
|  | } | 
|  |  | 
|  | LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, | 
|  | const llvm::DebugLoc &StartLoc, const llvm::DebugLoc &EndLoc, | 
|  | LoopInfo *Parent) | 
|  | : Header(Header), Attrs(Attrs), StartLoc(StartLoc), EndLoc(EndLoc), | 
|  | Parent(Parent) { | 
|  |  | 
|  | if (Attrs.IsParallel) { | 
|  | // Create an access group for this loop. | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  | AccGroup = MDNode::getDistinct(Ctx, {}); | 
|  | } | 
|  |  | 
|  | if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 && | 
|  | Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 && | 
|  | Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled && | 
|  | Attrs.PipelineInitiationInterval == 0 && | 
|  | Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified && | 
|  | Attrs.VectorizeEnable == LoopAttributes::Unspecified && | 
|  | Attrs.UnrollEnable == LoopAttributes::Unspecified && | 
|  | Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified && | 
|  | Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc && | 
|  | !EndLoc) | 
|  | return; | 
|  |  | 
|  | TempLoopID = MDNode::getTemporary(Header->getContext(), None); | 
|  | } | 
|  |  | 
|  | void LoopInfo::finish() { | 
|  | // We did not annotate the loop body instructions because there are no | 
|  | // attributes for this loop. | 
|  | if (!TempLoopID) | 
|  | return; | 
|  |  | 
|  | MDNode *LoopID; | 
|  | LoopAttributes CurLoopAttr = Attrs; | 
|  | LLVMContext &Ctx = Header->getContext(); | 
|  |  | 
|  | if (Parent && (Parent->Attrs.UnrollAndJamEnable || | 
|  | Parent->Attrs.UnrollAndJamCount != 0)) { | 
|  | // Parent unroll-and-jams this loop. | 
|  | // Split the transformations in those that happens before the unroll-and-jam | 
|  | // and those after. | 
|  |  | 
|  | LoopAttributes BeforeJam, AfterJam; | 
|  |  | 
|  | BeforeJam.IsParallel = AfterJam.IsParallel = Attrs.IsParallel; | 
|  |  | 
|  | BeforeJam.VectorizeWidth = Attrs.VectorizeWidth; | 
|  | BeforeJam.InterleaveCount = Attrs.InterleaveCount; | 
|  | BeforeJam.VectorizeEnable = Attrs.VectorizeEnable; | 
|  | BeforeJam.DistributeEnable = Attrs.DistributeEnable; | 
|  | BeforeJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable; | 
|  |  | 
|  | switch (Attrs.UnrollEnable) { | 
|  | case LoopAttributes::Unspecified: | 
|  | case LoopAttributes::Disable: | 
|  | BeforeJam.UnrollEnable = Attrs.UnrollEnable; | 
|  | AfterJam.UnrollEnable = Attrs.UnrollEnable; | 
|  | break; | 
|  | case LoopAttributes::Full: | 
|  | BeforeJam.UnrollEnable = LoopAttributes::Full; | 
|  | break; | 
|  | case LoopAttributes::Enable: | 
|  | AfterJam.UnrollEnable = LoopAttributes::Enable; | 
|  | break; | 
|  | } | 
|  |  | 
|  | AfterJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable; | 
|  | AfterJam.UnrollCount = Attrs.UnrollCount; | 
|  | AfterJam.PipelineDisabled = Attrs.PipelineDisabled; | 
|  | AfterJam.PipelineInitiationInterval = Attrs.PipelineInitiationInterval; | 
|  |  | 
|  | // If this loop is subject of an unroll-and-jam by the parent loop, and has | 
|  | // an unroll-and-jam annotation itself, we have to decide whether to first | 
|  | // apply the parent's unroll-and-jam or this loop's unroll-and-jam. The | 
|  | // UnrollAndJam pass processes loops from inner to outer, so we apply the | 
|  | // inner first. | 
|  | BeforeJam.UnrollAndJamCount = Attrs.UnrollAndJamCount; | 
|  | BeforeJam.UnrollAndJamEnable = Attrs.UnrollAndJamEnable; | 
|  |  | 
|  | // Set the inner followup metadata to process by the outer loop. Only | 
|  | // consider the first inner loop. | 
|  | if (!Parent->UnrollAndJamInnerFollowup) { | 
|  | // Splitting the attributes into a BeforeJam and an AfterJam part will | 
|  | // stop 'llvm.loop.isvectorized' (generated by vectorization in BeforeJam) | 
|  | // to be forwarded to the AfterJam part. We detect the situation here and | 
|  | // add it manually. | 
|  | SmallVector<Metadata *, 1> BeforeLoopProperties; | 
|  | if (BeforeJam.VectorizeEnable != LoopAttributes::Unspecified || | 
|  | BeforeJam.VectorizePredicateEnable != LoopAttributes::Unspecified || | 
|  | BeforeJam.InterleaveCount != 0 || BeforeJam.VectorizeWidth != 0) | 
|  | BeforeLoopProperties.push_back( | 
|  | MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized"))); | 
|  |  | 
|  | bool InnerFollowupHasTransform = false; | 
|  | MDNode *InnerFollowup = createMetadata(AfterJam, BeforeLoopProperties, | 
|  | InnerFollowupHasTransform); | 
|  | if (InnerFollowupHasTransform) | 
|  | Parent->UnrollAndJamInnerFollowup = InnerFollowup; | 
|  | } | 
|  |  | 
|  | CurLoopAttr = BeforeJam; | 
|  | } | 
|  |  | 
|  | bool HasUserTransforms = false; | 
|  | LoopID = createMetadata(CurLoopAttr, {}, HasUserTransforms); | 
|  | TempLoopID->replaceAllUsesWith(LoopID); | 
|  | } | 
|  |  | 
|  | void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc, | 
|  | const llvm::DebugLoc &EndLoc) { | 
|  | Active.emplace_back( | 
|  | new LoopInfo(Header, StagedAttrs, StartLoc, EndLoc, | 
|  | Active.empty() ? nullptr : Active.back().get())); | 
|  | // Clear the attributes so nested loops do not inherit them. | 
|  | StagedAttrs.clear(); | 
|  | } | 
|  |  | 
|  | void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, | 
|  | const clang::CodeGenOptions &CGOpts, | 
|  | ArrayRef<const clang::Attr *> Attrs, | 
|  | const llvm::DebugLoc &StartLoc, | 
|  | const llvm::DebugLoc &EndLoc) { | 
|  |  | 
|  | // Identify loop hint attributes from Attrs. | 
|  | for (const auto *Attr : Attrs) { | 
|  | const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr); | 
|  | const OpenCLUnrollHintAttr *OpenCLHint = | 
|  | dyn_cast<OpenCLUnrollHintAttr>(Attr); | 
|  |  | 
|  | // Skip non loop hint attributes | 
|  | if (!LH && !OpenCLHint) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | LoopHintAttr::OptionType Option = LoopHintAttr::Unroll; | 
|  | LoopHintAttr::LoopHintState State = LoopHintAttr::Disable; | 
|  | unsigned ValueInt = 1; | 
|  | // Translate opencl_unroll_hint attribute argument to | 
|  | // equivalent LoopHintAttr enums. | 
|  | // OpenCL v2.0 s6.11.5: | 
|  | // 0 - enable unroll (no argument). | 
|  | // 1 - disable unroll. | 
|  | // other positive integer n - unroll by n. | 
|  | if (OpenCLHint) { | 
|  | ValueInt = OpenCLHint->getUnrollHint(); | 
|  | if (ValueInt == 0) { | 
|  | State = LoopHintAttr::Enable; | 
|  | } else if (ValueInt != 1) { | 
|  | Option = LoopHintAttr::UnrollCount; | 
|  | State = LoopHintAttr::Numeric; | 
|  | } | 
|  | } else if (LH) { | 
|  | auto *ValueExpr = LH->getValue(); | 
|  | if (ValueExpr) { | 
|  | llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx); | 
|  | ValueInt = ValueAPS.getSExtValue(); | 
|  | } | 
|  |  | 
|  | Option = LH->getOption(); | 
|  | State = LH->getState(); | 
|  | } | 
|  | switch (State) { | 
|  | case LoopHintAttr::Disable: | 
|  | switch (Option) { | 
|  | case LoopHintAttr::Vectorize: | 
|  | // Disable vectorization by specifying a width of 1. | 
|  | setVectorizeWidth(1); | 
|  | break; | 
|  | case LoopHintAttr::Interleave: | 
|  | // Disable interleaving by speciyfing a count of 1. | 
|  | setInterleaveCount(1); | 
|  | break; | 
|  | case LoopHintAttr::Unroll: | 
|  | setUnrollState(LoopAttributes::Disable); | 
|  | break; | 
|  | case LoopHintAttr::UnrollAndJam: | 
|  | setUnrollAndJamState(LoopAttributes::Disable); | 
|  | break; | 
|  | case LoopHintAttr::VectorizePredicate: | 
|  | setVectorizePredicateState(LoopAttributes::Disable); | 
|  | break; | 
|  | case LoopHintAttr::Distribute: | 
|  | setDistributeState(false); | 
|  | break; | 
|  | case LoopHintAttr::PipelineDisabled: | 
|  | setPipelineDisabled(true); | 
|  | break; | 
|  | case LoopHintAttr::UnrollCount: | 
|  | case LoopHintAttr::UnrollAndJamCount: | 
|  | case LoopHintAttr::VectorizeWidth: | 
|  | case LoopHintAttr::InterleaveCount: | 
|  | case LoopHintAttr::PipelineInitiationInterval: | 
|  | llvm_unreachable("Options cannot be disabled."); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case LoopHintAttr::Enable: | 
|  | switch (Option) { | 
|  | case LoopHintAttr::Vectorize: | 
|  | case LoopHintAttr::Interleave: | 
|  | setVectorizeEnable(true); | 
|  | break; | 
|  | case LoopHintAttr::Unroll: | 
|  | setUnrollState(LoopAttributes::Enable); | 
|  | break; | 
|  | case LoopHintAttr::UnrollAndJam: | 
|  | setUnrollAndJamState(LoopAttributes::Enable); | 
|  | break; | 
|  | case LoopHintAttr::VectorizePredicate: | 
|  | setVectorizePredicateState(LoopAttributes::Enable); | 
|  | break; | 
|  | case LoopHintAttr::Distribute: | 
|  | setDistributeState(true); | 
|  | break; | 
|  | case LoopHintAttr::UnrollCount: | 
|  | case LoopHintAttr::UnrollAndJamCount: | 
|  | case LoopHintAttr::VectorizeWidth: | 
|  | case LoopHintAttr::InterleaveCount: | 
|  | case LoopHintAttr::PipelineDisabled: | 
|  | case LoopHintAttr::PipelineInitiationInterval: | 
|  | llvm_unreachable("Options cannot enabled."); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case LoopHintAttr::AssumeSafety: | 
|  | switch (Option) { | 
|  | case LoopHintAttr::Vectorize: | 
|  | case LoopHintAttr::Interleave: | 
|  | // Apply "llvm.mem.parallel_loop_access" metadata to load/stores. | 
|  | setParallel(true); | 
|  | setVectorizeEnable(true); | 
|  | break; | 
|  | case LoopHintAttr::Unroll: | 
|  | case LoopHintAttr::UnrollAndJam: | 
|  | case LoopHintAttr::VectorizePredicate: | 
|  | case LoopHintAttr::UnrollCount: | 
|  | case LoopHintAttr::UnrollAndJamCount: | 
|  | case LoopHintAttr::VectorizeWidth: | 
|  | case LoopHintAttr::InterleaveCount: | 
|  | case LoopHintAttr::Distribute: | 
|  | case LoopHintAttr::PipelineDisabled: | 
|  | case LoopHintAttr::PipelineInitiationInterval: | 
|  | llvm_unreachable("Options cannot be used to assume mem safety."); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case LoopHintAttr::Full: | 
|  | switch (Option) { | 
|  | case LoopHintAttr::Unroll: | 
|  | setUnrollState(LoopAttributes::Full); | 
|  | break; | 
|  | case LoopHintAttr::UnrollAndJam: | 
|  | setUnrollAndJamState(LoopAttributes::Full); | 
|  | break; | 
|  | case LoopHintAttr::Vectorize: | 
|  | case LoopHintAttr::Interleave: | 
|  | case LoopHintAttr::UnrollCount: | 
|  | case LoopHintAttr::UnrollAndJamCount: | 
|  | case LoopHintAttr::VectorizeWidth: | 
|  | case LoopHintAttr::InterleaveCount: | 
|  | case LoopHintAttr::Distribute: | 
|  | case LoopHintAttr::PipelineDisabled: | 
|  | case LoopHintAttr::PipelineInitiationInterval: | 
|  | case LoopHintAttr::VectorizePredicate: | 
|  | llvm_unreachable("Options cannot be used with 'full' hint."); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case LoopHintAttr::Numeric: | 
|  | switch (Option) { | 
|  | case LoopHintAttr::VectorizeWidth: | 
|  | setVectorizeWidth(ValueInt); | 
|  | break; | 
|  | case LoopHintAttr::InterleaveCount: | 
|  | setInterleaveCount(ValueInt); | 
|  | break; | 
|  | case LoopHintAttr::UnrollCount: | 
|  | setUnrollCount(ValueInt); | 
|  | break; | 
|  | case LoopHintAttr::UnrollAndJamCount: | 
|  | setUnrollAndJamCount(ValueInt); | 
|  | break; | 
|  | case LoopHintAttr::PipelineInitiationInterval: | 
|  | setPipelineInitiationInterval(ValueInt); | 
|  | break; | 
|  | case LoopHintAttr::Unroll: | 
|  | case LoopHintAttr::UnrollAndJam: | 
|  | case LoopHintAttr::VectorizePredicate: | 
|  | case LoopHintAttr::Vectorize: | 
|  | case LoopHintAttr::Interleave: | 
|  | case LoopHintAttr::Distribute: | 
|  | case LoopHintAttr::PipelineDisabled: | 
|  | llvm_unreachable("Options cannot be assigned a value."); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (CGOpts.OptimizationLevel > 0) | 
|  | // Disable unrolling for the loop, if unrolling is disabled (via | 
|  | // -fno-unroll-loops) and no pragmas override the decision. | 
|  | if (!CGOpts.UnrollLoops && | 
|  | (StagedAttrs.UnrollEnable == LoopAttributes::Unspecified && | 
|  | StagedAttrs.UnrollCount == 0)) | 
|  | setUnrollState(LoopAttributes::Disable); | 
|  |  | 
|  | /// Stage the attributes. | 
|  | push(Header, StartLoc, EndLoc); | 
|  | } | 
|  |  | 
|  | void LoopInfoStack::pop() { | 
|  | assert(!Active.empty() && "No active loops to pop"); | 
|  | Active.back()->finish(); | 
|  | Active.pop_back(); | 
|  | } | 
|  |  | 
|  | void LoopInfoStack::InsertHelper(Instruction *I) const { | 
|  | if (I->mayReadOrWriteMemory()) { | 
|  | SmallVector<Metadata *, 4> AccessGroups; | 
|  | for (const auto &AL : Active) { | 
|  | // Here we assume that every loop that has an access group is parallel. | 
|  | if (MDNode *Group = AL->getAccessGroup()) | 
|  | AccessGroups.push_back(Group); | 
|  | } | 
|  | MDNode *UnionMD = nullptr; | 
|  | if (AccessGroups.size() == 1) | 
|  | UnionMD = cast<MDNode>(AccessGroups[0]); | 
|  | else if (AccessGroups.size() >= 2) | 
|  | UnionMD = MDNode::get(I->getContext(), AccessGroups); | 
|  | I->setMetadata("llvm.access.group", UnionMD); | 
|  | } | 
|  |  | 
|  | if (!hasInfo()) | 
|  | return; | 
|  |  | 
|  | const LoopInfo &L = getInfo(); | 
|  | if (!L.getLoopID()) | 
|  | return; | 
|  |  | 
|  | if (I->isTerminator()) { | 
|  | for (BasicBlock *Succ : successors(I)) | 
|  | if (Succ == L.getHeader()) { | 
|  | I->setMetadata(llvm::LLVMContext::MD_loop, L.getLoopID()); | 
|  | break; | 
|  | } | 
|  | return; | 
|  | } | 
|  | } |