diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 790c8e3..9ce6d22 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -1580,18 +1580,17 @@ public:
     Kind MyKind;
     std::string Str;
     unsigned OperandNo;
+    SourceLocation Loc;
   public:
     AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {}
-    AsmStringPiece(unsigned OpNo, char Modifier)
-      : MyKind(Operand), Str(), OperandNo(OpNo) {
-      Str += Modifier;
+    AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation L)
+      : MyKind(Operand), Str(S), OperandNo(OpNo), Loc(L) {
     }
 
     bool isString() const { return MyKind == String; }
     bool isOperand() const { return MyKind == Operand; }
 
     const std::string &getString() const {
-      assert(isString());
       return Str;
     }
 
@@ -1600,12 +1599,13 @@ public:
       return OperandNo;
     }
 
+    SourceLocation getLocation() const {
+      return Loc;
+    }
+
     /// getModifier - Get the modifier for this operand, if present.  This
     /// returns '\0' if there was no modifier.
-    char getModifier() const {
-      assert(isOperand());
-      return Str[0];
-    }
+    char getModifier() const;
   };
 
   /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index edef7c0..e26f595 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -581,9 +581,11 @@ public:
                                  unsigned /*Size*/) const {
     return true;
   }
-  virtual bool validateConstraintModifier(StringRef /*Constraint*/,
-                                          const char /*Modifier*/,
-                                          unsigned /*Size*/) const {
+  virtual bool
+  validateConstraintModifier(StringRef /*Constraint*/,
+                             char /*Modifier*/,
+                             unsigned /*Size*/,
+                             std::string &/*SuggestedModifier*/) const {
     return true;
   }
   bool resolveSymbolicName(const char *&Name,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index d12642d..d6dba10 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -357,6 +357,11 @@ unsigned AsmStmt::getNumPlusOperands() const {
   return Res;
 }
 
+char GCCAsmStmt::AsmStringPiece::getModifier() const {
+  assert(isOperand());
+  return isLetter(Str[0]) ? Str[0] : '\0';
+}
+
 StringRef GCCAsmStmt::getClobber(unsigned i) const {
   return getClobberStringLiteral(i)->getString();
 }
@@ -518,21 +523,23 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
     }
 
     // Handle %x4 and %x[foo] by capturing x as the modifier character.
-    char Modifier = '\0';
+    const char *Begin = CurPtr - 1;
     if (isLetter(EscapedChar)) {
       if (CurPtr == StrEnd) { // Premature end.
         DiagOffs = CurPtr-StrStart-1;
         return diag::err_asm_invalid_escape;
       }
-      Modifier = EscapedChar;
       EscapedChar = *CurPtr++;
     }
 
+    SourceLocation LocStart = getAsmString()->getLocStart();
+
     if (isDigit(EscapedChar)) {
       // %n - Assembler operand n
       unsigned N = 0;
 
       --CurPtr;
+      DiagOffs = CurPtr - StrStart;
       while (CurPtr != StrEnd && isDigit(*CurPtr))
         N = N*10 + ((*CurPtr++)-'0');
 
@@ -543,7 +550,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
         return diag::err_asm_invalid_operand_number;
       }
 
-      Pieces.push_back(AsmStringPiece(N, Modifier));
+      Pieces.push_back(AsmStringPiece(N, std::string(Begin, CurPtr - Begin),
+                                      LocStart.getLocWithOffset(DiagOffs)));
       continue;
     }
 
@@ -566,7 +574,9 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
         DiagOffs = CurPtr-StrStart;
         return diag::err_asm_unknown_symbolic_operand_name;
       }
-      Pieces.push_back(AsmStringPiece(N, Modifier));
+      Pieces.push_back(AsmStringPiece(N,
+                                      std::string(Begin, NameEnd - Begin + 1),
+                                      LocStart.getLocWithOffset(DiagOffs)));
 
       CurPtr = NameEnd+1;
       continue;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 2b8de8a..51fb73b 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -4148,8 +4148,10 @@ public:
     }
     return R;
   }
-  bool validateConstraintModifier(StringRef Constraint, const char Modifier,
-                                  unsigned Size) const override {
+  bool
+  validateConstraintModifier(StringRef Constraint, const char Modifier,
+                             unsigned Size,
+                             std::string &SuggestedModifier) const override {
     bool isOutput = (Constraint[0] == '=');
     bool isInOut = (Constraint[0] == '+');
 
@@ -4595,9 +4597,10 @@ public:
     return false;
   }
 
-  virtual bool validateConstraintModifier(StringRef Constraint,
-                                          const char Modifier,
-                                          unsigned Size) const {
+  bool
+  validateConstraintModifier(StringRef Constraint, const char Modifier,
+                             unsigned Size,
+                             std::string &SuggestedModifier) const override {
     // Strip off constraint modifiers.
     while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
       Constraint = Constraint.substr(1);
@@ -4616,7 +4619,11 @@ public:
       default:
         // By default an 'r' constraint will be in the 'x'
         // registers.
-        return Size == 64;
+        if (Size == 64)
+          return true;
+
+        SuggestedModifier = "w";
+        return false;
       }
     }
     }
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 5d076ca..b00bc37 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -257,11 +257,25 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
       continue;
 
     unsigned Size = Context.getTypeSize(Ty);
-    if (!Context.getTargetInfo()
-          .validateConstraintModifier(Literal->getString(), Piece.getModifier(),
-                                      Size))
-      Diag(Exprs[ConstraintIdx]->getLocStart(),
-           diag::warn_asm_mismatched_size_modifier);
+    std::string SuggestedModifier;
+    const TargetInfo &TI = Context.getTargetInfo();
+    if (!TI.validateConstraintModifier(Literal->getString(),
+                                       Piece.getModifier(), Size,
+                                       SuggestedModifier)) {
+      SourceLocation Loc = Exprs[ConstraintIdx]->getLocStart();
+
+      if (!SuggestedModifier.empty())
+        Loc = Piece.getLocation();
+
+      auto B = Diag(Loc, diag::warn_asm_mismatched_size_modifier);
+
+      if (!SuggestedModifier.empty()) {
+        std::string AsmStr = Piece.getString();
+        SuggestedModifier = "\"%" + AsmStr.insert(0, SuggestedModifier) + "\"";
+        B.AddFixItHint(FixItHint::CreateInsertion(Loc.getLocWithOffset(-1),
+                                                  SuggestedModifier));
+      }
+    }
   }
 
   // Validate tied input operands for type mismatches.
diff --git a/test/Sema/inline-asm-validate-aarch64.c b/test/Sema/inline-asm-validate-aarch64.c
new file mode 100644
index 0000000..ff149bf
--- /dev/null
+++ b/test/Sema/inline-asm-validate-aarch64.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only %s 2>&1 | FileCheck %s -strict-whitespace
+
+typedef unsigned char uint8_t;
+
+uint8_t constraint_r(uint8_t *addr) {
+  uint8_t byte;
+
+  __asm__ volatile("ldrb %0, [%1]" : "=r" (byte) : "r" (addr) : "memory");
+// CHECK: warning: value size does not match register size specified by the constraint and modifier
+// CHECK:{{^}}                         ^
+// CHECK:{{^}}                        "%w0"
+
+  return byte;
+}
+
+uint8_t constraint_r_symbolic(uint8_t *addr) {
+  uint8_t byte;
+
+  __asm__ volatile("ldrb %[s0], %[s1]" : [s0] "=r" (byte) : [s1] "r" (addr) : "memory");
+// CHECK: warning: value size does not match register size specified by the constraint and modifier
+// CHECK:{{^}}                         ^
+// CHECK:{{^}}                        "%w[s0]"
+
+  return byte;
+}
