diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 0e54d9564eb709a372eb06e076892721aa26a7b8..cd79df32a1bbe3c3622055008c611487fafda6d6 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -92,6 +92,8 @@ protected:
 
   unsigned HasBuiltinMSVaList : 1;
 
+  unsigned IsRenderScriptTarget : 1;
+
   // TargetInfo Constructor.  Default initializes all fields.
   TargetInfo(const llvm::Triple &T);
 
@@ -565,6 +567,9 @@ public:
   /// available on this target.
   bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; }
 
+  /// Returns true for RenderScript.
+  bool isRenderScriptTarget() const { return IsRenderScriptTarget; }
+
   /// \brief Returns whether the passed in string is a valid clobber in an
   /// inline asm statement.
   ///
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 92f658a6a37ff0da3a15a35f249bf169dd960cb9..dec8b7cda4ecab0dac87e98b1221138b124a142a 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -80,6 +80,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
   SSERegParmMax = 0;
   HasAlignMac68kSupport = false;
   HasBuiltinMSVaList = false;
+  IsRenderScriptTarget = false;
 
   // Default to no types using fpret.
   RealTypeUsesObjCFPRet = 0;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 6ce14ced7b73d8be66e1cc9f866b47bd5a51c7a6..2d0b3c0a9c56e8e1b93ec90c3ecd4b3a7f21fbb5 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -8113,6 +8113,7 @@ public:
                                      Triple.getOSName(),
                                      Triple.getEnvironmentName()),
                         Opts) {
+    IsRenderScriptTarget = true;
     LongWidth = LongAlign = 64;
   }
   void getTargetDefines(const LangOptions &Opts,
@@ -8130,7 +8131,9 @@ public:
       : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(),
                                          Triple.getOSName(),
                                          Triple.getEnvironmentName()),
-                            Opts) {}
+                            Opts) {
+    IsRenderScriptTarget = true;
+  }
 
   void getTargetDefines(const LangOptions &Opts,
                         MacroBuilder &Builder) const override {
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index be97d648e88441e341b2490b2746132610789275..2d1fa65c4764e6eb13063d4cfd7fbf13057e2bfa 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -31,6 +31,31 @@
 using namespace clang;
 using namespace CodeGen;
 
+// Helper for coercing an aggregate argument or return value into an integer
+// array of the same size (including padding) and alignment.  This alternate
+// coercion happens only for the RenderScript ABI and can be removed after
+// runtimes that rely on it are no longer supported.
+//
+// RenderScript assumes that the size of the argument / return value in the IR
+// is the same as the size of the corresponding qualified type. This helper
+// coerces the aggregate type into an array of the same size (including
+// padding).  This coercion is used in lieu of expansion of struct members or
+// other canonical coercions that return a coerced-type of larger size.
+//
+// Ty          - The argument / return value type
+// Context     - The associated ASTContext
+// LLVMContext - The associated LLVMContext
+static ABIArgInfo coerceToIntArray(QualType Ty,
+                                   ASTContext &Context,
+                                   llvm::LLVMContext &LLVMContext) {
+  // Alignment and Size are measured in bits.
+  const uint64_t Size = Context.getTypeSize(Ty);
+  const uint64_t Alignment = Context.getTypeAlign(Ty);
+  llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment);
+  const uint64_t NumElements = (Size + Alignment - 1) / Alignment;
+  return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements));
+}
+
 static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
                                llvm::Value *Array,
                                llvm::Value *Value,
@@ -4556,6 +4581,11 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const {
   // Aggregates <= 16 bytes are passed directly in registers or on the stack.
   uint64_t Size = getContext().getTypeSize(Ty);
   if (Size <= 128) {
+    // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
+    // same size and alignment.
+    if (getTarget().isRenderScriptTarget()) {
+      return coerceToIntArray(Ty, getContext(), getVMContext());
+    }
     unsigned Alignment = getContext().getTypeAlign(Ty);
     Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
 
@@ -4601,6 +4631,11 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
   // Aggregates <= 16 bytes are returned directly in registers or on the stack.
   uint64_t Size = getContext().getTypeSize(RetTy);
   if (Size <= 128) {
+    // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of
+    // same size and alignment.
+    if (getTarget().isRenderScriptTarget()) {
+      return coerceToIntArray(RetTy, getContext(), getVMContext());
+    }
     unsigned Alignment = getContext().getTypeAlign(RetTy);
     Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
 
@@ -5291,6 +5326,12 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
                                    /*Realign=*/TyAlign > ABIAlign);
   }
 
+  // On RenderScript, coerce Aggregates <= 64 bytes to an integer array of
+  // same size and alignment.
+  if (getTarget().isRenderScriptTarget()) {
+    return coerceToIntArray(Ty, getContext(), getVMContext());
+  }
+
   // Otherwise, pass by coercing to a structure of the appropriate size.
   llvm::Type* ElemTy;
   unsigned SizeRegs;
@@ -5472,6 +5513,11 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
   // are returned indirectly.
   uint64_t Size = getContext().getTypeSize(RetTy);
   if (Size <= 32) {
+    // On RenderScript, coerce Aggregates <= 4 bytes to an integer array of
+    // same size and alignment.
+    if (getTarget().isRenderScriptTarget()) {
+      return coerceToIntArray(RetTy, getContext(), getVMContext());
+    }
     if (getDataLayout().isBigEndian())
       // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4)
       return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
diff --git a/test/CodeGen/renderscript.c b/test/CodeGen/renderscript.c
index d47750a7736e4fa53b668d63d2b5a7457db9ed86..5482d36f583dc1fd38e811b5e4985fd4730023c0 100644
--- a/test/CodeGen/renderscript.c
+++ b/test/CodeGen/renderscript.c
@@ -23,3 +23,118 @@ _Static_assert(_Alignof(long) == LONG_WIDTH_AND_ALIGN, "sizeof long is wrong");
 long test_long(long v) {
   return v + 1;
 }
+
+// =============================================================================
+// Test coercion of aggregate argument or return value into integer arrays
+// =============================================================================
+
+// =============================================================================
+// aggregate parameter <= 4 bytes: coerced to [a x iNN] for both 32-bit and
+// 64-bit RenderScript
+// ==============================================================================
+
+typedef struct {char c1, c2, c3; } sChar3;
+typedef struct {short s; char c;} sShortChar;
+
+// CHECK-RS32: void @argChar3([3 x i8] %s.coerce)
+// CHECK-RS64: void @argChar3([3 x i8] %s.coerce)
+void argChar3(sChar3 s) {}
+
+// CHECK-RS32: void @argShortChar([2 x i16] %s.coerce)
+// CHECK-RS64: void @argShortChar([2 x i16] %s.coerce)
+void argShortChar(sShortChar s) {}
+
+// =============================================================================
+// aggregate return value <= 4 bytes: coerced to [a x iNN] for both 32-bit and
+// 64-bit RenderScript
+// =============================================================================
+
+// CHECK-RS32: [3 x i8] @retChar3()
+// CHECK-RS64: [3 x i8] @retChar3()
+sChar3 retChar3() { sChar3 r; return r; }
+
+// CHECK-RS32: [2 x i16] @retShortChar()
+// CHECK-RS64: [2 x i16] @retShortChar()
+sShortChar retShortChar() { sShortChar r; return r; }
+
+// =============================================================================
+// aggregate parameter <= 16 bytes: coerced to [a x iNN] for both 32-bit and
+// 64-bit RenderScript
+// =============================================================================
+
+typedef struct {short s1; char c; short s2; } sShortCharShort;
+typedef struct {int i; short s; char c; } sIntShortChar;
+typedef struct {long l; int i; } sLongInt;
+
+// CHECK-RS32: void @argShortCharShort([3 x i16] %s.coerce)
+// CHECK-RS64: void @argShortCharShort([3 x i16] %s.coerce)
+void argShortCharShort(sShortCharShort s) {}
+
+// CHECK-RS32: void @argIntShortChar([2 x i32] %s.coerce)
+// CHECK-RS64: void @argIntShortChar([2 x i32] %s.coerce)
+void argIntShortChar(sIntShortChar s) {}
+
+// CHECK-RS32: void @argLongInt([2 x i64] %s.coerce)
+// CHECK-RS64: void @argLongInt([2 x i64] %s.coerce)
+void argLongInt(sLongInt s) {}
+
+// =============================================================================
+// aggregate return value <= 16 bytes: returned on stack for 32-bit RenderScript
+// and coerced to [a x iNN] for 64-bit RenderScript
+// =============================================================================
+
+// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret %agg.result)
+// CHECK-RS64: [3 x i16] @retShortCharShort()
+sShortCharShort retShortCharShort() { sShortCharShort r; return r; }
+
+// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret %agg.result)
+// CHECK-RS64: [2 x i32] @retIntShortChar()
+sIntShortChar retIntShortChar() { sIntShortChar r; return r; }
+
+// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret %agg.result)
+// CHECK-RS64: [2 x i64] @retLongInt()
+sLongInt retLongInt() { sLongInt r; return r; }
+
+// =============================================================================
+// aggregate parameter <= 64 bytes: coerced to [a x iNN] for 32-bit RenderScript
+// and passed on the stack for 64-bit RenderScript
+// =============================================================================
+
+typedef struct {int i1, i2, i3, i4, i5; } sInt5;
+typedef struct {long l1, l2; char c; } sLong2Char;
+
+// CHECK-RS32: void @argInt5([5 x i32] %s.coerce)
+// CHECK-RS64: void @argInt5(%struct.sInt5* %s)
+void argInt5(sInt5 s) {}
+
+// CHECK-RS32: void @argLong2Char([3 x i64] %s.coerce)
+// CHECK-RS64: void @argLong2Char(%struct.sLong2Char* %s)
+void argLong2Char(sLong2Char s) {}
+
+// =============================================================================
+// aggregate return value <= 64 bytes: returned on stack for both 32-bit and
+// 64-bit RenderScript
+// =============================================================================
+
+// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret %agg.result)
+// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret %agg.result)
+sInt5 retInt5() { sInt5 r; return r;}
+
+// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result)
+// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result)
+sLong2Char retLong2Char() { sLong2Char r; return r;}
+
+// =============================================================================
+// aggregate parameters and return values > 64 bytes: passed and returned on the
+// stack for both 32-bit and 64-bit RenderScript
+// =============================================================================
+
+typedef struct {long l1, l2, l3, l4, l5, l6, l7, l8, l9; } sLong9;
+
+// CHECK-RS32: void @argLong9(%struct.sLong9* byval align 8 %s)
+// CHECK-RS64: void @argLong9(%struct.sLong9* %s)
+void argLong9(sLong9 s) {}
+
+// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret %agg.result)
+// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret %agg.result)
+sLong9 retLong9() { sLong9 r; return r; }