diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h
--- a/flang/include/flang/Frontend/CodeGenOptions.h
+++ b/flang/include/flang/Frontend/CodeGenOptions.h
@@ -69,6 +69,57 @@
   /// The format used for serializing remarks (default: YAML)
   std::string OptRecordFormat;
 
+  // The RemarkKind enum class and OptRemark struct are identical to what Clang
+  // has
+  // TODO: Share with clang instead of re-implementing here
+  enum class RemarkKind {
+    RK_Missing,  // Remark argument not present on the command line.
+    RK_Enabled,  // Remark enabled via '-Rgroup', i.e. -Rpass, -Rpass-missed,
+                 // -Rpass-analysis
+    RK_Disabled, // Remark disabled via '-Rno-group', i.e. -Rno-pass,
+                 // -Rno-pass-missed, -Rno-pass-analysis.
+  };
+
+  /// Optimization remark with an optional regular expression pattern.
+  struct OptRemark {
+    RemarkKind Kind = RemarkKind::RK_Missing;
+    std::string Pattern;
+    std::shared_ptr<llvm::Regex> Regex;
+
+    /// By default, optimization remark is missing.
+    OptRemark() = default;
+
+    /// Returns true iff the optimization remark holds a valid regular
+    /// expression.
+    bool hasValidPattern() const { return Regex != nullptr; }
+
+    /// Matches the given string against the regex, if there is some.
+    bool patternMatches(llvm::StringRef string) const {
+      return hasValidPattern() && Regex->match(string);
+    }
+  };
+
+  // The OptRemark fields provided here are identical to Clang.
+
+  /// Selected optimizations for which we should enable optimization remarks.
+  /// Transformation passes whose name matches the contained (optional) regular
+  /// expression (and support this feature), will emit a diagnostic whenever
+  /// they perform a transformation.
+  OptRemark OptimizationRemark;
+
+  /// Selected optimizations for which we should enable missed optimization
+  /// remarks. Transformation passes whose name matches the contained (optional)
+  /// regular expression (and support this feature), will emit a diagnostic
+  /// whenever they tried but failed to perform a transformation.
+  OptRemark OptimizationRemarkMissed;
+
+  /// Selected optimizations for which we should enable optimization analyses.
+  /// Transformation passes whose name matches the contained (optional) regular
+  /// expression (and support this feature), will emit a diagnostic whenever
+  /// they want to explain why they decided to apply or not apply a given
+  /// transformation.
+  OptRemark OptimizationRemarkAnalysis;
+
   // Define accessors/mutators for code generation options of enumeration type.
 #define CODEGENOPT(Name, Bits, Default)
 #define ENUM_CODEGENOPT(Name, Type, Bits, Default)                             \
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -153,6 +153,38 @@
   return true;
 }
 
+// Generate an OptRemark object containing info on if the -Rgroup
+// specified is enabled or not.
+static CodeGenOptions::OptRemark
+parseOptimizationRemark(llvm::opt::ArgList &args,
+                        llvm::StringRef remarkOptName) {
+  assert((remarkOptName == "pass" || remarkOptName == "pass-missed" ||
+          remarkOptName == "pass-analysis") &&
+         "Unknown group name provided.");
+  CodeGenOptions::OptRemark result;
+
+  for (llvm::opt::Arg *a : args) {
+    if (a->getOption().matches(clang::driver::options::OPT_R_Joined)) {
+      llvm::StringRef value = a->getValue();
+
+      if (value == remarkOptName) {
+        result.Kind = CodeGenOptions::RemarkKind::RK_Enabled;
+        // Enable everything
+        result.Pattern = ".*";
+        result.Regex = std::make_shared<llvm::Regex>(result.Pattern);
+
+      } else if (value.split('-') ==
+                 std::make_pair(llvm::StringRef("no"), remarkOptName)) {
+        result.Kind = CodeGenOptions::RemarkKind::RK_Disabled;
+        // Disable everything
+        result.Pattern = "";
+        result.Regex = nullptr;
+      }
+    }
+  }
+  return result;
+}
+
 static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
                              llvm::opt::ArgList &args,
                              clang::DiagnosticsEngine &diags) {
@@ -194,14 +226,30 @@
           args.getLastArg(clang::driver::options::OPT_opt_record_file))
     opts.OptRecordFile = a->getValue();
 
+  // Optimization file format. Defaults to yaml
   if (const llvm::opt::Arg *a =
           args.getLastArg(clang::driver::options::OPT_opt_record_format))
     opts.OptRecordFormat = a->getValue();
 
+  // Specifies, using a regex, which successful optimization passes(middle and
+  // backend), to include in the final optimization record file generated. If
+  // not provided -fsave-optimization-record will include all passes.
   if (const llvm::opt::Arg *a =
           args.getLastArg(clang::driver::options::OPT_opt_record_passes))
     opts.OptRecordPasses = a->getValue();
 
+  // Create OptRemark that allows printing of all successful optimization
+  // passes applied.
+  opts.OptimizationRemark = parseOptimizationRemark(args, "pass");
+
+  // Create OptRemark that allows all missed optimization passes to be printed.
+  opts.OptimizationRemarkMissed = parseOptimizationRemark(args, "pass-missed");
+
+  // Create OptRemark that allows all optimization decisions made by LLVM
+  // to be printed.
+  opts.OptimizationRemarkAnalysis =
+      parseOptimizationRemark(args, "pass-analysis");
+
   if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ))
     opts.SaveTempsDir = a->getValue();
 
@@ -959,6 +1007,12 @@
     res.loweringOpts.setNoPPCNativeVecElemOrder(true);
   }
 
+  // Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
+  // -Rpass-analysis. This will be used later when processing and outputting the
+  // remarks generated by LLVM in ExecuteCompilerInvocation.cpp.
+  for (auto *a : args.filtered(clang::driver::options::OPT_R_Group))
+    res.getDiagnosticOpts().Remarks.push_back(a->getValue());
+
   success &= parseFrontendArgs(res.getFrontendOpts(), args, diags);
   parseTargetArgs(res.getTargetOpts(), args);
   parsePreprocessorArgs(res.getPreprocessorOpts(), args);
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -919,6 +919,108 @@
   mpm.run(*llvmModule, mam);
 }
 
+// This class handles optimization remark messages requested if
+// any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
+class BackendRemarkConsumer : public llvm::DiagnosticHandler {
+
+  const CodeGenOptions &codeGenOpts;
+  clang::DiagnosticsEngine &diags;
+
+public:
+  BackendRemarkConsumer(clang::DiagnosticsEngine &diags,
+                        const CodeGenOptions &codeGenOpts)
+      : codeGenOpts(codeGenOpts), diags(diags) {}
+
+  bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override {
+    return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName);
+  }
+  bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override {
+    return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName);
+  }
+  bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override {
+    return codeGenOpts.OptimizationRemark.patternMatches(passName);
+  }
+
+  bool isAnyRemarkEnabled() const override {
+    return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
+           codeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
+           codeGenOpts.OptimizationRemark.hasValidPattern();
+  }
+
+  void
+  emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &diagInfo,
+                          unsigned diagID) {
+    // We only support warnings and remarks.
+    assert(diagInfo.getSeverity() == llvm::DS_Remark ||
+           diagInfo.getSeverity() == llvm::DS_Warning);
+
+    std::string msg;
+    llvm::raw_string_ostream msgStream(msg);
+    msgStream << diagInfo.getMsg();
+
+    // Emit message.
+    diags.Report(diagID) << clang::AddFlagValue(diagInfo.getPassName())
+                         << msgStream.str();
+  }
+
+  void optimizationRemarkHandler(
+      const llvm::DiagnosticInfoOptimizationBase &diagInfo) {
+    auto passName = diagInfo.getPassName();
+    if (diagInfo.isPassed()) {
+      if (codeGenOpts.OptimizationRemark.patternMatches(passName))
+        // Optimization remarks are active only if the -Rpass flag has a regular
+        // expression that matches the name of the pass name in \p d.
+        emitOptimizationMessage(
+            diagInfo, clang::diag::remark_fe_backend_optimization_remark);
+
+      return;
+    }
+
+    if (diagInfo.isMissed()) {
+      if (codeGenOpts.OptimizationRemarkMissed.patternMatches(passName))
+        // Missed optimization remarks are active only if the -Rpass-missed
+        // flag has a regular expression that matches the name of the pass
+        // name in \p d.
+        emitOptimizationMessage(
+            diagInfo,
+            clang::diag::remark_fe_backend_optimization_remark_missed);
+
+      return;
+    }
+
+    assert(diagInfo.isAnalysis() && "Unknown remark type");
+
+    bool shouldAlwaysPrint = false;
+    auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&diagInfo);
+    if (ora)
+      shouldAlwaysPrint = ora->shouldAlwaysPrint();
+
+    if (shouldAlwaysPrint ||
+        codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName))
+      emitOptimizationMessage(
+          diagInfo,
+          clang::diag::remark_fe_backend_optimization_remark_analysis);
+  }
+
+  bool handleDiagnostics(const llvm::DiagnosticInfo &di) override {
+    switch (di.getKind()) {
+    case llvm::DK_OptimizationRemark:
+      optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di));
+      break;
+    case llvm::DK_OptimizationRemarkMissed:
+      optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di));
+      break;
+    case llvm::DK_OptimizationRemarkAnalysis:
+      optimizationRemarkHandler(
+          llvm::cast<llvm::OptimizationRemarkAnalysis>(di));
+      break;
+    default:
+      break;
+    }
+    return true;
+  }
+};
+
 void CodeGenAction::embedOffloadObjects() {
   CompilerInstance &ci = this->getInstance();
   const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
@@ -1029,6 +1131,11 @@
   if (!codeGenOpts.OffloadObjects.empty())
     embedOffloadObjects();
 
+  BackendRemarkConsumer remarkConsumer(diags, codeGenOpts);
+
+  llvmModule->getContext().setDiagnosticHandler(
+      std::make_unique<BackendRemarkConsumer>(remarkConsumer));
+
   // write optimization-record
   llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
       setupLLVMOptimizationRemarks(
diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
--- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -22,6 +22,7 @@
 #include "mlir/IR/AsmState.h"
 #include "mlir/IR/MLIRContext.h"
 #include "mlir/Pass/PassManager.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Driver/Options.h"
 #include "llvm/Option/OptTable.h"
 #include "llvm/Option/Option.h"
@@ -100,6 +101,34 @@
   llvm_unreachable("Invalid program action!");
 }
 
+// Remarks are ignored by default in Diagnostic.td, hence, we have to
+// enable them here before execution. Clang follows same idea using
+// ProcessWarningOptions in Warnings.cpp
+// This function is also responsible for emitting early warnings for
+// invalid -R options.
+static void
+updateDiagEngineForOptRemarks(clang::DiagnosticsEngine &diagsEng,
+                              const clang::DiagnosticOptions &opts) {
+  llvm::SmallVector<clang::diag::kind, 10> diags;
+  const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs =
+      diagsEng.getDiagnosticIDs();
+
+  for (unsigned i = 0; i < opts.Remarks.size(); i++) {
+    llvm::StringRef remarkOpt = opts.Remarks[i];
+    const auto flavor = clang::diag::Flavor::Remark;
+
+    // Check to see if this opt starts with "no-", if so, this is a
+    // negative form of the option.
+    bool isPositive = !remarkOpt.startswith("no-");
+    if (!isPositive)
+      remarkOpt = remarkOpt.substr(3);
+
+    diagsEng.setSeverityForGroup(flavor, remarkOpt,
+                                 isPositive ? clang::diag::Severity::Remark
+                                            : clang::diag::Severity::Ignored);
+  }
+}
+
 bool executeCompilerInvocation(CompilerInstance *flang) {
   // Honor -help.
   if (flang->getFrontendOpts().showHelp) {
@@ -165,6 +194,9 @@
   // Honor color diagnostics.
   flang->getDiagnosticOpts().ShowColors = flang->getFrontendOpts().showColors;
 
+  updateDiagEngineForOptRemarks(flang->getDiagnostics(),
+                                flang->getDiagnosticOpts());
+
   // Create and execute the frontend action.
   std::unique_ptr<FrontendAction> act(createFrontendAction(*flang));
   if (!act)
diff --git a/flang/test/Driver/optimization-remark.f90 b/flang/test/Driver/optimization-remark.f90
new file mode 100644
--- /dev/null
+++ b/flang/test/Driver/optimization-remark.f90
@@ -0,0 +1,46 @@
+! This file tests the -Rpass family of flags (-Rpass, -Rpass-missed
+! and -Rpass-analysis)
+! loop-delete isn't enabled at O0 so we use at least O1
+
+! Check that we can override -Rpass= with -Rno-pass.
+! RUN: %flang_fc1 %s -O1 -Rpass -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=REMARKS
+! RUN: %flang_fc1 %s -O1 -Rpass -Rno-pass -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=NO-REMARKS
+
+! Check -Rno-pass, -Rno-pass-analysis, -Rno-pass-missed nothing emitted
+! RUN: %flang %s -O1 -Rno-pass 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-REMARKS
+! RUN: %flang %s -O1 -Rno-pass-missed 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-REMARKS
+! RUN: %flang %s -O1 -Rno-pass-analysis 2>&1 | FileCheck %s --allow-empty --check-prefix=NO-REMARKS
+
+! Check full -Rpass message is emitted
+! RUN: %flang %s -O1 -Rpass 2>&1 | FileCheck %s
+
+! Check full -Rpass-missed message is emitted
+! RUN: %flang %s -O1 -Rpass-missed 2>&1 | FileCheck %s --check-prefix=REMARKS-MISSED
+
+! Check full -Rpass-analysis message is emitted
+! RUN: %flang %s -O1 -Rpass-analysis 2>&1 | FileCheck %s --check-prefix=REMARKS-ANALYSIS
+
+! CHECK: remark: Loop deleted because it is invariant
+! REMARKS-MISSED: remark: loop not vectorized
+! REMARKS-MISSED-NOT: instruction cannot be vectorized
+! REMARKS-ANALYSIS: remark: loop not vectorized: instruction cannot be vectorized
+! REMARKS-ANALYSIS-NOT: will not be inlined into {{.*}} because its definition is unavailable
+
+! REMARKS: remark:
+! NO-REMARKS-NOT: remark:
+
+program forttest
+    implicit none
+    real, dimension(1:50) :: aR1
+    integer :: n
+
+    do n = 1,50
+        aR1(n) = n * 1.34
+        print *, "hello"
+    end do
+
+    do n = 1,50
+        aR1(n) = n * 1.34
+    end do
+
+end program forttest