Index: llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -84,6 +84,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/IRBuilder.h" @@ -5846,87 +5847,372 @@ AU.addPreserved(); } -using EqualValues = SmallVector, 4>; -using EqualValuesMap = - DenseMap>>; -using LocationMap = - DenseMap>; +struct SCEVDbgBuilder { + SCEVDbgBuilder(){}; + SCEVDbgBuilder(const SCEVDbgBuilder &Base) { + Values = Base.Values; + Expr = Base.Expr; + } + + /// The DIExpression as we translate the SCEV. + SmallVector Expr; + /// The location ops of the DIExpression. + SmallVector Values; + + void pushOperator(uint64_t Op) { Expr.push_back(Op); } + void pushUInt(uint64_t Operand) { Expr.push_back(Operand); } + + /// Add a DW_OP_LLVM_arg to the expression, followed by the index of the value + /// in the set of values referenced by the expression. + void pushValue(llvm::Value *V) { + Expr.push_back(llvm::dwarf::DW_OP_LLVM_arg); + auto It = + std::find(Values.begin(), Values.end(), llvm::ValueAsMetadata::get(V)); + unsigned ArgIndex = 0; + if (It != Values.end()) { + ArgIndex = std::distance(Values.begin(), It); + } else { + ArgIndex = Values.size(); + Values.push_back(llvm::ValueAsMetadata::get(V)); + } + Expr.push_back(ArgIndex); + } + + void pushValue(const SCEVUnknown *U) { + llvm::Value *V = cast(U)->getValue(); + pushValue(V); + } + + void pushConst(const SCEVConstant *C) { + Expr.push_back(llvm::dwarf::DW_OP_consts); + Expr.push_back(C->getAPInt().getSExtValue()); + } + + /// Several SCEV types are sequences of the same arithmetic operator applied + /// to constants and values that may be extended or truncated. + bool pushArithmeticExpr(const llvm::SCEVCommutativeExpr *CommExpr, + uint64_t DwarfOp) { + assert((isa(CommExpr) || isa(CommExpr)) && + "Expected arithmetic SCEV type"); + bool Success = true; + unsigned EmitOperator = 0; + for (auto &Op : CommExpr->operands()) { + Success &= pushSCEV(Op); + + if (EmitOperator >= 1) + pushOperator(DwarfOp); + EmitOperator++; + } + return Success; + } + + // TODO: Identify and omit noop casts. + bool pushCastImpl(const llvm::SCEVCastExpr *C, bool IsSigned) { + const llvm::SCEV *Inner = C->getOperand(0); + const llvm::Type *Type = C->getType(); + uint64_t ToWidth = Type->getIntegerBitWidth(); + uint64_t CastOps[] = {dwarf::DW_OP_LLVM_convert, ToWidth, + IsSigned ? llvm::dwarf::DW_ATE_signed + : llvm::dwarf::DW_ATE_unsigned}; + for (auto Op : CastOps) + pushOperator(Op); + + bool Success = true; + if (const llvm::SCEVUnknown *U = dyn_cast(Inner)) { + pushValue(cast(U)->getValue()); + } else if (const SCEVConstant *C = dyn_cast(Inner)) { + pushUInt(C->getAPInt().trunc(ToWidth).getZExtValue()); + } else { + Success &= pushSCEV(Inner); + } + return Success; + } + + bool pushCast(const llvm::SCEVCastExpr *Cast) { + bool Success = true; + if (isa(Cast) || isa(Cast) || + isa(Cast) || isa(Cast)) + Success &= pushCastImpl(Cast, (isa(Cast))); + else + llvm_unreachable("Unrecognised SCEVCastExpr type."); + + return Success; + } + + // TODO: MinMax - although these haven't been encountered in the test suite. + bool pushSCEV(const llvm::SCEV *S) { + bool Success = true; + if (const SCEVConstant *StartInt = dyn_cast(S)) { + pushConst(StartInt); + + } else if (const SCEVUnknown *U = dyn_cast(S)) { + pushValue(U->getValue()); + + } else if (const SCEVMulExpr *MulRec = dyn_cast(S)) { + Success &= pushArithmeticExpr(MulRec, llvm::dwarf::DW_OP_mul); + + } else if (const SCEVUDivExpr *UDiv = dyn_cast(S)) { + Success &= pushSCEV(UDiv->getLHS()); + Success &= pushSCEV(UDiv->getRHS()); + pushOperator(llvm::dwarf::DW_OP_div); + + } else if (const SCEVCastExpr *Cast = dyn_cast(S)) { + Success &= pushCast(Cast); + + } else if (const SCEVAddExpr *AddExpr = dyn_cast(S)) { + pushArithmeticExpr(AddExpr, llvm::dwarf::DW_OP_plus); + + } else if (const SCEVAddRecExpr *InnerRec = dyn_cast(S)) { + // Nested SCEVAddRecExpr are generated by nested loops and are currently + // unsupported. + return false; + + } else { + return false; + } + return Success; + } + + void setFinalExpression(llvm::DbgValueInst &DI, const DIExpression *OldExpr) { + // Re-state assumption that this dbg.value is not variadic. Any remaining + // opcodes in its expression operate on a single value already on the + // expression stack. Prepend our operations, which will re-compute and + // place that value on the expression stack. + assert(!DI.hasArgList()); + auto *NewExpr = + DIExpression::prependOpcodes(OldExpr, Expr, /*StackValue*/ true); + DI.setExpression(NewExpr); + + auto ValArrayRef = llvm::ArrayRef(Values); + DI.setRawLocation(llvm::DIArgList::get(DI.getContext(), ValArrayRef)); + } + + /// If a DVI can be emitted without a DIArgList, omit DW_OP_llvm_arg and the + /// location op index 0. + void setShortFinalExpression(llvm::DbgValueInst &DI, const DIExpression *OldExpr) { + assert((Expr[0] == llvm::dwarf::DW_OP_LLVM_arg && Expr[1] == 0) && + "Expected DW_OP_llvm_arg and 0."); + DI.replaceVariableLocationOp( + 0u, llvm::MetadataAsValue::get(DI.getContext(), Values[0])); + + // See setFinalExpression: prepend our opcodes on the start of any old + // expression opcodes. + assert(!DI.hasArgList()); + llvm::SmallVector FinalExpr(Expr.begin() + 2, Expr.end()); + auto *NewExpr = + DIExpression::prependOpcodes(OldExpr, FinalExpr, /*StackValue*/ true); + DI.setExpression(NewExpr); + } + + /// Once the IV and variable SCEV translation is complete, write it to the + /// source DVI. + void applyExprToDbgValue(llvm::DbgValueInst &DI, const DIExpression *OldExpr) { + assert(!Expr.empty() && "Unexpected empty expression."); + // Emit a simpler form if only a single location is referenced. + if (Values.size() == 1 && Expr[0] == llvm::dwarf::DW_OP_LLVM_arg && + Expr[1] == 0) { + setShortFinalExpression(DI, OldExpr); + } else { + setFinalExpression(DI, OldExpr); + } + } + + /// Return true if the combination of arithmetic operator and underlying + /// SCEV constant value is an identity function. + bool isIdentityFunction(uint64_t Op, const SCEV *S) { + if (const SCEVConstant *C = dyn_cast(S)) { + int64_t I = C->getAPInt().getSExtValue(); + switch (Op) { + case llvm::dwarf::DW_OP_plus: + case llvm::dwarf::DW_OP_minus: + return I == 0; + case llvm::dwarf::DW_OP_mul: + case llvm::dwarf::DW_OP_div: + return I == 1; + } + } + return false; + } + + /// Convert a SCEV of a value to a DIExpression that is pushed onto the + /// builder's expression stack. The stack should already contain an + /// expression for the iteration count, so that it can be multiplied by + /// the stride and added to the start. + /// Components of the expression are omitted if they are an identity function. + /// Chain (non-affine) SCEVs are not supported. + bool SCEVToValueExpr(const llvm::SCEVAddRecExpr &SAR, ScalarEvolution &SE) { + assert(SAR.isAffine() && "Expected affine SCEV"); + // TODO: Is this check needed? + if (isa(SAR.getStart())) + return false; + + const SCEV *Start = SAR.getStart(); + const SCEV *Stride = SAR.getStepRecurrence(SE); + + // Skip pushing arithmetic noops. + if (!isIdentityFunction(llvm::dwarf::DW_OP_mul, Stride)) { + if (!pushSCEV(Stride)) + return false; + pushOperator(llvm::dwarf::DW_OP_mul); + } + if (!isIdentityFunction(llvm::dwarf::DW_OP_plus, Start)) { + if (!pushSCEV(Start)) + return false; + pushOperator(llvm::dwarf::DW_OP_plus); + } + return true; + } + + /// Convert a SCEV of a value to a DIExpression that is pushed onto the + /// builder's expression stack. The stack should already contain an + /// expression for the iteration count, so that it can be multiplied by + /// the stride and added to the start. + /// Components of the expression are omitted if they are an identity function. + bool SCEVToIterCountExpr(const llvm::SCEVAddRecExpr &SAR, + ScalarEvolution &SE) { + assert(SAR.isAffine() && "Expected affine SCEV"); + if (const auto *Start = dyn_cast(SAR.getStart())) { + LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV. Unsupported nested AddRec: " + << SAR << '\n'); + return false; + } + const SCEV *Start = SAR.getStart(); + const SCEV *Stride = SAR.getStepRecurrence(SE); + + // Skip pushing arithmetic noops. + if (!isIdentityFunction(llvm::dwarf::DW_OP_minus, Start)) { + if (!pushSCEV(Start)) + return false; + pushOperator(llvm::dwarf::DW_OP_minus); + } + if (!isIdentityFunction(llvm::dwarf::DW_OP_div, Stride)) { + if (!pushSCEV(Stride)) + return false; + pushOperator(llvm::dwarf::DW_OP_div); + } + return true; + } +}; + +struct DVIRecoveryRec { + DbgValueInst *DVI; + DIExpression *Expr; + Metadata *LocationOp; + const llvm::SCEV *SCEV; +}; + +static bool RewriteDVIUsingIterCount(DVIRecoveryRec CachedDVI, + SCEVDbgBuilder &IterationCount, + ScalarEvolution &SE) { + assert(CachedDVI.DVI->getNumVariableLocationOps() == 1 && + "Expected only one location op."); + + // SCEVs for SSA values are most frquently of the form + // {start,+,stride}, but sometimes they are ({start,+,stride} + %a + ..). + // This is because %a is a PHI node that is not the IV. However, these + // SCEVs have not been observed to result in debuginfo-lossy optimisations, + // so its not expected this point will be reached. + if (!isa(CachedDVI.SCEV)) + return false; + + LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: " + << *CachedDVI.SCEV << '\n'); + + const auto *Rec = cast(CachedDVI.SCEV); + if (!Rec->isAffine()) + return false; + + // Initialise a new builder with the iteration count expression. In + // combination with the value's SCEV this enables recovery. + SCEVDbgBuilder RecoverValue(IterationCount); + if (!RecoverValue.SCEVToValueExpr(*Rec, SE)) + return false; + + + LLVM_DEBUG(dbgs() << "scev-salvage: Updating: " << *CachedDVI.DVI << '\n'); + RecoverValue.applyExprToDbgValue(*CachedDVI.DVI, CachedDVI.Expr); + LLVM_DEBUG(dbgs() << "scev-salvage: to: " << *CachedDVI.DVI << '\n'); + return true; +} + +static bool +DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE, + llvm::PHINode *LSRInductionVar, + SmallVector &DVIToUpdate) { + if (DVIToUpdate.empty()) + return false; + + const llvm::SCEV *SCEVInductionVar = SE.getSCEV(LSRInductionVar); + assert(SCEVInductionVar && + "Anticipated a SCEV for the post-LSR induction variable"); + + bool Changed = false; + if (const SCEVAddRecExpr *IVAddRec = + dyn_cast(SCEVInductionVar)) { + + SCEVDbgBuilder IterCountExpr; + IterCountExpr.pushValue(LSRInductionVar); + if (!IterCountExpr.SCEVToIterCountExpr(*IVAddRec, SE)) + return false; + + LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV: " << *SCEVInductionVar + << '\n'); -static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE, - EqualValuesMap &DbgValueToEqualSet, - LocationMap &DbgValueToLocation) { + // Needn't salvage if the location op hasn't been undef'd by LSR. + for (auto &DVIRec : DVIToUpdate) { + if (!DVIRec.DVI->isUndef()) + continue; + + Changed |= RewriteDVIUsingIterCount(DVIRec, IterCountExpr, SE); + } + } + return Changed; +} + +/// Identify and cache salvageable DVI locations and expressions along with the +/// corresponding SCEV(s). Also ensure that the DVI is not deleted before +static void +DbgGatherSalvagableDVI(Loop *L, ScalarEvolution &SE, + SmallVector &SalvageableDVISCEVs, + SmallSet, 2> &DVIHandles) { for (auto &B : L->getBlocks()) { for (auto &I : *B) { auto DVI = dyn_cast(&I); - if (!DVI) + if (!DVI || DVI->hasArgList() || + !SE.isSCEVable(DVI->getVariableLocationOp(0)->getType())) continue; - for (unsigned Idx = 0; Idx < DVI->getNumVariableLocationOps(); ++Idx) { - // TODO: We can duplicate results if the same arg appears more than - // once. - Value *V = DVI->getVariableLocationOp(Idx); - if (!V || !SE.isSCEVable(V->getType())) - continue; - auto DbgValueSCEV = SE.getSCEV(V); - EqualValues EqSet; - for (PHINode &Phi : L->getHeader()->phis()) { - if (V->getType() != Phi.getType()) - continue; - if (!SE.isSCEVable(Phi.getType())) - continue; - auto PhiSCEV = SE.getSCEV(&Phi); - Optional Offset = - SE.computeConstantDifference(DbgValueSCEV, PhiSCEV); - if (Offset && Offset->getMinSignedBits() <= 64) - EqSet.emplace_back( - std::make_tuple(&Phi, Offset.getValue().getSExtValue())); - } - DbgValueToEqualSet[DVI].push_back({Idx, std::move(EqSet)}); - // If we fall back to using this raw location, at least one location op - // must be dead. A DIArgList will automatically undef arguments when - // they become unavailable, but a ValueAsMetadata will not; since we - // know the value should be undef, we use the undef value directly here. - Metadata *RawLocation = - DVI->hasArgList() ? DVI->getRawLocation() - : ValueAsMetadata::get(UndefValue::get( - DVI->getVariableLocationOp(0)->getType())); - DbgValueToLocation[DVI] = {DVI->getExpression(), RawLocation}; - } + + SalvageableDVISCEVs.push_back( + {DVI, DVI->getExpression(), DVI->getRawLocation(), + SE.getSCEV(DVI->getVariableLocationOp(0))}); + DVIHandles.insert(DVI); } } } -static void DbgApplyEqualValues(EqualValuesMap &DbgValueToEqualSet, - LocationMap &DbgValueToLocation) { - for (auto A : DbgValueToEqualSet) { - auto *DVI = A.first; - // Only update those that are now undef. - if (!DVI->isUndef()) +/// Sometimes Loop's methods for returning an IV fail. Provide a backup. +static llvm::PHINode *GetInductionVariable(const Loop &L, ScalarEvolution &SE) { + llvm::PHINode *IV = (L.getInductionVariable(SE) == nullptr) + ? L.getCanonicalInductionVariable() + : L.getInductionVariable(SE); + if (IV) + return IV; + + for (PHINode &Phi : L.getHeader()->phis()) { + if (!SE.isSCEVable(Phi.getType())) { continue; - // The dbg.value may have had its value or expression changed during LSR by - // a failed salvage attempt; refresh them from the map. - auto *DbgDIExpr = DbgValueToLocation[DVI].first; - DVI->setRawLocation(DbgValueToLocation[DVI].second); - DVI->setExpression(DbgDIExpr); - assert(DVI->isUndef() && "dbg.value with non-undef location should not " - "have been modified by LSR."); - for (auto IdxEV : A.second) { - unsigned Idx = IdxEV.first; - for (auto EV : IdxEV.second) { - auto EVHandle = std::get(EV); - if (!EVHandle) - continue; - int64_t Offset = std::get(EV); - DVI->replaceVariableLocationOp(Idx, EVHandle); - if (Offset) { - SmallVector Ops; - DIExpression::appendOffset(Ops, Offset); - DbgDIExpr = DIExpression::appendOpsToArg(DbgDIExpr, Ops, Idx, true); - } - DVI->setExpression(DbgDIExpr); - break; - } } + const llvm::SCEV *PhiSCEV = SE.getSCEV(&Phi); + if (const llvm::SCEVAddRecExpr *Rec = dyn_cast(PhiSCEV)) { + if (!Rec->isAffine()) + continue; + } + + LLVM_DEBUG(dbgs() << "scev-salvage: Manually selected an IV: " << Phi + << " with SCEV: " << *PhiSCEV << "\n"); + return Φ } + return nullptr; } static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE, @@ -5935,6 +6221,12 @@ AssumptionCache &AC, TargetLibraryInfo &TLI, MemorySSA *MSSA) { + // Debug preservation - before we start removing anything identify which DVI + // meet the salvageable criteria and store their DIExpression and SCEVs. + SmallVector SalvageableDVI; + SmallSet, 2> DVIHandles; + DbgGatherSalvagableDVI(L, SE, SalvageableDVI, DVIHandles); + bool Changed = false; std::unique_ptr MSSAU; if (MSSA) @@ -5944,12 +6236,6 @@ Changed |= LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged(); - // Debug preservation - before we start removing anything create equivalence - // sets for the llvm.dbg.value intrinsics. - EqualValuesMap DbgValueToEqualSet; - LocationMap DbgValueToLocation; - DbgGatherEqualValues(L, SE, DbgValueToEqualSet, DbgValueToLocation); - // Remove any extra phis created by processing inner loops. Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get()); if (EnablePhiElim && L->isLoopSimplifyForm()) { @@ -5968,8 +6254,20 @@ } } - DbgApplyEqualValues(DbgValueToEqualSet, DbgValueToLocation); - + if (SalvageableDVI.empty()) + return Changed; + // Obtain relevant IVs and attempt to rewrite the salvageable DVIs in terms + // of the IVs. + // TODO: Allow for multiple IV references for nested AddRecSCEVs + for (auto &L : LI) { + if (llvm::PHINode *IV = GetInductionVariable(*L, SE)) + DbgRewriteSalvageableDVIs(L, SE, IV, SalvageableDVI); + else { + LLVM_DEBUG(dbgs() << "scev-salvage: SCEV salvaging not possible. An IV " + "could not be identified.\n"); + } + } + DVIHandles.empty(); return Changed; } Index: llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll +++ llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-0.ll @@ -21,11 +21,11 @@ call void @llvm.dbg.value(metadata i8 %i.06, metadata !14, metadata !DIExpression()), !dbg !17 call void @llvm.dbg.value(metadata i8* %p.addr.05, metadata !13, metadata !DIExpression()), !dbg !16 ; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef -; CHECK: call void @llvm.dbg.value(metadata i8* %lsr.iv, metadata ![[MID_p:[0-9]+]], metadata !DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value)), !dbg !16 +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i8* %lsr.iv, i8* %p), metadata ![[MID_p:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 3, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_minus, DW_OP_consts, 3, DW_OP_div, DW_OP_consts, 3, DW_OP_mul, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)) %add.ptr = getelementptr inbounds i8, i8* %p.addr.05, i64 3, !dbg !20 call void @llvm.dbg.value(metadata i8* %add.ptr, metadata !13, metadata !DIExpression()), !dbg !16 ; CHECK-NOT: call void @llvm.dbg.value(metadata i8* undef -; CHECK: call void @llvm.dbg.value(metadata i8* %lsr.iv, metadata ![[MID_p]], metadata !DIExpression()), !dbg !16 +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i8* %lsr.iv, i8* %p), metadata ![[MID_p]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 3, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_minus, DW_OP_consts, 3, DW_OP_div, DW_OP_consts, 3, DW_OP_mul, DW_OP_consts, 3, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_plus, DW_OP_stack_value)) store i8 %i.06, i8* %add.ptr, align 1, !dbg !23, !tbaa !24 %inc = add nuw nsw i8 %i.06, 1, !dbg !27 call void @llvm.dbg.value(metadata i8 %inc, metadata !14, metadata !DIExpression()), !dbg !17 Index: llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll =================================================================== --- llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll +++ llvm/test/Transforms/LoopStrengthReduce/dbg-preserve-2.ll @@ -2,7 +2,7 @@ ; Test that LSR does not produce invalid debug info when a debug value is ; salvaged during LSR by adding additional location operands, then becomes -; undef, and finally recovered by using equal values gathered before LSR. +; undef, and finally recovered by SCEV salvaging. target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" @@ -20,7 +20,7 @@ %Result.addr.0 = phi i32 [ %Result, %entry ], [ %or, %do.body ] %Itr.0 = phi i32 [ 0, %entry ], [ %add, %do.body ], !dbg !17 ; CHECK-NOT: call void @llvm.dbg.value(metadata !DIArgList -; CHECK: call void @llvm.dbg.value(metadata i32 %lsr.iv, metadata ![[VAR_ITR:[0-9]+]], metadata !DIExpression() +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i32 %lsr.iv, i32 %Step), metadata ![[VAR_ITR:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_minus, DW_OP_LLVM_arg, 1, DW_OP_div, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)) call void @llvm.dbg.value(metadata i32 %Itr.0, metadata !16, metadata !DIExpression()), !dbg !17 call void @llvm.dbg.value(metadata i32 %Result.addr.0, metadata !12, metadata !DIExpression()), !dbg !17 %add = add nsw i32 %Itr.0, %Step, !dbg !19 Index: llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-0.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-0.ll @@ -0,0 +1,91 @@ +; RUN: opt -S -loop-reduce %s -o - | FileCheck %s +;; Ensure that we retain debuginfo for the induction variable and dependant +;; variables when loop strength reduction is applied to the loop. +;; This IR produced from: +;; +;; clang -S -emit-llvm -Xclang -disable-llvm-passes -g lsr-basic.cpp -o +;; Then executing opt -O2 up to the the loopFullUnroll pass. +;; void mul_pow_of_2_to_shift(unsigned size, unsigned *data) { +;; unsigned i = 0; +;; #pragma clang loop vectorize(disable) +;; while (i < size) { +;; unsigned comp = i * 8; +;; data[i] = comp; +;; i++; // DexLabel('mul_pow_of_2_induction_increment') +;; } +;; } +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i:[0-9]+]], metadata !DIExpression(DW_OP_consts, 8, DW_OP_div, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[comp:[0-9]+]], metadata !DIExpression(DW_OP_consts, 8, DW_OP_div, DW_OP_consts, 8, DW_OP_mul, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i]], metadata !DIExpression(DW_OP_consts, 8, DW_OP_div, DW_OP_consts, 1, DW_OP_plus, DW_OP_stack_value)) +; CHECK: ![[i]] = !DILocalVariable(name: "i" +; CHECK: ![[comp]] = !DILocalVariable(name: "comp" + +source_filename = "./llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-0.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local void @_Z21mul_pow_of_2_to_shiftjPj(i32 %size, i32* nocapture %data) local_unnamed_addr !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %size, metadata !12, metadata !DIExpression()), !dbg !13 + call void @llvm.dbg.value(metadata i32* %data, metadata !14, metadata !DIExpression()), !dbg !13 + call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression()), !dbg !13 + %cmp4.not = icmp eq i32 %size, 0, !dbg !13 + br i1 %cmp4.not, label %while.end, label %while.body.preheader, !dbg !13 + +while.body.preheader: ; preds = %entry + %wide.trip.count = zext i32 %size to i64, !dbg !13 + br label %while.body, !dbg !13 + +while.body: ; preds = %while.body, %while.body.preheader + %indvars.iv = phi i64 [ 0, %while.body.preheader ], [ %indvars.iv.next, %while.body ] + call void @llvm.dbg.value(metadata i64 %indvars.iv, metadata !15, metadata !DIExpression()), !dbg !13 + %0 = trunc i64 %indvars.iv to i32, !dbg !16 + %mul = shl i32 %0, 3, !dbg !16 + call void @llvm.dbg.value(metadata i32 %mul, metadata !18, metadata !DIExpression()), !dbg !16 + %arrayidx = getelementptr inbounds i32, i32* %data, i64 %indvars.iv, !dbg !16 + store i32 %mul, i32* %arrayidx, align 4, !dbg !16 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !16 + call void @llvm.dbg.value(metadata i64 %indvars.iv.next, metadata !15, metadata !DIExpression()), !dbg !13 + %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count, !dbg !13 + br i1 %exitcond, label %while.body, label %while.end.loopexit, !dbg !13, !llvm.loop !19 + +while.end.loopexit: ; preds = %while.body + br label %while.end, !dbg !13 + +while.end: ; preds = %while.end.loopexit, %entry + ret void, !dbg !13 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "lsr-basic.cpp", directory: "/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0"} +!7 = distinct !DISubprogram(name: "mul_pow_of_2_to_shift", linkageName: "_Z21mul_pow_of_2_to_shiftjPj", scope: !1, file: !1, line: 18, type: !8, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10, !11} +!10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!12 = !DILocalVariable(name: "size", arg: 1, scope: !7, file: !1, line: 18, type: !10) +!13 = !DILocation(line: 0, scope: !7) +!14 = !DILocalVariable(name: "data", arg: 2, scope: !7, file: !1, line: 18, type: !11) +!15 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 19, type: !10) +!16 = !DILocation(line: 22, column: 27, scope: !17) +!17 = distinct !DILexicalBlock(scope: !7, file: !1, line: 21, column: 22) +!18 = !DILocalVariable(name: "comp", scope: !17, file: !1, line: 22, type: !10) +!19 = distinct !{!19, !20, !21, !22, !23} +!20 = !DILocation(line: 21, column: 5, scope: !7) +!21 = !DILocation(line: 25, column: 5, scope: !7) +!22 = !{!"llvm.loop.mustprogress"} +!23 = !{!"llvm.loop.vectorize.width", i32 1} Index: llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-2.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-2.ll @@ -0,0 +1,92 @@ +; RUN: opt -S -loop-reduce %s -o - | FileCheck %s +;; Ensure that we retain debuginfo for the induction variable and dependant +;; variables when loop strength reduction is applied to the loop. +;; This IR produced from: +;; +;; clang -S -emit-llvm -Xclang -disable-llvm-passes -g lsr-basic.cpp -o +;; Then executing opt -O2 up to the the loopFullUnroll pass. +;; void mul_to_addition(unsigned k, unsigned size, unsigned *data) { +;; int i = 0; +;; #pragma clang loop vectorize(disable) +;; while (i < size) { +;; int comp = (4 * i) + k; +;; data[i] = comp; +;; i += 1; +;; } +;; } +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i:[0-9]+]], metadata !DIExpression()) +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i64 %lsr.iv, i32 %k), metadata ![[comp:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 4, DW_OP_mul, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i]], metadata !DIExpression(DW_OP_consts, 1, DW_OP_plus, DW_OP_stack_value)) +; CHECK: ![[i]] = !DILocalVariable(name: "i" +; CHECK: ![[comp]] = !DILocalVariable(name: "comp" + +; ModuleID = './llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-2.ll' +source_filename = "./llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-2.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local void @_Z15mul_to_additionjjPj(i32 %k, i32 %size, i32* nocapture %data) local_unnamed_addr !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %k, metadata !13, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata i32 %size, metadata !15, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata i32* %data, metadata !16, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata i32 0, metadata !17, metadata !DIExpression()), !dbg !14 + br label %while.cond, !dbg !14 + +while.cond: ; preds = %while.body, %entry + %i.0 = phi i32 [ 0, %entry ], [ %add1, %while.body ], !dbg !14 + call void @llvm.dbg.value(metadata i32 %i.0, metadata !17, metadata !DIExpression()), !dbg !14 + %cmp = icmp ult i32 %i.0, %size, !dbg !14 + br i1 %cmp, label %while.body, label %while.end, !dbg !14 + +while.body: ; preds = %while.cond + %mul = mul nsw i32 %i.0, 4, !dbg !19 + %add = add i32 %mul, %k, !dbg !19 + call void @llvm.dbg.value(metadata i32 %add, metadata !21, metadata !DIExpression()), !dbg !19 + %idxprom = zext i32 %i.0 to i64, !dbg !19 + %arrayidx = getelementptr inbounds i32, i32* %data, i64 %idxprom, !dbg !19 + store i32 %add, i32* %arrayidx, align 4, !dbg !19 + %add1 = add nuw nsw i32 %i.0, 1, !dbg !19 + call void @llvm.dbg.value(metadata i32 %add1, metadata !17, metadata !DIExpression()), !dbg !14 + br label %while.cond, !dbg !14, !llvm.loop !22 + +while.end: ; preds = %while.cond + ret void, !dbg !14 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "basic.cpp", directory: "/test") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0"} +!7 = distinct !DISubprogram(name: "mul_to_addition", linkageName: "_Z15mul_to_additionjjPj", scope: !8, file: !8, line: 64, type: !9, scopeLine: 64, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DIFile(filename: "./basic.cpp", directory: "/test") +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11, !11, !12} +!11 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!13 = !DILocalVariable(name: "k", arg: 1, scope: !7, file: !8, line: 64, type: !11) +!14 = !DILocation(line: 0, scope: !7) +!15 = !DILocalVariable(name: "size", arg: 2, scope: !7, file: !8, line: 64, type: !11) +!16 = !DILocalVariable(name: "data", arg: 3, scope: !7, file: !8, line: 64, type: !12) +!17 = !DILocalVariable(name: "i", scope: !7, file: !8, line: 65, type: !18) +!18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!19 = !DILocation(line: 68, column: 23, scope: !20) +!20 = distinct !DILexicalBlock(scope: !7, file: !8, line: 67, column: 22) +!21 = !DILocalVariable(name: "comp", scope: !20, file: !8, line: 68, type: !18) +!22 = distinct !{!22, !23, !24, !25, !26} +!23 = !DILocation(line: 67, column: 5, scope: !7) +!24 = !DILocation(line: 71, column: 5, scope: !7) +!25 = !{!"llvm.loop.mustprogress"} +!26 = !{!"llvm.loop.vectorize.width", i32 1} Index: llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-3.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-3.ll @@ -0,0 +1,90 @@ +; RUN: opt -S -loop-reduce %s -o - | FileCheck %s +;; Ensure that we retain debuginfo for the induction variable and dependant +;; variables when loop strength reduction is applied to the loop. +;; This IR produced from: +;; +;; clang -S -emit-llvm -Xclang -disable-llvm-passes -g lsr-basic.cpp -o +;; Then executing opt -O2 up to the the loopFullUnroll pass. +;; void basic_recurrence(unsigned k, unsigned size, unsigned *data) +;; { +;; unsigned i = 0; +;; #pragma clang loop vectorize(disable) +;; while (i < size) { +;; unsigned comp = i * k; +;; data[i] = comp; +;; i++; +;; } +;; } +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i:[0-9]+]], metadata !DIExpression()) +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i64 %lsr.iv, i32 %k), metadata ![[comp:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i]], metadata !DIExpression(DW_OP_consts, 1, DW_OP_plus, DW_OP_stack_value)) +; CHECK: ![[i]] = !DILocalVariable(name: "i" +; CHECK: ![[comp]] = !DILocalVariable(name: "comp" + +; ModuleID = './llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-3.ll' +source_filename = "./llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-3.ll" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local void @_Z16basic_recurrencejjPj(i32 %k, i32 %size, i32* nocapture %data) local_unnamed_addr !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %k, metadata !13, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata i32 %size, metadata !15, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata i32* %data, metadata !16, metadata !DIExpression()), !dbg !14 + br label %while.cond, !dbg !14 + +while.cond: ; preds = %while.body, %entry + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.body ] + call void @llvm.dbg.value(metadata i32 %i.0, metadata !17, metadata !DIExpression()), !dbg !14 + %cmp = icmp ult i32 %i.0, %size, !dbg !14 + br i1 %cmp, label %while.body, label %while.end, !dbg !14 + +while.body: ; preds = %while.cond + %mul = mul i32 %i.0, %k, !dbg !18 + call void @llvm.dbg.value(metadata i32 %mul, metadata !20, metadata !DIExpression()), !dbg !18 + %idxprom = zext i32 %i.0 to i64, !dbg !18 + %arrayidx = getelementptr inbounds i32, i32* %data, i64 %idxprom, !dbg !18 + store i32 %mul, i32* %arrayidx, align 4, !dbg !18 + %inc = add nuw i32 %i.0, 1, !dbg !18 + call void @llvm.dbg.value(metadata i32 %inc, metadata !17, metadata !DIExpression()), !dbg !14 + br label %while.cond, !dbg !14, !llvm.loop !21 + +while.end: ; preds = %while.cond + ret void, !dbg !14 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "basic.cpp", directory: "/test") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0)"} +!7 = distinct !DISubprogram(name: "basic_recurrence", linkageName: "_Z16basic_recurrencejjPj", scope: !8, file: !8, line: 82, type: !9, scopeLine: 83, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DIFile(filename: "./basic.cpp", directory: "/test") +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11, !11, !12} +!11 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!13 = !DILocalVariable(name: "k", arg: 1, scope: !7, file: !8, line: 82, type: !11) +!14 = !DILocation(line: 0, scope: !7) +!15 = !DILocalVariable(name: "size", arg: 2, scope: !7, file: !8, line: 82, type: !11) +!16 = !DILocalVariable(name: "data", arg: 3, scope: !7, file: !8, line: 82, type: !12) +!17 = !DILocalVariable(name: "i", scope: !7, file: !8, line: 84, type: !11) +!18 = !DILocation(line: 87, column: 27, scope: !19) +!19 = distinct !DILexicalBlock(scope: !7, file: !8, line: 86, column: 22) +!20 = !DILocalVariable(name: "comp", scope: !19, file: !8, line: 87, type: !11) +!21 = distinct !{!21, !22, !23, !24, !25} +!22 = !DILocation(line: 86, column: 5, scope: !7) +!23 = !DILocation(line: 90, column: 5, scope: !7) +!24 = !{!"llvm.loop.mustprogress"} +!25 = !{!"llvm.loop.vectorize.width", i32 1} Index: llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-4.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-variadic-value-4.ll @@ -0,0 +1,90 @@ +; RUN: opt -S -loop-reduce %s -o - | FileCheck %s +;; Ensure that we retain debuginfo for the induction variable and dependant +;; variables when loop strength reduction is applied to the loop. +;; This IR produced from: +;; +;; clang -S -emit-llvm -Xclang -disable-llvm-passes -g lsr-basic.cpp -o +;; Then executing opt -O2 up to the the loopFullUnroll pass. +;; void mul_pow_of_2_to_shift_var_inc(unsigned size, unsigned *data, unsigned multiplicand) { +;; unsigned i = 0; +;; #pragma clang loop vectorize(disable) +;; while (i < size) { +;; unsigned comp = i * multiplicand; +;; data[i] = comp; +;; i++; +;; } +;; } +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i:[0-9]+]], metadata !DIExpression()) +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i64 %lsr.iv, i32 %multiplicand), metadata ![[comp:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata i64 %lsr.iv, metadata ![[i]], metadata !DIExpression(DW_OP_consts, 1, DW_OP_plus, DW_OP_stack_value)) +; CHECK: ![[i]] = !DILocalVariable(name: "i" +; CHECK: ![[comp]] = !DILocalVariable(name: "comp" + + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@__const.main.data = private unnamed_addr constant [16 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15], align 16 + +define dso_local void @_Z21mul_pow_of_2_to_shiftjPjj(i32 %size, i32* nocapture %data, i32 %multiplicand) local_unnamed_addr !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %size, metadata !12, metadata !DIExpression()), !dbg !13 + call void @llvm.dbg.value(metadata i32* %data, metadata !14, metadata !DIExpression()), !dbg !13 + call void @llvm.dbg.value(metadata i32 %multiplicand, metadata !15, metadata !DIExpression()), !dbg !13 + call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !DIExpression()), !dbg !13 + br label %while.cond, !dbg !13 + +while.cond: ; preds = %while.body, %entry + %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.body ], !dbg !13 + call void @llvm.dbg.value(metadata i32 %i.0, metadata !16, metadata !DIExpression()), !dbg !13 + %cmp = icmp ult i32 %i.0, %size, !dbg !13 + br i1 %cmp, label %while.body, label %while.end, !dbg !13 + +while.body: ; preds = %while.cond + %mul = mul i32 %i.0, %multiplicand, !dbg !17 + call void @llvm.dbg.value(metadata i32 %mul, metadata !19, metadata !DIExpression()), !dbg !17 + %idxprom = zext i32 %i.0 to i64, !dbg !17 + %arrayidx = getelementptr inbounds i32, i32* %data, i64 %idxprom, !dbg !17 + store i32 %mul, i32* %arrayidx, align 4, !dbg !17 + %inc = add nuw i32 %i.0, 1, !dbg !17 + call void @llvm.dbg.value(metadata i32 %inc, metadata !16, metadata !DIExpression()), !dbg !13 + br label %while.cond, !dbg !13, !llvm.loop !20 + +while.end: ; preds = %while.cond + ret void, !dbg !13 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + +attributes #0 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "basic.cpp", directory: "/test") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0"} +!7 = distinct !DISubprogram(name: "mul_pow_of_2_to_shift", linkageName: "_Z21mul_pow_of_2_to_shiftjPjj", scope: !1, file: !1, line: 17, type: !8, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10, !11, !10} +!10 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!12 = !DILocalVariable(name: "size", arg: 1, scope: !7, file: !1, line: 17, type: !10) +!13 = !DILocation(line: 0, scope: !7) +!14 = !DILocalVariable(name: "data", arg: 2, scope: !7, file: !1, line: 17, type: !11) +!15 = !DILocalVariable(name: "multiplicand", arg: 3, scope: !7, file: !1, line: 17, type: !10) +!16 = !DILocalVariable(name: "i", scope: !7, file: !1, line: 18, type: !10) +!17 = !DILocation(line: 21, column: 27, scope: !18) +!18 = distinct !DILexicalBlock(scope: !7, file: !1, line: 20, column: 22) +!19 = !DILocalVariable(name: "comp", scope: !18, file: !1, line: 21, type: !10) +!20 = distinct !{!20, !21, !22, !23, !24} +!21 = !DILocation(line: 20, column: 5, scope: !7) +!22 = !DILocation(line: 24, column: 5, scope: !7) +!23 = !{!"llvm.loop.mustprogress"} +!24 = !{!"llvm.loop.vectorize.width", i32 1}