Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang][AVR] Implement standard calling convention for AVR and AVRTiny
This patch implements avr-gcc's calling convention: https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention Reviewed By: aykevl Differential Revision: https://reviews.llvm.org/D120720
- Loading branch information
Showing
5 changed files
with
263 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 {{.*}} i8 @foo4({{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} i8 @foo4({{.*}}, i32 {{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} i8 @foo4({{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
char foo4(struct s15 a, long b, char c) { | ||
return a.arr[c]; | ||
} | ||
|
||
// NOTE: On avrtiny, `a` only costs 4 registers, though there are 2 vacant | ||
// registers, both `b` and `c` are passed via the stack. | ||
// AVR: define {{.*}} i8 @foo5(i32 {{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} i8 @foo5(i32 {{.*}}, i32 {{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} i8 @foo5(i32 {{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
char foo5(long a, long b, char c) { | ||
return c + 1; | ||
} | ||
|
||
// NOTE: All arguments are passed via the stack, though all registers are vacant. | ||
// AVR: define {{.*}} i8 @foo6({{.*}}, i8 {{.*}}) | ||
// AVR-NOT: define {{.*}} i8 @foo6({{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} i8 @foo6({{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} i8 @foo6({{.*}}, i8 {{.*}} signext {{.*}}) | ||
struct s32 { | ||
char arr[32]; | ||
}; | ||
char foo6(struct s32 a, char b) { | ||
return a.arr[b]; | ||
} | ||
|
||
// NOTE: All arguments are passed via registers on avr. While all arguments are passed | ||
// via the stack on avrtiny, though all registers are vacant. | ||
// AVR: define {{.*}} i8 @foo7({{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} i8 @foo7({{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} i8 @foo7({{.*}}, i8 {{.*}} signext {{.*}}) | ||
char foo7(struct s15 a, char b) { | ||
return a.arr[b]; | ||
} | ||
|
||
// NOTE: On avr, though `a` only cost 16 registers, `b` has to be passed via the | ||
// stack, since there is an implicit pointer argument costs 2 registers. | ||
// AVR: define {{.*}} @foo8({{.*}}, {{.*}}, i8 {{.*}}) | ||
// AVR-NOT: define {{.*}} @foo8({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} @foo8({{.*}}, {{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} @foo8({{.*}}, {{.*}}, i8 {{.*}} signext {{.*}}) | ||
struct s15 foo8(struct s15 a, char b) { | ||
a.arr[0] = b; | ||
return a; | ||
} | ||
|
||
// NOTE: On avrtiny, `b` has to be passed via the stack, since there is an | ||
// implicit pointer argument costs 2 registers. | ||
// AVR: define {{.*}} @foo9({{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} @foo9({{.*}}, i32 {{.*}}, i8 {{.*}}) | ||
// TINY-NOT: define {{.*}} @foo9({{.*}}, i32 {{.*}}, i8 {{.*}} signext {{.*}}) | ||
struct s15 foo9(long a, char b) { | ||
struct s15 x; | ||
x.arr[0] = b; | ||
return x; | ||
} | ||
|
||
// NOTE: All arguments are passed via registers, though there is an implicit | ||
// pointer argument costs 2 registers. | ||
// AVR: define {{.*}} @fooa({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}) | ||
// TINY: define {{.*}} @fooa({{.*}}, i8 {{.*}} signext {{.*}}, i8 {{.*}} signext {{.*}}) | ||
struct s15 fooa(char a, char b) { | ||
struct s15 x; | ||
x.arr[0] = a; | ||
x.arr[1] = b; | ||
return x; | ||
} |
Oops, something went wrong.