Index: llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp
===================================================================
--- llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -35,6 +35,7 @@
 #include "llvm/IR/CallSite.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
@@ -610,6 +611,16 @@
   return true;
 }
 
+static void emitTargetsRemarks(const std::vector<VirtualCallTarget> &TargetsForSlot) {
+  for (const VirtualCallTarget &Target : TargetsForSlot) {
+    Function *F = Target.Fn;
+    DISubprogram *SP = F->getSubprogram();
+    DebugLoc DL = SP ? DebugLoc::get(SP->getScopeLine(), 0, SP) : DebugLoc();
+    emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, DL,
+                           std::string("devirtualized ") + F->getName().str());
+  }
+}
+
 void DevirtModule::rebuildGlobal(VTableBits &B) {
   if (B.Before.Bytes.empty() && B.After.Bytes.empty())
     return;
@@ -815,10 +826,15 @@
                                    S.first.ByteOffset))
       continue;
 
-    if (trySingleImplDevirt(TargetsForSlot, S.second))
+    if (trySingleImplDevirt(TargetsForSlot, S.second)) {
+      emitTargetsRemarks(TargetsForSlot);
       continue;
+    }
 
-    DidVirtualConstProp |= tryVirtualConstProp(TargetsForSlot, S.second);
+    if (tryVirtualConstProp(TargetsForSlot, S.second)) {
+      emitTargetsRemarks(TargetsForSlot);
+      DidVirtualConstProp = true;
+    }
   }
 
   // If we were able to eliminate all unsafe uses for a type checked load,
Index: llvm/trunk/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll
===================================================================
--- llvm/trunk/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll
+++ llvm/trunk/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll
@@ -1,8 +1,12 @@
-; RUN: opt -S -wholeprogramdevirt %s | FileCheck %s
+; RUN: opt -S -wholeprogramdevirt -pass-remarks=wholeprogramdevirt %s 2>&1 | FileCheck %s
 
 target datalayout = "e-p:64:64"
 target triple = "x86_64-unknown-linux-gnu"
 
+; CHECK: remark: <unknown>:0:0: devirtualized call
+; CHECK: remark: <unknown>:0:0: devirtualized vf
+; CHECK: remark: <unknown>:0:0: devirtualized vf
+
 @vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0
 @vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0
 
Index: llvm/trunk/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll
===================================================================
--- llvm/trunk/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll
+++ llvm/trunk/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll
@@ -4,8 +4,20 @@
 target triple = "x86_64-unknown-linux-gnu"
 
 ; CHECK: remark: <unknown>:0:0: devirtualized call
+; CHECK: remark: <unknown>:0:0: devirtualized vf1i32
+; CHECK: remark: <unknown>:0:0: devirtualized vf2i32
+; CHECK: remark: <unknown>:0:0: devirtualized vf3i32
+; CHECK: remark: <unknown>:0:0: devirtualized vf4i32
 ; CHECK: remark: <unknown>:0:0: devirtualized call
+; CHECK: remark: <unknown>:0:0: devirtualized vf1i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf0i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf1i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf0i1
 ; CHECK: remark: <unknown>:0:0: devirtualized call
+; CHECK: remark: <unknown>:0:0: devirtualized vf0i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf1i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf0i1
+; CHECK: remark: <unknown>:0:0: devirtualized vf1i1
 ; CHECK-NOT: devirtualized call
 
 ; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]