Index: llvm/trunk/include/llvm/Analysis/OptimizationDiagnosticInfo.h =================================================================== --- llvm/trunk/include/llvm/Analysis/OptimizationDiagnosticInfo.h +++ llvm/trunk/include/llvm/Analysis/OptimizationDiagnosticInfo.h @@ -223,6 +223,7 @@ namespace ore { using NV = DiagnosticInfoOptimizationBase::Argument; using setIsVerbose = DiagnosticInfoOptimizationBase::setIsVerbose; +using setExtraArgs = DiagnosticInfoOptimizationBase::setExtraArgs; } /// OptimizationRemarkEmitter legacy analysis pass Index: llvm/trunk/include/llvm/IR/DiagnosticInfo.h =================================================================== --- llvm/trunk/include/llvm/IR/DiagnosticInfo.h +++ llvm/trunk/include/llvm/IR/DiagnosticInfo.h @@ -382,6 +382,12 @@ /// \brief Used to set IsVerbose via the stream interface. struct setIsVerbose {}; + /// \brief When an instance of this is inserted into the stream, the arguments + /// following will not appear in the remark printed in the compiler output + /// (-Rpass) but only in the optimization record file + /// (-fsave-optimization-record). + struct setExtraArgs {}; + /// \brief Used in the streaming interface as the general argument type. It /// internally converts everything into a key-value pair. struct Argument { @@ -452,6 +458,7 @@ DiagnosticInfoOptimizationBase &operator<<(StringRef S); DiagnosticInfoOptimizationBase &operator<<(Argument A); DiagnosticInfoOptimizationBase &operator<<(setIsVerbose V); + DiagnosticInfoOptimizationBase &operator<<(setExtraArgs EA); /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; @@ -501,6 +508,11 @@ /// The remark is expected to be noisy. bool IsVerbose = false; + /// \brief If positive, the index of the first argument that only appear in + /// the optimization records and not in the remark printed in the compiler + /// output. + int FirstExtraArgIndex = -1; + friend struct yaml::MappingTraits; }; Index: llvm/trunk/lib/IR/DiagnosticInfo.cpp =================================================================== --- llvm/trunk/lib/IR/DiagnosticInfo.cpp +++ llvm/trunk/lib/IR/DiagnosticInfo.cpp @@ -170,14 +170,25 @@ getLocation(&Filename, &Line, &Column); return (Filename + ":" + Twine(Line) + ":" + Twine(Column)).str(); } + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, Value *V) - : Key(Key), Val(GlobalValue::getRealLinkageName(V->getName())) { + : Key(Key) { if (auto *F = dyn_cast(V)) { if (DISubprogram *SP = F->getSubprogram()) DLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); } else if (auto *I = dyn_cast(V)) DLoc = I->getDebugLoc(); + + // Only include names that correspond to user variables. FIXME: we should use + // debug info if available to get the name of the user variable. + if (isa(V) || isa(V)) + Val = GlobalValue::getRealLinkageName(V->getName()); + else if (isa(V)) { + raw_string_ostream OS(Val); + V->printAsOperand(OS, /*PrintType=*/false); + } else if (auto *I = dyn_cast(V)) + Val = I->getOpcodeName(); } DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, Type *T) @@ -359,10 +370,19 @@ return *this; } +DiagnosticInfoOptimizationBase &DiagnosticInfoOptimizationBase:: +operator<<(setExtraArgs EA) { + FirstExtraArgIndex = Args.size(); + return *this; +} + std::string DiagnosticInfoOptimizationBase::getMsg() const { std::string Str; raw_string_ostream OS(Str); - for (const DiagnosticInfoOptimizationBase::Argument &Arg : Args) + for (const DiagnosticInfoOptimizationBase::Argument &Arg : + make_range(Args.begin(), FirstExtraArgIndex == -1 + ? Args.end() + : Args.begin() + FirstExtraArgIndex)) OS << Arg.Val; return OS.str(); } Index: llvm/trunk/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/GVN.cpp +++ llvm/trunk/lib/Transforms/Scalar/GVN.cpp @@ -1590,10 +1590,13 @@ return true; } -static void reportLoadElim(LoadInst *LI, OptimizationRemarkEmitter *ORE) { +static void reportLoadElim(LoadInst *LI, Value *AvailableValue, + OptimizationRemarkEmitter *ORE) { + using namespace ore; ORE->emit(OptimizationRemark(DEBUG_TYPE, "LoadElim", LI) - << "load of type " << ore::NV("Type", LI->getType()) - << " eliminated"); + << "load of type " << NV("Type", LI->getType()) << " eliminated" + << setExtraArgs() << " in favor of " + << NV("InfavorOfValue", AvailableValue)); } /// Attempt to eliminate a load whose dependencies are @@ -1666,7 +1669,7 @@ MD->invalidateCachedPointerInfo(V); markInstructionForDeletion(LI); ++NumGVNLoad; - reportLoadElim(LI, ORE); + reportLoadElim(LI, V, ORE); return true; } @@ -1813,7 +1816,7 @@ patchAndReplaceAllUsesWith(L, AvailableValue); markInstructionForDeletion(L); ++NumGVNLoad; - reportLoadElim(L, ORE); + reportLoadElim(L, AvailableValue, ORE); // Tell MDA to rexamine the reused pointer since we might have more // information after forwarding it. if (MD && AvailableValue->getType()->getScalarType()->isPointerTy()) Index: llvm/trunk/test/Transforms/GVN/opt-remarks.ll =================================================================== --- llvm/trunk/test/Transforms/GVN/opt-remarks.ll +++ llvm/trunk/test/Transforms/GVN/opt-remarks.ll @@ -15,6 +15,8 @@ ; YAML-NEXT: - String: 'load of type ' ; YAML-NEXT: - Type: i32 ; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: - String: ' in favor of ' +; YAML-NEXT: - InfavorOfValue: i ; YAML-NEXT: ... ; YAML-NEXT: --- !Passed ; YAML-NEXT: Pass: gvn @@ -24,6 +26,8 @@ ; YAML-NEXT: - String: 'load of type ' ; YAML-NEXT: - Type: i32 ; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: - String: ' in favor of ' +; YAML-NEXT: - InfavorOfValue: '4' ; YAML-NEXT: ... ; YAML-NEXT: --- !Passed ; YAML-NEXT: Pass: gvn @@ -33,6 +37,8 @@ ; YAML-NEXT: - String: 'load of type ' ; YAML-NEXT: - Type: i32 ; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: - String: ' in favor of ' +; YAML-NEXT: - InfavorOfValue: load ; YAML-NEXT: ...