[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-23 Thread Ben Shi via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG51585aa240de: [clang][AVR] Implement standard calling 
convention for AVR and AVRTiny (authored by benshi001).

Changed prior to commit:
  https://reviews.llvm.org/D120720?vs=415734=417811#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120720/new/

https://reviews.llvm.org/D120720

Files:
  clang/lib/Basic/Targets/AVR.cpp
  clang/lib/Basic/Targets/AVR.h
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/avr/argument.c
  clang/test/CodeGen/avr/struct.c

Index: clang/test/CodeGen/avr/struct.c
===
--- clang/test/CodeGen/avr/struct.c
+++ clang/test/CodeGen/avr/struct.c
@@ -1,15 +1,23 @@
-// RUN: %clang_cc1 -triple avr -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=TINY
 
 // Structure that is more than 8 bytes.
 struct s10 {
   int a, b, c, d, e;
 };
 
-// Structure that is less than 8 bytes.
+// Structure that is less than 8 bytes but more than 4 bytes.
 struct s06 {
   int a, b, c;
 };
 
+// Structure that is less than 4 bytes.
+struct s04 {
+  int a, b;
+};
+
 struct s10 foo10(int a, int b, int c) {
   struct s10 a0;
   return a0;
@@ -20,7 +28,21 @@
   return a0;
 }
 
-// CHECK: %struct.s10 = type { i16, i16, i16, i16, i16 }
-// CHECK: %struct.s06 = type { i16, i16, i16 }
-// CHECK: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
-// CHECK: define{{.*}} %struct.s06 @foo06(i16 noundef %a, i16 noundef %b, i16 noundef %c)
+struct s04 foo04(int a, int b) {
+  struct s04 a0;
+  return a0;
+}
+
+// AVR: %struct.s10 = type { i16, i16, i16, i16, i16 }
+// AVR: %struct.s06 = type { i16, i16, i16 }
+// AVR: %struct.s04 = type { i16, i16 }
+// AVR: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// AVR: define{{.*}} %struct.s06 @foo06(i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// AVR: define{{.*}} %struct.s04 @foo04(i16 noundef %a, i16 noundef %b)
+
+// TINY: %struct.s10 = type { i16, i16, i16, i16, i16 }
+// TINY: %struct.s06 = type { i16, i16, i16 }
+// TINY: %struct.s04 = type { i16, i16 }
+// TINY: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// TINY: define{{.*}} void @foo06(%struct.s06* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// TINY: define{{.*}} %struct.s04 @foo04(i16 noundef %a, i16 noundef %b)
Index: clang/test/CodeGen/avr/argument.c
===
--- /dev/null
+++ clang/test/CodeGen/avr/argument.c
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix TINY
+
+// NOTE: All arguments are passed via the stack for functions with variable arguments.
+// AVR:  define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// TINY: define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// AVR-NOT:  define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+// TINY-NOT: define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+char foo0(char a, char b, ...) {
+  return a + b;
+}
+
+// NOTE: All arguments are passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} i8 @foo1(i32 {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo1(i32 {{.*}}, i8 {{.*}} signext {{.*}})
+char foo1(long a, char b) {
+  return a + b;
+}
+
+// NOTE: The argument `char c` is passed via registers on avr, while via the stack on avrtiny.
+//   The argument `char b` costs 2 registers, so there is no vacant register left for
+//   `char c` on avrtiny.
+// AVR:  define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}})
+// TINY-NOT: define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+char foo2(long a, char b, char c) {
+  return a + b + c;
+}
+
+// NOTE: On avr, the argument `a` costs 16 registers and `b` costs 2 registers, so
+//   `c` has to be passed via the stack.
+// AVR:  define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo3({{.*}}, i8 {{.*}}, i8 {{.*}})
+// TINY-NOT: define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+struct s15 {
+  char arr[15];
+};
+char foo3(struct s15 a, char b, 

[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-16 Thread Ben Shi via Phabricator via cfe-commits
benshi001 updated this revision to Diff 415734.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120720/new/

https://reviews.llvm.org/D120720

Files:
  clang/lib/Basic/Targets/AVR.cpp
  clang/lib/Basic/Targets/AVR.h
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/avr/argument.c
  clang/test/CodeGen/avr/struct.c

Index: clang/test/CodeGen/avr/struct.c
===
--- clang/test/CodeGen/avr/struct.c
+++ clang/test/CodeGen/avr/struct.c
@@ -1,15 +1,23 @@
-// RUN: %clang_cc1 -triple avr -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix=TINY
 
 // Structure that is more than 8 bytes.
 struct s10 {
   int a, b, c, d, e;
 };
 
-// Structure that is less than 8 bytes.
+// Structure that is less than 8 bytes but more than 4 bytes.
 struct s06 {
   int a, b, c;
 };
 
+// Structure that is less than 4 bytes.
+struct s04 {
+  int a, b;
+};
+
 struct s10 foo10(int a, int b, int c) {
   struct s10 a0;
   return a0;
@@ -20,7 +28,21 @@
   return a0;
 }
 
-// CHECK: %struct.s10 = type { i16, i16, i16, i16, i16 }
-// CHECK: %struct.s06 = type { i16, i16, i16 }
-// CHECK: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
-// CHECK: define{{.*}} %struct.s06 @foo06(i16 noundef %a, i16 noundef %b, i16 noundef %c)
+struct s04 foo04(int a, int b) {
+  struct s04 a0;
+  return a0;
+}
+
+// AVR: %struct.s10 = type { i16, i16, i16, i16, i16 }
+// AVR: %struct.s06 = type { i16, i16, i16 }
+// AVR: %struct.s04 = type { i16, i16 }
+// AVR: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// AVR: define{{.*}} %struct.s06 @foo06(i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// AVR: define{{.*}} %struct.s04 @foo04(i16 noundef %a, i16 noundef %b)
+
+// TINY: %struct.s10 = type { i16, i16, i16, i16, i16 }
+// TINY: %struct.s06 = type { i16, i16, i16 }
+// TINY: %struct.s04 = type { i16, i16 }
+// TINY: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// TINY: define{{.*}} void @foo06(%struct.s06* {{.*}}, i16 noundef %a, i16 noundef %b, i16 noundef %c)
+// TINY: define{{.*}} %struct.s04 @foo04(i16 noundef %a, i16 noundef %b)
Index: clang/test/CodeGen/avr/argument.c
===
--- /dev/null
+++ clang/test/CodeGen/avr/argument.c
@@ -0,0 +1,116 @@
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix TINY
+
+// NOTE: All arguments are passed via the stack for functions with variable arguments.
+// AVR:  define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// TINY: define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// AVR-NOT:  define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+// TINY-NOT: define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+char foo0(char a, char b, ...) {
+  return a + b;
+}
+
+// NOTE: All arguments are passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} i8 @foo1(i32 {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo1(i32 {{.*}}, i8 {{.*}} signext {{.*}})
+char foo1(long a, char b) {
+  return a + b;
+}
+
+// NOTE: The argument `char c` is passed via registers on avr, while via the stack on avrtiny.
+//   The argument `char b` costs 2 registers, so there is no vacant register left for
+//   `char c` on avrtiny.
+// AVR:  define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}})
+// TINY-NOT: define {{.*}} i8 @foo2(i32 {{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+char foo2(long a, char b, char c) {
+  return a + b + c;
+}
+
+// NOTE: On avr, the argument `a` costs 16 registers and `b` costs 2 registers, so
+//   `c` has to be passed via the stack.
+// AVR:  define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo3({{.*}}, i8 {{.*}}, i8 {{.*}})
+// TINY-NOT: define {{.*}} i8 @foo3({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+struct s15 {
+  char arr[15];
+};
+char foo3(struct s15 a, char b, char c) {
+  return a.arr[b] + a.arr[c];
+}
+
+// NOTE: On avr, `a` only costs 16 registers, though there are 2 vacant registers,
+//   both `b` and `c` have to be passed via the stack.
+// AVR:  define {{.*}} i8 @foo4({{.*}}, i32 {{.*}}, i8 {{.*}})
+// AVR-NOT:  define 

[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-12 Thread Ben Shi via Phabricator via cfe-commits
benshi001 added a comment.

This patch fixes the issue https://github.com/llvm/llvm-project/issues/45485 .


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120720/new/

https://reviews.llvm.org/D120720

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-02 Thread Ben Shi via Phabricator via cfe-commits
benshi001 updated this revision to Diff 412357.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120720/new/

https://reviews.llvm.org/D120720

Files:
  clang/lib/Basic/Targets/AVR.cpp
  clang/lib/Basic/Targets/AVR.h
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/avr/argument.c

Index: clang/test/CodeGen/avr/argument.c
===
--- /dev/null
+++ clang/test/CodeGen/avr/argument.c
@@ -0,0 +1,167 @@
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix TINY
+
+// NOTE: All arguments are passed in memory for functions with variable arguments.
+// AVR:  define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// TINY: define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// AVR-NOT:  define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+// TINY-NOT: define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+char foo0(char a, char b, ...) {
+  return a + b;
+}
+
+// NOTE: The char type argument is passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} @foo1({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} @foo1({{.*}}, i8 {{.*}} signext {{.*}})
+struct s08 {
+  char arr[8];
+};
+struct s06 {
+  char arr[6];
+};
+struct s08 foo1(struct s06 s6, char a) {
+  struct s08 s8;
+  s8.arr[a] = s6.arr[a];
+  return s8;
+}
+
+// NOTE: The char type argument is passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} void @foo2({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} void @foo2({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}})
+struct s09 {
+  char arr[9];
+};
+struct s04 {
+  char arr[4];
+};
+struct s09 foo2(struct s04 s4, char a) {
+  struct s09 s9;
+  s9.arr[a] = s4.arr[a];
+  return s9;
+}
+
+// NOTE: The char type argument is passed via registers on avr but via stack on avrtiny.
+// AVR:  define {{.*}} void @foo3({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} void @foo3({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} void @foo3({{.*}}, {{.*}}, i8 {{.*}})
+struct s09 foo3(struct s06 s6, char a) {
+  struct s09 s9;
+  s9.arr[a] = s6.arr[a];
+  return s9;
+}
+
+// NOTE: The char type argument is passed via stack on both avr and avrtiny.
+// AVR:  define {{.*}} void @foo4({{.*}}, i8 {{.*}}, ...)
+// TINY: define {{.*}} void @foo4({{.*}}, i8 {{.*}}, ...)
+// AVR-NOT:  define {{.*}} i8 @foo4({{.*}}, i8 {{.*}} signext {{.*}}, ...)
+// TINY-NOT: define {{.*}} i8 @foo4({{.*}}, i8 {{.*}} signext {{.*}}, ...)
+struct s09 foo4(char b, ...) {
+  struct s09 s9;
+  s9.arr[b] = b;
+  return s9;
+}
+
+// NOTE: The char type argument is passed via stack on both avr and avrtiny.
+// AVR:  define {{.*}} void @foo5({{.*}}, {{.*}}, i8 {{.*}})
+// TINY: define {{.*}} void @foo5({{.*}}, {{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} void @foo5({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} void @foo5({{{.*}}, {.*}}, i8 {{.*}} signext {{.*}})
+struct s15 {
+  char arr[15];
+};
+struct s09 foo5(struct s15 sx, char a) {
+  struct s09 s9;
+  s9.arr[a] = sx.arr[a];
+  return s9;
+}
+
+// NOTE: The char type argument is passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} i8 @foo6({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo6({{.*}}, i8 {{.*}} signext {{.*}})
+char foo6(struct s06 s, char b) {
+  return s.arr[b];
+}
+
+// NOTE: The char type argument is passed via stack on both avr and avrtiny.
+// AVR:  define {{.*}} @foo7({{.*}}, i8 {{.*}})
+// TINY: define {{.*}} @foo7({{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} @foo7({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} @foo7({{.*}}, i8 {{.*}} signext {{.*}})
+struct s17 {
+  char arr[17];
+};
+char foo7(struct s17 s, char c) {
+  return s.arr[c];
+}
+
+// NOTE: The char type argument is passed via registers on avr but via stack on avrtiny.
+// AVR:  define {{.*}} @foo8({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} @foo8({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} @foo8({{.*}}, i8 {{.*}})
+struct s07 {
+  char arr[7];
+};
+char foo8(struct s07 s, char a) {
+  return s.arr[a];
+}
+
+// NOTE: All arguments are passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} i8 @foo9(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo9(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+char foo9(char a, char b) {
+  return a + b;
+}
+
+// NOTE: All arguments are passed via stack on both avr and avrtiny.
+// AVR:  define {{.*}} i8 @foo10({{.*}}, i8 {{.*}})
+// TINY: define {{.*}} i8 @foo10({{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} i8 @foo10({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} i8 @foo10({{.*}}, i8 

[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-01 Thread Ben Shi via Phabricator via cfe-commits
benshi001 added a comment.
Herald added a project: All.

This patch is a correct implementation against to the abundoned 
https://reviews.llvm.org/D120475


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120720/new/

https://reviews.llvm.org/D120720

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D120720: [clang][AVR] Implement standard calling convention for AVR and AVRTiny

2022-03-01 Thread Ben Shi via Phabricator via cfe-commits
benshi001 created this revision.
benshi001 added reviewers: aykevl, dylanmckay.
Herald added a subscriber: Jim.
benshi001 requested review of this revision.
Herald added subscribers: cfe-commits, jacquesguan.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120720

Files:
  clang/lib/Basic/Targets/AVR.cpp
  clang/lib/Basic/Targets/AVR.h
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/avr/argument.c

Index: clang/test/CodeGen/avr/argument.c
===
--- /dev/null
+++ clang/test/CodeGen/avr/argument.c
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -triple avr -target-cpu atmega328 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix AVR
+// RUN: %clang_cc1 -triple avr -target-cpu attiny40 -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefix TINY
+
+// NOTE: All arguments are passed in memory for functions with variable arguments.
+// AVR:  define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// TINY: define {{.*}} i8 @foo0(i8 {{.*}}, i8 {{.*}}, ...)
+// AVR-NOT:  define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+// TINY-NOT: define {{.*}} i8 @foo0(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}, ...)
+char foo0(char a, char b, ...) {
+  return a + b;
+}
+
+// NOTE: All arguments are passed via registers.
+// AVR:  define {{.*}} i8 @foo1(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} i8 @foo1(i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}})
+char foo1(char a, char b) {
+  return a + b;
+}
+
+// NOTE: The char type argument is passed via registers on both avr and avrtiny.
+// AVR:  define {{.*}} @foo2({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} @foo2({{.*}}, i8 {{.*}} signext {{.*}})
+struct s07 {
+  char arr[7];
+};
+struct s06 {
+  char arr[6];
+};
+struct s07 foo2(struct s06 s6, char a) {
+  struct s07 s7;
+  s7.arr[a] = s6.arr[a];
+  return s7;
+}
+
+// NOTE: The char type argument is passed via registers on avr but via stack on avrtiny.
+// AVR:  define {{.*}} @foo3({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} @foo3({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY: define {{.*}} @foo3({{.*}}, i8 {{.*}})
+struct s09 {
+  char arr[9];
+};
+struct s09 foo3(struct s06 s6, char a) {
+  struct s09 s9;
+  s9.arr[a] = s6.arr[a];
+  return s9;
+}
+
+// NOTE: The char type argument is passed via stack on both avr and avrtiny.
+// AVR:  define {{.*}} @foo4({{.*}}, i8 {{.*}})
+// TINY: define {{.*}} @foo4({{.*}}, i8 {{.*}})
+// AVR-NOT:  define {{.*}} @foo4({{.*}}, i8 {{.*}} signext {{.*}})
+// TINY-NOT: define {{.*}} @foo4({{.*}}, i8 {{.*}} signext {{.*}})
+struct s17 {
+  char arr[17];
+};
+char foo4(struct s17 s, char c) {
+  return s.arr[c];
+}
Index: clang/lib/CodeGen/TargetInfo.cpp
===
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -19,9 +19,9 @@
 #include "CodeGenFunction.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/Basic/DiagnosticFrontend.h"
-#include "clang/Basic/Builtins.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
 #include "clang/CodeGen/SwiftCallingConv.h"
 #include "llvm/ADT/SmallBitVector.h"
@@ -33,6 +33,7 @@
 #include "llvm/IR/IntrinsicsNVPTX.h"
 #include "llvm/IR/IntrinsicsS390.h"
 #include "llvm/IR/Type.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include  // std::sort
 
@@ -8272,32 +8273,83 @@
 
 namespace {
 class AVRABIInfo : public DefaultABIInfo {
+private:
+  // The total amount of registers can be used to pass parameters. It is 18 on
+  // AVR, or 8 on AVRTiny.
+  mutable unsigned ParamRegs;
+
 public:
-  AVRABIInfo(CodeGenTypes ) : DefaultABIInfo(CGT) {}
+  AVRABIInfo(CodeGenTypes , unsigned N)
+  : DefaultABIInfo(CGT), ParamRegs(N) {}
 
   ABIArgInfo classifyReturnType(QualType Ty) const {
-// A return struct with size less than or equal to 8 bytes is returned
-// directly via registers R18-R25.
-if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) <= 64)
+if (isAggregateTypeForABI(Ty)) {
+  // A return struct with size less than or equal to 8 bytes is returned
+  // directly via registers R18-R25.
+  if (getContext().getTypeSize(Ty) <= 64)
+return ABIArgInfo::getDirect();
+  // A return struct with size larger than 8 bytes is returned via a stack
+  // slot, along with a pointer to it as the function's implicit argument.
+  ParamRegs -= 2;
+  return getNaturalAlignIndirect(Ty);
+}
+// Otherwise we follow the default way which is compatible.
+return DefaultABIInfo::classifyReturnType(Ty);
+  }
+
+  ABIArgInfo classifyArgumentType(QualType Ty, unsigned ) const {
+unsigned TySize = getContext().getTypeSize(Ty);
+
+// An int8 type