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 * 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 8400b57cec5SDimitry 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