Index: llvm/include/llvm/Analysis/ScalarEvolution.h =================================================================== --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h @@ -544,6 +544,10 @@ /// Return true if the SCEV expression contains an undef value. bool containsUndefs(const SCEV *S) const; + /// Return true if the SCEV expression contains a Value that has been + /// optimised out and is now a nullptr. + bool containsErasedValue(const SCEV *S) const; + /// Return a SCEV expression for the full generality of the specified /// expression. const SCEV *getSCEV(Value *V); Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -12826,6 +12826,15 @@ }); } +// Return true when S contains a value that is a nullptr. +bool ScalarEvolution::containsErasedValue(const SCEV *S) const { + return SCEVExprContains(S, [](const SCEV *S) { + if (const auto *SU = dyn_cast(S)) + return SU->getValue() == nullptr; + return false; + }); +} + /// Return the size of an element read or written by Inst. const SCEV *ScalarEvolution::getElementSize(Instruction *Inst) { Type *Ty; Index: llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -5897,31 +5897,37 @@ namespace { struct SCEVDbgValueBuilder { SCEVDbgValueBuilder() = default; - SCEVDbgValueBuilder(const SCEVDbgValueBuilder &Base) { - Values = Base.Values; + SCEVDbgValueBuilder(const SCEVDbgValueBuilder &Base) { clone(Base); } + + void clone(const SCEVDbgValueBuilder &Base) { + LocationOps = Base.LocationOps; Expr = Base.Expr; } + void clear() { + LocationOps.clear(); + Expr.clear(); + } + /// The DIExpression as we translate the SCEV. SmallVector Expr; /// The location ops of the DIExpression. - SmallVector Values; + SmallVector LocationOps; 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. + /// in the set of LocationOps 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)); + auto *It = std::find(LocationOps.begin(), LocationOps.end(), V); unsigned ArgIndex = 0; - if (It != Values.end()) { - ArgIndex = std::distance(Values.begin(), It); + if (It != LocationOps.end()) { + ArgIndex = std::distance(LocationOps.begin(), It); } else { - ArgIndex = Values.size(); - Values.push_back(llvm::ValueAsMetadata::get(V)); + ArgIndex = LocationOps.size(); + LocationOps.push_back(V); } Expr.push_back(ArgIndex); } @@ -5939,6 +5945,20 @@ return true; } + // Iterating the expression as DWARF ops is convenient when updating + // DWARF_OP_LLVM_args. + llvm::DIExpression::expr_op_iterator exprBegin() const { + return llvm::DIExpression::expr_op_iterator(Expr.begin()); + } + + llvm::DIExpression::expr_op_iterator exprEnd() const { + return llvm::DIExpression::expr_op_iterator(Expr.end()); + } + + iterator_range expr_ops() const { + return {exprBegin(), exprEnd()}; + } + /// 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, @@ -6011,52 +6031,6 @@ 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(llvm::drop_begin(Expr, 2)); - 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) { @@ -6105,6 +6079,42 @@ return true; } + /// Create an offset expression for a given value (usually the IV). + void CreateOffsetExpr(int64_t Offset, Value *OffsetValue) { + pushValue(OffsetValue); + DIExpression::appendOffset(Expr, Offset); + LLVM_DEBUG(dbgs() << "scev-salvage: Generated IV offset expression.\n"); + } + + /// Combine a translation of the SCEV and the IV to create an expression that + /// recovers a location's value. + void CreateIterCountExpr(const SCEV *S, + const SCEVDbgValueBuilder &IterationCount, + ScalarEvolution &SE) { + // 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(S)) + return; + + LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: " << *S << '\n'); + + const auto *Rec = cast(S); + if (!Rec->isAffine()) + return; + + if (S->getExpressionSize() > MaxSCEVSalvageExpressionSize) + return; + + // Initialise a new builder with the iteration count expression. In + // combination with the value's SCEV this enables recovery. + clone(IterationCount); + if (!SCEVToValueExpr(*Rec, SE)) + return; + } + /// 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 @@ -6134,70 +6144,193 @@ } return true; } + + // Append the current expression and locations to a location list and an + // expression list. Modify the DW_OP_LLVM_arg indexes to account for + // the locations already present in the destination list. + // The IV is shared amongst all value recovery expressions, so it is left at + // Location index 0. + void appendToVectors(SmallVectorImpl &DestExpr, + SmallVectorImpl &DestLocations, + uint64_t LocationIndexOfIV = 0) { + assert(!DestLocations.empty() && + "Expected the locations vector to contain the IV"); + // The DWARF_OP_LLVM_arg arguments of the expression being appended must be + // modified to account for the locations already in the destination vector. + // All builders contain the IV as the first location op. + assert(!LocationOps.empty() && + "Expected the location ops to contain the IV."); + uint64_t IndexOffset = DestLocations.size() - 1; + DestLocations.insert(DestLocations.end(), LocationOps.begin() + 1, + LocationOps.end()); + + for (const auto &Op : expr_ops()) { + if (Op.getOp() != dwarf::DW_OP_LLVM_arg) { + Op.appendToVector(DestExpr); + continue; + } + + DestExpr.push_back(dwarf::DW_OP_LLVM_arg); + uint64_t NewIndex = Op.getArg(0) == LocationIndexOfIV + ? LocationIndexOfIV + : Op.getArg(0) + IndexOffset; + DestExpr.push_back(NewIndex); + } + } }; +/// Holds all the required data to salvage a dbg.value using the pre-LSR SCEVs +/// and DIExpression. struct DVIRecoveryRec { + + DVIRecoveryRec(DbgValueInst *DVI) : DVI(DVI), Expr(DVI->getExpression()) {} + DbgValueInst *DVI; DIExpression *Expr; - Metadata *LocationOp; - const llvm::SCEV *SCEV; + SmallVector LocationOps; + SmallVector SCEVs; + DenseMap RecoveryExprs; + + void clear() { + for (auto RE : RecoveryExprs) + RE.getSecond()->clear(); + RecoveryExprs.clear(); + } + + ~DVIRecoveryRec() { clear(); } }; } // namespace -static void RewriteDVIUsingIterCount(DVIRecoveryRec CachedDVI, - const SCEVDbgValueBuilder &IterationCount, - ScalarEvolution &SE) { - // LSR may add locations to previously single location-op DVIs which - // are currently not supported. - if (CachedDVI.DVI->getNumVariableLocationOps() != 1) - return; +/// Rewrite the expression and location ops for the dbg.value. If only a single +/// value is used then omit 'DIArgList()' via some clumsy checking. +static void UpdateDbgValueInst(DVIRecoveryRec &DVIRec, + SmallVectorImpl &NewLocationOps, + SmallVectorImpl &NewExpr) { - // 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; + // Writing over an empty DIExpression with an expression that has more than + // {DW_OP_LLVM_arg,0}. + if (DVIRec.Expr->getNumElements() == 0 && NewExpr.size() > 2) + NewExpr.push_back(dwarf::DW_OP_stack_value); - LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: " - << *CachedDVI.SCEV << '\n'); + if (NewLocationOps.size() == 1 && NewExpr[0] == dwarf::DW_OP_LLVM_arg && + NewExpr[1] == 0) { + DVIRec.DVI->replaceVariableLocationOp(0u, NewLocationOps[0]); + llvm::SmallVector FinalExpr(llvm::drop_begin(NewExpr, 2)); + DVIRec.DVI->setExpression( + DIExpression::get(DVIRec.DVI->getContext(), FinalExpr)); - const auto *Rec = cast(CachedDVI.SCEV); - if (!Rec->isAffine()) - return; + } else { + SmallVector MetadataLocs; + for (Value *V : NewLocationOps) + MetadataLocs.push_back(ValueAsMetadata::get(V)); + auto ValArrayRef = llvm::ArrayRef(MetadataLocs); + DVIRec.DVI->setRawLocation( + llvm::DIArgList::get(DVIRec.DVI->getContext(), ValArrayRef)); + DVIRec.DVI->setExpression( + DIExpression::get(DVIRec.DVI->getContext(), NewExpr)); + } +} + +static bool SalvageDVI(llvm::Loop *L, ScalarEvolution &SE, + llvm::PHINode *LSRInductionVar, DVIRecoveryRec &DVIRec, + const SCEV *SCEVInductionVar, + SCEVDbgValueBuilder IterCountExpr) { + if (!DVIRec.DVI->isUndef()) + return false; - if (CachedDVI.SCEV->getExpressionSize() > MaxSCEVSalvageExpressionSize) - return; + // Restore the expression to pre-LSR state so that is consistent with the + // cached SCEVs and Values. + DVIRec.DVI->setExpression(DVIRec.Expr); + LLVM_DEBUG(dbgs() << "scev-salvage: attempt to salvage: " << *DVIRec.DVI + << '\n'); + + DenseMap LocationOpIndexMap; + SmallVector NewLocationOps = {LSRInductionVar}; + for (unsigned i = 0; i < DVIRec.LocationOps.size(); i++) { + WeakVH VH = DVIRec.LocationOps[i]; + // LSR may modify the dbg.value in an unsuccessful salvaging attempt, so + // prevent function calls against a nullptr Value. + if (VH == nullptr) + VH = UndefValue::get(llvm::Type::getInt64Ty(DVIRec.DVI->getContext())); + + // Place the locations not optimised out in the list first, avoiding + // inserts later. The map is used to update the DIExpression's + // DW_OP_LLVM_arg arguments as the expression is updated. + if (!isa(VH)) { + NewLocationOps.push_back(VH); + LocationOpIndexMap[i] = NewLocationOps.size() - 1; + LLVM_DEBUG(dbgs() << "scev-salvage: Location index " << i + << " now at index " << LocationOpIndexMap[i] << "\n"); + continue; + } - // Initialise a new builder with the iteration count expression. In - // combination with the value's SCEV this enables recovery. - SCEVDbgValueBuilder RecoverValue(IterationCount); - if (!RecoverValue.SCEVToValueExpr(*Rec, SE)) - return; + // It's possible that a value referred to in the SCEV may have been + // optimised out by LSR. + if (SE.containsErasedValue(DVIRec.SCEVs[i]) || + SE.containsUndefs(DVIRec.SCEVs[i])) { + LLVM_DEBUG(dbgs() << "scev-salvage: SCEV for value at index: " << i + << " now refers to an undef. Salvage abaondoned.\n"); + 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'); -} + LLVM_DEBUG(dbgs() << "scev-salvage: salvaging location at index " << i + << " with SCEV: " << *DVIRec.SCEVs[i] << "\n"); + + SCEVDbgValueBuilder *SalvageExpr = new SCEVDbgValueBuilder(); + DVIRec.RecoveryExprs[i] = SalvageExpr; + + // Create an offset-based salvage expression if possible, as it requires + // less DWARF ops than an iteration count-based expression. + if (Optional Offset = + SE.computeConstantDifference(DVIRec.SCEVs[i], SCEVInductionVar)) { + if (Offset.getValue().getMinSignedBits() <= 64) + SalvageExpr->CreateOffsetExpr(Offset.getValue().getSExtValue(), + LSRInductionVar); + } else + SalvageExpr->CreateIterCountExpr(DVIRec.SCEVs[i], IterCountExpr, SE); + } + + // Merge the DbgValueBuilder generated expressions and the original + // DIExpression, place the result into an new vector. + SmallVector NewExpr; + if (DVIRec.Expr->getNumElements() == 0) { + assert(DVIRec.RecoveryExprs.size() == 1 && + "Expected only a single recovery expression for an empty " + "DIExpression."); + SCEVDbgValueBuilder *B = DVIRec.RecoveryExprs.find(0)->getSecond(); + assert(B && "Expected a SCEVDbgSalvageBuilder for location 0"); + B->appendToVectors(NewExpr, NewLocationOps); + } + for (const auto &Op : DVIRec.Expr->expr_ops()) { + // Most Ops needn't be updated. + if (Op.getOp() != dwarf::DW_OP_LLVM_arg) { + Op.appendToVector(NewExpr); + continue; + } + + uint64_t locationArgIndex = Op.getArg(0); + auto DbgBuilderIt = DVIRec.RecoveryExprs.find(locationArgIndex); + // The location isn't in the recovery expression map, so LSR did not + // optimise it away. So just translate the argument to the updated + // location index. + if (DbgBuilderIt == DVIRec.RecoveryExprs.end()) { + NewExpr.push_back(dwarf::DW_OP_LLVM_arg); + NewExpr.push_back(LocationOpIndexMap[Op.getArg(0)]); + continue; + } + // The location has a recovery expression. + SCEVDbgValueBuilder *B = DbgBuilderIt->getSecond(); + B->appendToVectors(NewExpr, NewLocationOps); + } + + UpdateDbgValueInst(DVIRec, NewLocationOps, NewExpr); -static void RewriteDVIUsingOffset(DVIRecoveryRec &DVIRec, llvm::PHINode &IV, - int64_t Offset) { - assert(!DVIRec.DVI->hasArgList() && "Expected single location-op dbg.value."); - DbgValueInst *DVI = DVIRec.DVI; - SmallVector Ops; - DIExpression::appendOffset(Ops, Offset); - DIExpression *Expr = DIExpression::prependOpcodes(DVIRec.Expr, Ops, true); - LLVM_DEBUG(dbgs() << "scev-salvage: Updating: " << *DVIRec.DVI << '\n'); - DVI->setExpression(Expr); - llvm::Value *ValIV = dyn_cast(&IV); - DVI->replaceVariableLocationOp( - 0u, llvm::MetadataAsValue::get(DVI->getContext(), - llvm::ValueAsMetadata::get(ValIV))); - LLVM_DEBUG(dbgs() << "scev-salvage: updated with offset to IV: " - << *DVIRec.DVI << '\n'); + LLVM_DEBUG(dbgs() << "scev-salvage: Updated DVI: " << *DVIRec.DVI << "\n"); + return true; } +/// Obtain an expression for the iteration count, then attempt to salvage the +/// dbg.value intrinsics. static void DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE, llvm::PHINode *LSRInductionVar, @@ -6214,6 +6347,7 @@ if (!IVAddRec->isAffine()) return; + // Prevent translation using excessive resources. if (IVAddRec->getExpressionSize() > MaxSCEVSalvageExpressionSize) return; @@ -6226,37 +6360,9 @@ LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV: " << *SCEVInductionVar << '\n'); - // Needn't salvage if the location op hasn't been undef'd by LSR. for (auto &DVIRec : DVIToUpdate) { - if (!DVIRec.DVI->isUndef()) - continue; - - // Some DVIs that were single location-op when cached are now multi-op, - // due to LSR optimisations. However, multi-op salvaging is not yet - // supported by SCEV salvaging. But, we can attempt a salvage by restoring - // the pre-LSR single-op expression. - if (DVIRec.DVI->hasArgList()) { - if (!DVIRec.DVI->getVariableLocationOp(0)) - continue; - llvm::Type *Ty = DVIRec.DVI->getVariableLocationOp(0)->getType(); - DVIRec.DVI->setRawLocation( - llvm::ValueAsMetadata::get(UndefValue::get(Ty))); - DVIRec.DVI->setExpression(DVIRec.Expr); - } - - LLVM_DEBUG(dbgs() << "scev-salvage: value to recover SCEV: " - << *DVIRec.SCEV << '\n'); - - // Create a simple expression if the IV and value to salvage SCEVs - // start values differ by only a constant value. - if (Optional Offset = - SE.computeConstantDifference(DVIRec.SCEV, SCEVInductionVar)) { - if (Offset.getValue().getMinSignedBits() <= 64) - RewriteDVIUsingOffset(DVIRec, *LSRInductionVar, - Offset.getValue().getSExtValue()); - } else { - RewriteDVIUsingIterCount(DVIRec, IterCountExpr, SE); - } + SalvageDVI(L, SE, LSRInductionVar, DVIRec, SCEVInductionVar, + IterCountExpr); } } } @@ -6273,30 +6379,38 @@ auto DVI = dyn_cast(&I); if (!DVI) continue; - + // Ensure that if any location op is undef that the dbg.vlue is not + // cached. if (DVI->isUndef()) continue; - if (DVI->hasArgList()) - continue; + // Check that the location op SCEVs are suitable for translation to + // DIExpression. + const auto &HasTranslatableLocationOps = + [&](const DbgValueInst *DVI) -> bool { + for (const auto LocOp : DVI->location_ops()) { + if (!LocOp) + return false; - if (!DVI->getVariableLocationOp(0) || - !SE.isSCEVable(DVI->getVariableLocationOp(0)->getType())) - continue; + if (!SE.isSCEVable(LocOp->getType())) + return false; - // SCEVUnknown wraps an llvm::Value, it does not have a start and stride. - // Therefore no translation to DIExpression is performed. - const SCEV *S = SE.getSCEV(DVI->getVariableLocationOp(0)); - if (isa(S)) - continue; + const SCEV *S = SE.getSCEV(LocOp); + if (SE.containsUndefs(S)) + return false; + } + return true; + }; - // Avoid wasting resources generating an expression containing undef. - if (SE.containsUndefs(S)) + if (!HasTranslatableLocationOps(DVI)) continue; - SalvageableDVISCEVs.push_back( - {DVI, DVI->getExpression(), DVI->getRawLocation(), - SE.getSCEV(DVI->getVariableLocationOp(0))}); + DVIRecoveryRec &NewRec = SalvageableDVISCEVs.emplace_back(DVI); + for (const auto LocOp : DVI->location_ops()) { + NewRec.SCEVs.push_back(SE.getSCEV(LocOp)); + NewRec.LocationOps.push_back(LocOp); + } + SalvageableDVISCEVs.push_back(NewRec); DVIHandles.insert(DVI); } } @@ -6392,6 +6506,7 @@ } } + SalvageableDVI.clear(); DVIHandles.clear(); return Changed; } Index: llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-salvage-5.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-salvage-5.ll @@ -0,0 +1,123 @@ +; RUN: opt -S -loop-reduce %s | FileCheck %s + +;; Ensure that SCEV-based salvaging in Loop Strength Reduction can salvage +;; variadic dbg.value intrinsics. Generated from the following C++: + +;; clang -S -emit-llvm -Xclang -disable-llvm-passes -g lsr-variadic.cpp -o +;; Then running 'opt -O2' up until LSR. +;; void mul_to_addition(unsigned k, unsigned l, unsigned m, unsigned size, unsigned *data) { +;; unsigned i = 0; +;; #pragma clang loop vectorize(disable) +;; while (i < size) { +;; unsigned comp = (4 * i) + k; +;; unsigned comp2 = comp * l; +;; unsigned comp3 = comp2 << m; +;; data[i] = comp; +;; i++; +;; } +;; } +;; This produces variadic dbg.value intrinsics with location op DIArglists +;; of length two and three. +;; A third dbg.value was added artificially by copying a generated dbg.value +;; and the modifying the position of the optimised-out value in the location +;; list. + +; 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_div, 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 !DIArgList(i64 %lsr.iv, i32 %l, i32 %k), metadata ![[comp2:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 4, DW_OP_div, DW_OP_consts, 4, DW_OP_mul, DW_OP_LLVM_arg, 2, DW_OP_plus, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i64 %lsr.iv, i32 %m, i32 %l, i32 %k), metadata ![[comp3:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 4, DW_OP_div, DW_OP_consts, 4, DW_OP_mul, DW_OP_LLVM_arg, 3, DW_OP_plus, DW_OP_LLVM_arg, 2, DW_OP_mul, DW_OP_LLVM_arg, 1, DW_OP_shl, DW_OP_stack_value)) +; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i64 %lsr.iv, i32 %m, i32 %l, i32 %k), metadata ![[comp3:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_consts, 4, DW_OP_div, DW_OP_consts, 4, DW_OP_mul, DW_OP_LLVM_arg, 3, DW_OP_plus, DW_OP_LLVM_arg, 2, DW_OP_mul, DW_OP_LLVM_arg, 1, DW_OP_shl, DW_OP_stack_value)) +; CHECK: ![[comp]] = !DILocalVariable(name: "comp" +; CHECK: ![[comp2]] = !DILocalVariable(name: "comp2" +; CHECK: ![[comp3]] = !DILocalVariable(name: "comp3" + + +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_additionjjjjPj(i32 %k, i32 %l, i32 %m, i32 %size, i32* nocapture %data) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %k, metadata !14, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata i32 %l, metadata !15, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata i32 %m, metadata !16, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata i32 %size, metadata !17, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata i32* %data, metadata !18, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata i32 0, metadata !19, metadata !DIExpression()), !dbg !24 + %cmp9.not = icmp eq i32 %size, 0, !dbg !25 + br i1 %cmp9.not, label %while.end, label %while.body.preheader, !dbg !26 + +while.body.preheader: ; preds = %entry + %wide.trip.count = zext i32 %size to i64, !dbg !25 + br label %while.body, !dbg !26 + +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 !19, metadata !DIExpression()), !dbg !24 + %0 = trunc i64 %indvars.iv to i32, !dbg !27 + %mul = shl i32 %0, 2, !dbg !27 + %add = add i32 %mul, %k, !dbg !28 + call void @llvm.dbg.value(metadata i32 %add, metadata !20, metadata !DIExpression()), !dbg !29 + call void @llvm.dbg.value(metadata !DIArgList(i32 %add, i32 %l), metadata !22, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)), !dbg !29 + call void @llvm.dbg.value(metadata !DIArgList(i32 %add, i32 %m, i32 %l), metadata !23, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 2, DW_OP_mul, DW_OP_LLVM_arg, 1, DW_OP_shl, DW_OP_stack_value)), !dbg !29 + call void @llvm.dbg.value(metadata !DIArgList(i32 %m, i32 %add, i32 %l), metadata !23, metadata !DIExpression(DW_OP_LLVM_arg, 1, DW_OP_LLVM_arg, 2, DW_OP_mul, DW_OP_LLVM_arg, 0, DW_OP_shl, DW_OP_stack_value)), !dbg !29 + %arrayidx = getelementptr inbounds i32, i32* %data, i64 %indvars.iv, !dbg !30 + store i32 %add, i32* %arrayidx, align 4, !dbg !31 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1, !dbg !32 + call void @llvm.dbg.value(metadata i64 %indvars.iv.next, metadata !19, metadata !DIExpression()), !dbg !24 + %exitcond = icmp ne i64 %indvars.iv.next, %wide.trip.count, !dbg !25 + br i1 %exitcond, label %while.body, label %while.end.loopexit, !dbg !26, !llvm.loop !33 + +while.end.loopexit: ; preds = %while.body + br label %while.end, !dbg !37 + +while.end: ; preds = %while.end.loopexit, %entry + ret void, !dbg !37 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { "target-cpu"="x86-64" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "variadic2.cpp", directory: "/test") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0"} +!7 = distinct !DISubprogram(name: "mul_to_addition", linkageName: "_Z15mul_to_additionjjjjPj", scope: !8, file: !8, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13) +!8 = !DIFile(filename: "./variadic2.cpp", directory: "/test") +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11, !11, !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 = !{!14, !15, !16, !17, !18, !19, !20, !22, !23} +!14 = !DILocalVariable(name: "k", arg: 1, scope: !7, file: !8, line: 1, type: !11) +!15 = !DILocalVariable(name: "l", arg: 2, scope: !7, file: !8, line: 1, type: !11) +!16 = !DILocalVariable(name: "m", arg: 3, scope: !7, file: !8, line: 1, type: !11) +!17 = !DILocalVariable(name: "size", arg: 4, scope: !7, file: !8, line: 1, type: !11) +!18 = !DILocalVariable(name: "data", arg: 5, scope: !7, file: !8, line: 1, type: !12) +!19 = !DILocalVariable(name: "i", scope: !7, file: !8, line: 2, type: !11) +!20 = !DILocalVariable(name: "comp", scope: !21, file: !8, line: 5, type: !11) +!21 = distinct !DILexicalBlock(scope: !7, file: !8, line: 4, column: 23) +!22 = !DILocalVariable(name: "comp2", scope: !21, file: !8, line: 6, type: !11) +!23 = !DILocalVariable(name: "comp3", scope: !21, file: !8, line: 7, type: !11) +!24 = !DILocation(line: 0, scope: !7) +!25 = !DILocation(line: 4, column: 15, scope: !7) +!26 = !DILocation(line: 4, column: 6, scope: !7) +!27 = !DILocation(line: 5, column: 29, scope: !21) +!28 = !DILocation(line: 5, column: 34, scope: !21) +!29 = !DILocation(line: 0, scope: !21) +!30 = !DILocation(line: 8, column: 10, scope: !21) +!31 = !DILocation(line: 8, column: 18, scope: !21) +!32 = !DILocation(line: 9, column: 11, scope: !21) +!33 = distinct !{!33, !26, !34, !35, !36} +!34 = !DILocation(line: 10, column: 6, scope: !7) +!35 = !{!"llvm.loop.mustprogress"} +!36 = !{!"llvm.loop.vectorize.width", i32 1} +!37 = !DILocation(line: 11, column: 2, scope: !7)