1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 23:29:39 +00:00

Merge branch 'master' into fptest

This commit is contained in:
mrdudz 2023-10-26 17:40:07 +02:00
commit bb2a367fcf
4 changed files with 649 additions and 47 deletions

View File

@ -167,6 +167,17 @@ int ED_IsLocQuasiConst (const ExprDesc* Expr)
int ED_IsLocZP (const ExprDesc* Expr)
/* Return true if the expression is in a location on a zeropage */
{
return ED_IsLocRegister (Expr) ||
(ED_IsLocConst (Expr) &&
Expr->Sym != 0 &&
(Expr->Sym->Flags & SC_ZEROPAGE) != 0);
}
#if !defined(HAVE_INLINE)
int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
@ -302,6 +313,23 @@ int ED_IsQuasiConstAddr (const ExprDesc* Expr)
int ED_IsStackAddr (const ExprDesc* Expr)
/* Return true if the expression denotes a fixed address on stack */
{
return ED_IsAddrExpr (Expr) && ED_IsLocStack (Expr);
}
int ED_IsZPInd (const ExprDesc* Expr)
/* Return true if the expression is located on the zeropage */
{
return ED_IsIndExpr (Expr) && ED_IsLocZP (Expr);
}
int ED_IsNullPtr (const ExprDesc* Expr)
/* Return true if the given expression is a NULL pointer constant */
{

View File

@ -369,6 +369,9 @@ int ED_IsLocQuasiConst (const ExprDesc* Expr);
*/
#endif
int ED_IsLocZP (const ExprDesc* Expr);
/* Return true if the expression is in a location on a zeropage */
#if defined(HAVE_INLINE)
INLINE int ED_IsLocPrimaryOrExpr (const ExprDesc* Expr)
/* Return true if the expression is E_LOC_PRIMARY or E_LOC_EXPR */
@ -572,6 +575,12 @@ int ED_IsQuasiConstAddr (const ExprDesc* Expr);
** This can be a constant address or a stack variable address.
*/
int ED_IsStackAddr (const ExprDesc* Expr);
/* Return true if the expression denotes a fixed address on stack */
int ED_IsZPInd (const ExprDesc* Expr);
/* Return true if the expression is located on the zeropage */
int ED_IsNullPtr (const ExprDesc* Expr);
/* Return true if the given expression is a NULL pointer constant */

View File

@ -280,13 +280,11 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** generated, and emit better code.
*/
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) ||
(ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) &&
((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) ||
(ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)))) {
(ED_IsConstAddr (&Arg2.Expr) || ED_IsZPInd (&Arg2.Expr)) &&
(ED_IsConstAddr (&Arg1.Expr) || ED_IsZPInd (&Arg1.Expr))) {
int Reg1 = ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr);
int Reg2 = ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr);
int Reg1 = ED_IsZPInd (&Arg1.Expr);
int Reg2 = ED_IsZPInd (&Arg2.Expr);
/* Drop the generated code */
RemoveCode (&Arg1.Expr.Start);
@ -342,9 +340,9 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
}
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr) &&
ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) &&
(Arg1.Expr.IVal - StackPtr) + Arg3.Expr.IVal < 256) {
ED_IsConstAddr (&Arg2.Expr) &&
ED_IsStackAddr (&Arg1.Expr) &&
ED_GetStackOffs (&Arg1.Expr, Arg3.Expr.IVal) < 256) {
/* It is possible to just use one index register even if the stack
** offset is not zero, by adjusting the offset to the constant
@ -353,7 +351,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** than 256. Register space is zero page, which means that the
** address calculation could overflow in the linker.
*/
int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) &&
int AllowOneIndex = !ED_IsLocZP (&Arg2.Expr) &&
!(ED_IsLocNone (&Arg2.Expr) && Arg2.Expr.IVal < 256);
/* Calculate the real stack offset */
@ -420,9 +418,9 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
}
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsRVal (&Arg2.Expr) && ED_IsLocStack (&Arg2.Expr) &&
(Arg2.Expr.IVal - StackPtr) + Arg3.Expr.IVal < 256 &&
ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) {
ED_IsStackAddr (&Arg2.Expr) &&
ED_GetStackOffs (&Arg2.Expr, Arg3.Expr.IVal) < 256 &&
ED_IsConstAddr (&Arg1.Expr)) {
/* It is possible to just use one index register even if the stack
** offset is not zero, by adjusting the offset to the constant
@ -431,7 +429,7 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** than 256. Register space is zero page, which means that the
** address calculation could overflow in the linker.
*/
int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) &&
int AllowOneIndex = !ED_IsLocZP (&Arg1.Expr) &&
!(ED_IsLocNone (&Arg1.Expr) && Arg1.Expr.IVal < 256);
/* Calculate the real stack offset */
@ -497,8 +495,8 @@ static void StdFunc_memcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
goto ExitPoint;
}
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsRVal (&Arg2.Expr) && ED_IsLocStack (&Arg2.Expr) &&
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsStackAddr (&Arg2.Expr) &&
(Offs = ED_GetStackOffs (&Arg2.Expr, 0)) == 0) {
/* Drop the generated code but leave the load of the first argument*/
@ -637,10 +635,9 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
*/
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsConstAbsInt (&Arg2.Expr) &&
((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) ||
(ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)))) {
(ED_IsConstAddr (&Arg1.Expr) || ED_IsZPInd (&Arg1.Expr))) {
int Reg = ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr);
int Reg = ED_IsZPInd (&Arg1.Expr);
/* Drop the generated code */
RemoveCode (&Arg1.Expr.Start);
@ -689,8 +686,8 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
if (ED_IsConstAbsInt (&Arg3.Expr) && Arg3.Expr.IVal <= 256 &&
ED_IsConstAbsInt (&Arg2.Expr) &&
ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) &&
(Arg1.Expr.IVal - StackPtr) + Arg3.Expr.IVal < 256) {
ED_IsStackAddr (&Arg1.Expr) &&
ED_GetStackOffs (&Arg1.Expr, Arg3.Expr.IVal) < 256) {
/* Calculate the real stack offset */
int Offs = ED_GetStackOffs (&Arg1.Expr, 0);
@ -836,7 +833,7 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
*/
if (ED_IsLocLiteral (&Arg2.Expr) &&
IS_Get (&WritableStrings) == 0 &&
GetLiteralSize (Arg2.Expr.V.LVal) == 1 &&
GetLiteralSize (Arg2.Expr.V.LVal) >= 1 &&
GetLiteralStr (Arg2.Expr.V.LVal)[0] == '\0') {
/* Drop the generated code so we have the first argument in the
@ -850,7 +847,7 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
/* We do now have Arg1 in the primary. Load the first character from
** this string and cast to int. This is the function result.
*/
IsArray = IsTypeArray (Arg1.Type) && ED_IsRVal (&Arg1.Expr);
IsArray = IsTypeArray (Arg1.Type) && ED_IsAddrExpr (&Arg1.Expr);
if (IsArray && ED_IsLocStack (&Arg1.Expr) &&
(Offs = ED_GetStackOffs (&Arg1.Expr, 0) < 256)) {
/* Drop the generated code */
@ -878,22 +875,20 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
}
} else if ((IS_Get (&CodeSizeFactor) >= 165) &&
((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) ||
(ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) &&
((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) ||
(ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr))) &&
(ED_IsConstAddr (&Arg2.Expr) || ED_IsZPInd (&Arg2.Expr)) &&
(ED_IsConstAddr (&Arg1.Expr) || ED_IsZPInd (&Arg1.Expr)) &&
(IS_Get (&EagerlyInlineFuncs) || (ECount1 > 0 && ECount1 < 256))) {
unsigned Entry, Loop, Fin; /* Labels */
const char* Load;
const char* Compare;
if (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)) {
if (ED_IsZPInd (&Arg1.Expr)) {
Load = "lda (%s),y";
} else {
Load = "lda %s,y";
}
if (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr)) {
if (ED_IsZPInd (&Arg2.Expr)) {
Compare = "cmp (%s),y";
} else {
Compare = "cmp %s,y";
@ -924,14 +919,13 @@ static void StdFunc_strcmp (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
g_defcodelabel (Fin);
} else if ((IS_Get (&CodeSizeFactor) > 190) &&
((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) ||
(ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) &&
(ED_IsConstAddr (&Arg2.Expr) || ED_IsZPInd (&Arg2.Expr)) &&
(IS_Get (&EagerlyInlineFuncs) || (ECount1 > 0 && ECount1 < 256))) {
unsigned Entry, Loop, Fin; /* Labels */
const char* Compare;
if (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr)) {
if (ED_IsZPInd (&Arg2.Expr)) {
Compare = "cmp (%s),y";
} else {
Compare = "cmp %s,y";
@ -1028,21 +1022,19 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** be generated. If such a situation is detected, throw away the
** generated, and emit better code.
*/
if (((ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr)) ||
(ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr))) &&
((ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) ||
(ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr))) &&
if ((ED_IsConstAddr (&Arg2.Expr) || ED_IsZPInd (&Arg2.Expr)) &&
(ED_IsConstAddr (&Arg1.Expr) || ED_IsZPInd (&Arg1.Expr)) &&
(IS_Get (&EagerlyInlineFuncs) ||
(ECount != UNSPECIFIED && ECount < 256))) {
const char* Load;
const char* Store;
if (ED_IsLVal (&Arg2.Expr) && ED_IsLocRegister (&Arg2.Expr)) {
if (ED_IsZPInd (&Arg2.Expr)) {
Load = "lda (%s),y";
} else {
Load = "lda %s,y";
}
if (ED_IsLVal (&Arg1.Expr) && ED_IsLocRegister (&Arg1.Expr)) {
if (ED_IsZPInd (&Arg1.Expr)) {
Store = "sta (%s),y";
} else {
Store = "sta %s,y";
@ -1069,9 +1061,9 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
goto ExitPoint;
}
if (ED_IsRVal (&Arg2.Expr) && ED_IsLocStack (&Arg2.Expr) &&
if (ED_IsStackAddr (&Arg2.Expr) &&
StackPtr >= -255 &&
ED_IsRVal (&Arg1.Expr) && ED_IsLocConst (&Arg1.Expr)) {
ED_IsConstAddr (&Arg1.Expr)) {
/* It is possible to just use one index register even if the stack
** offset is not zero, by adjusting the offset to the constant
@ -1080,7 +1072,7 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** than 256. Register space is zero page, which means that the
** address calculation could overflow in the linker.
*/
int AllowOneIndex = !ED_IsLocRegister (&Arg1.Expr) &&
int AllowOneIndex = !ED_IsLocZP (&Arg1.Expr) &&
!(ED_IsLocNone (&Arg1.Expr) && Arg1.Expr.IVal < 256);
/* Calculate the real stack offset */
@ -1116,8 +1108,8 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
goto ExitPoint;
}
if (ED_IsRVal (&Arg2.Expr) && ED_IsLocConst (&Arg2.Expr) &&
ED_IsRVal (&Arg1.Expr) && ED_IsLocStack (&Arg1.Expr) &&
if (ED_IsConstAddr (&Arg2.Expr) &&
ED_IsStackAddr (&Arg1.Expr) &&
StackPtr >= -255) {
/* It is possible to just use one index register even if the stack
@ -1127,7 +1119,7 @@ static void StdFunc_strcpy (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** than 256. Register space is zero page, which means that the
** address calculation could overflow in the linker.
*/
int AllowOneIndex = !ED_IsLocRegister (&Arg2.Expr) &&
int AllowOneIndex = !ED_IsLocZP (&Arg2.Expr) &&
!(ED_IsLocNone (&Arg2.Expr) && Arg2.Expr.IVal < 256);
/* Calculate the real stack offset */
@ -1234,9 +1226,13 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** at runtime.
*/
if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings) == 0) {
/* Get the length of the C string within the string literal.
** Note: Keep in mind that the literal could contain '\0' in it.
*/
size_t Len = strnlen (GetLiteralStr (Arg.V.LVal), GetLiteralSize (Arg.V.LVal) - 1);
/* Constant string literal */
ED_MakeConstAbs (Expr, GetLiteralSize (Arg.V.LVal) - 1, type_size_t);
ED_MakeConstAbs (Expr, Len, type_size_t);
/* We don't need the literal any longer */
ReleaseLiteral (Arg.V.LVal);
@ -1276,7 +1272,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** completely within the reach of a byte sized index register.
*/
if (ED_IsLocStack (&Arg) && IsArray && IsByteIndex &&
(Arg.IVal - StackPtr) + ECount < 256) {
ED_GetStackOffs (&Arg, ECount) < 256) {
/* Calculate the true stack offset */
int Offs = ED_GetStackOffs (&Arg, 0);
@ -1305,7 +1301,7 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
** get inlined if requested on the command line, since we cannot know how
** big the buffer actually is, so inlining is not always safe.
*/
if (ED_IsLocRegister (&Arg) && ED_IsLVal (&Arg) && IsPtr &&
if (ED_IsZPInd (&Arg) && IsPtr &&
IS_Get (&EagerlyInlineFuncs)) {
/* Generate the strlen code */

569
test/val/bug2207.c Normal file
View File

@ -0,0 +1,569 @@
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/********* Macros *********/
#define DEBUG_DETAIL 0
/* TODO: enable these when they can be compiled */
#define SKIP_VOID_RETURN_VALUE_TESTS 1
#define SKIP_INLINED_ARG_SIDE_EFFECT_TESTS 1
#define CHECK(C) \
if (!(C)) { \
++failures; \
print_header(); \
printf(" failed: expected %s\n", #C); \
}
#define CHECK_RANGE(L, R, D, N) \
index = my_memcmp(L, R, D, N); \
if (index >= 0) { \
++failures; \
print_header(); \
printf(" failed: %s vs %s dismatch at [%d]\n", #L, #R, index); \
}
#define MEM_SIZE 512
#define STACK_SIZE 160
#define ZP_SIZE 8
#define MAGIC_SIZE 129
#define BROKEN_STR "hello\0!"
#define BROKEN_STR_SIZE 6
#define BROKEN_STR_LEN 5
/********* Data *********/
unsigned failures;
int need_header = 1;
const char* test_header;
static int x;
static int y;
static int z;
static int index;
static char mem_dst[MEM_SIZE];
static char mem_src[MEM_SIZE];
static char mem_ori[MEM_SIZE];
#pragma data-name(push, "ZEROPAGE", "zp")
#pragma bss-name(push, "ZEROPAGE", "zp")
static char zp_src[ZP_SIZE];
static char zp_dst[ZP_SIZE];
static char zp_ori[ZP_SIZE];
static char* p_zp_src;
static char* p_zp_dst;
static char* p_zp_ori;
#pragma bss-name(pop)
#pragma data-name(pop)
/********* Helpers *********/
void my_memfill(void *dst, int init, size_t size)
{
unsigned i;
for (i = 0; i < size; ++i)
{
((char*)dst)[i] = init;
init += 3;
}
}
void my_memset(void *dst, int val, size_t size)
{
unsigned i;
for (i = 0; i < size; ++i)
{
((unsigned char *)dst)[i] = val;
}
}
void my_memcpy(void *dst, const void *src, size_t size)
{
unsigned i;
for (i = 0; i < size; ++i)
{
((char*)dst)[i] = ((char*)src)[i];
}
}
int my_memcmp(const void *dst, const void *src, int diff, size_t size)
{
unsigned i;
diff %= 256;
for (i = 0; i < size; ++i)
{
if ((unsigned char)(((unsigned char*)dst)[i] - ((unsigned char*)src)[i]) != diff)
{
#if DEBUG_DETAIL
/* DEBUG */
printf("%d vs %d\n", (unsigned char)(((unsigned char*)dst)[i] - ((unsigned char*)src)[i]), diff);
#endif
return i;
}
}
return -1;
}
void* mul_two(void* p, int* px)
{
*px *= 2;
return p;
}
void* add_one(void* p, int* px)
{
*px += 1;
return p;
}
void* negate(void* p, int* px)
{
*px = -*px;
return p;
}
void set_header(const char* name)
{
if (need_header == 0)
{
printf("\n");
}
test_header = name;
need_header = 1;
}
void print_header(void)
{
if (need_header)
{
need_header = 0;
printf("%s test\n", test_header);
}
}
/********* Tests *********/
/* memcpy */
void test_memcpy(void)
{
const char *name = 0;
unsigned size = 0;
void *p;
/* init */
my_memfill(mem_ori, 1000, sizeof mem_ori);
my_memfill(zp_ori, 1000, sizeof zp_ori);
p_zp_src = zp_src;
p_zp_dst = zp_dst;
p_zp_ori = zp_ori;
#if !SKIP_INLINED_ARG_SIDE_EFFECT_TESTS
/* arg3 == 0 */
set_header("p = memcpy(arg1, arg2, 0)");
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
x = 42;
y = -42;
z = 36;
p = memcpy(mul_two(mem_dst, &x), add_one(mem_src, &y), (negate(0, &z), 0));
CHECK(p == mem_dst);
CHECK(x == 84);
CHECK(y == -41);
CHECK(z == -36);
CHECK_RANGE(mem_dst, mem_ori, 2000, size);
CHECK_RANGE(mem_src, mem_ori, 1000, size);
#endif
#if !SKIP_INLINED_ARG_SIDE_EFFECT_TESTS
/* Check if the arguments are still generated if the return value is unused.
** We have this question since the first argument could be directly used as
** the return value when this function gets inlined.
*/
#if !SKIP_VOID_RETURN_VALUE_TESTS
set_header("(void)memcpy(arg1, arg2, 0)");
#else
set_header("memcpy(arg1, arg2, 0)");
#endif
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
x = 42;
y = -42;
z = 36;
#if !SKIP_VOID_RETURN_VALUE_TESTS
(void)
#endif
memcpy(mul_two(mem_dst, &x), add_one(mem_src, &y), (negate(0, &z), 0));
CHECK(x == 84);
CHECK(y == -41);
CHECK(z == -36);
CHECK_RANGE(mem_dst, mem_ori, 2000, size);
CHECK_RANGE(mem_src, mem_ori, 1000, size);
#endif
/* The memcpy inliner will give up with further optimizations if any of
** the arguments have side effects.
*/
/* arg1: const addr, arg2: const addr, arg3 <= 129 */
set_header("memcpy(const_addr_1, const_addr_2, 129) w/ side-effects");
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
x = 42;
y = -42;
z = 36;
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(mul_two(mem_dst, &x), add_one(mem_src, &y), (negate(0, &z), MAGIC_SIZE));
size = MAGIC_SIZE;
CHECK(p == mem_dst);
CHECK(x == 84);
CHECK(y == -41);
CHECK(z == -36);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, MEM_SIZE - size);
/* arg1: (void*)ptr, arg2: const_addr_2 */
set_header("memcpy((void*)ptr, const_addr_2, 129)");
{
void *ptr = mem_dst;
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy((void*)ptr, mem_src, MAGIC_SIZE);
size = MAGIC_SIZE;
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, MEM_SIZE - size);
}
/* arg1: const addr, arg2: const addr, arg3 <= 129 */
set_header("memcpy(const_addr_1, const_addr_2, 129)");
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(mem_dst, mem_src, MAGIC_SIZE);
size = MAGIC_SIZE;
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, MEM_SIZE - size);
/* arg1: const addr, arg2: const addr, arg3 <= 256 */
set_header("memcpy(const_addr_1, const_addr_2, 256)");
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
my_memfill(mem_src, 2000, size);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(mem_dst, mem_src, 256);
size = 256;
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, size - size);
/* arg1: ptr on zp, arg2: ptr on zp, arg3 <= 256 */
set_header("memcpy(p_on_zp_1, p_on_zp_2, 4)");
/* We cannot allocate 256 bytes on the zeropage, unfortunately */
my_memfill(zp_dst, 3000, ZP_SIZE);
my_memfill(zp_src, 2000, ZP_SIZE);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(p_zp_dst, p_zp_src, ZP_SIZE / 2);
size = ZP_SIZE / 2;
CHECK(p == zp_dst);
CHECK_RANGE(zp_dst, zp_ori, 1000, size);
CHECK_RANGE(zp_dst + size, zp_ori + size, 2000, ZP_SIZE - size);
/* arg1: on stack, arg2: const addr, arg3 <= 129 */
set_header("memcpy(on_stack_1, const_addr_2, 129)");
{
char sp_dst[STACK_SIZE];
my_memfill(sp_dst, 3000, STACK_SIZE);
my_memfill(mem_src, 2000, STACK_SIZE);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(sp_dst, mem_src, MAGIC_SIZE);
size = MAGIC_SIZE;
CHECK(p == sp_dst);
CHECK_RANGE(sp_dst, mem_ori, 1000, size);
CHECK_RANGE(sp_dst + size, mem_ori + size, 2000, STACK_SIZE - size);
}
/* arg1: on stack, arg2: const addr, arg3 <= 256 */
set_header("memcpy(on_stack_1, const_addr_2, 144)");
{
char sp_dst[STACK_SIZE];
/* We cannot allocate 256 bytes on the stack, unfortunately */
my_memfill(sp_dst, 3000, STACK_SIZE);
my_memfill(mem_src, 2000, STACK_SIZE);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(sp_dst, mem_src, 144);
size = 144;
CHECK(p == sp_dst);
CHECK_RANGE(sp_dst, mem_ori, 1000, size);
CHECK_RANGE(sp_dst + size, mem_ori + size, 2000, STACK_SIZE - size);
}
/* arg1: const addr, arg2: on stack, arg3 <= 129 */
set_header("memcpy(const_addr_1, on_stack_2, 129)");
{
char sp_src[STACK_SIZE];
/* We cannot allocate 256 bytes on the stack, unfortunately */
my_memfill(mem_dst, 3000, STACK_SIZE);
my_memfill(sp_src, 2000, STACK_SIZE);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(mem_dst, sp_src, 129);
size = 129;
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, STACK_SIZE - size);
}
/* arg1: const addr, arg2: on stack, arg3 <= 256 */
set_header("memcpy(const_addr_1, on_stack_2, 144)");
{
char sp_src[STACK_SIZE];
/* We cannot allocate 256 bytes on the stack, unfortunately */
my_memfill(mem_dst, 3000, STACK_SIZE);
my_memfill(sp_src, 2000, STACK_SIZE);
/* memcpy size here must be an integer constant to allow the optimization */
p = memcpy(mem_dst, sp_src, 144);
size = 144;
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_ori, 1000, size);
CHECK_RANGE(mem_dst + size, mem_ori + size, 2000, STACK_SIZE - size);
}
}
/* memset */
void test_memset(void)
{
const char *name = 0;
unsigned size = 0;
void *p;
/* init */
my_memfill(mem_ori, 1000, sizeof mem_ori);
my_memfill(zp_ori, 1000, sizeof zp_ori);
p_zp_dst = zp_dst;
p_zp_ori = zp_ori;
#if !SKIP_INLINED_ARG_SIDE_EFFECT_TESTS
/* arg3 == 0 */
set_header("p = memset(arg1, arg2, 0)");
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
x = 42;
y = -42;
z = 36;
p = memset(mul_two(mem_dst, &x), (add_one(0, &y), 42), (negate(0, &z), 0));
CHECK(p == mem_dst);
CHECK(x == 84);
CHECK(y == -41);
CHECK(z == -36);
CHECK_RANGE(mem_dst, mem_ori, 2000, size);
#endif
#if !SKIP_INLINED_ARG_SIDE_EFFECT_TESTS
/* Check if the arguments are still generated if the return value is unused.
** We have this question since the first argument could be directly used as
** the return value when this function gets inlined.
*/
#if !SKIP_VOID_RETURN_VALUE_TESTS
set_header("(void)memset(arg1, arg2, 0)");
#else
set_header("memset(arg1, arg2, 0)");
#endif
size = MEM_SIZE;
my_memfill(mem_dst, 3000, size);
x = 42;
y = -42;
z = 36;
#if !SKIP_VOID_RETURN_VALUE_TESTS
(void)
#endif
memset(mul_two(mem_dst, &x), (add_one(0, &y), 42), (negate(0, &z), 0));
CHECK(x == 84);
CHECK(y == -41);
CHECK(z == -36);
CHECK_RANGE(mem_dst, mem_ori, 2000, size);
#endif
}
/* strcmp */
void test_strcmp(void)
{
const char *name = 0;
unsigned size = 0;
int res = 0;
/* init */
p_zp_dst = zp_dst;
/* Compared to zero-length C string literal */
set_header("strcmp(arg1, \"\\0Z\")");
{
char str[] = "AA";
size = sizeof str;
my_memcpy(zp_dst, str, size);
x = 42;
y = -42;
res = strcmp(zp_dst, "\0Z");
CHECK(res > 0);
#if !SKIP_INLINED_ARG_SIDE_EFFECT_TESTS
res = strcmp(mul_two(p_zp_dst, &x), (add_one(0, &y), "\0Z"));
CHECK(res > 0);
CHECK(x == 84);
CHECK(y == -41);
#endif
}
}
/* strcpy */
void test_strcpy(void)
{
const char *name = 0;
unsigned size = 0;
void *p;
char stack_dst[ZP_SIZE];
char stack_src[ZP_SIZE];
/* init */
{
char str[] = BROKEN_STR;
size = BROKEN_STR_LEN + 1;
my_memfill(mem_src, 1000, ZP_SIZE);
my_memfill(stack_src, 1000, ZP_SIZE);
my_memfill(zp_src, 1000, ZP_SIZE);
my_memcpy(mem_src, str, size);
my_memcpy(stack_src, str, size);
my_memcpy(zp_src, str, size);
p_zp_src = zp_src;
p_zp_dst = zp_dst;
p_zp_dst = zp_dst;
}
/* arg1: const addr, arg2: const addr */
set_header("strcpy(const_addr_1, const_addr_2)");
my_memfill(mem_dst, 2000, ZP_SIZE);
size = BROKEN_STR_LEN + 1;
p = strcpy(mem_dst, mem_src);
CHECK(p == mem_dst);
CHECK_RANGE(mem_dst, mem_src, 0, size);
CHECK_RANGE(mem_dst + size, mem_src + size, 1000, ZP_SIZE - size);
/* arg1: ptr on zp, arg2: ptr on zp */
set_header("strcpy(p_on_zp_1, p_on_zp_2)");
my_memfill(zp_dst, 2000, ZP_SIZE);
size = BROKEN_STR_LEN + 1;
p = strcpy(zp_dst, zp_src);
CHECK(p == zp_dst);
CHECK_RANGE(zp_dst, zp_src, 0, size);
CHECK_RANGE(zp_dst + size, zp_src + size, 1000, ZP_SIZE - size);
/* arg1: on stack, arg2: on stack */
set_header("strcpy(on_stack_1, on_stack_2)");
my_memfill(stack_dst, 2000, ZP_SIZE);
size = BROKEN_STR_LEN + 1;
p = strcpy(stack_dst, stack_src);
CHECK(p == stack_dst);
CHECK_RANGE(stack_dst, stack_src, 0, size);
CHECK_RANGE(stack_dst + size, stack_src + size, 1000, ZP_SIZE - size);
/* TODO: args side-effects tests */
}
/* strlen */
void test_strlen(void)
{
const char *name = 0;
size_t len;
/* init */
{
char str[] = BROKEN_STR;
my_memcpy(mem_ori, str, ZP_SIZE);
//my_memcpy(stack_ori, str, ZP_SIZE);
my_memcpy(zp_ori, str, ZP_SIZE);
p_zp_ori = zp_ori;
}
/* arg1: string_literal */
set_header("strlen(\"hello\\0!\")");
x = 42;
y = -42;
len = strlen((mul_two(0, &x), BROKEN_STR));
(void)strlen((add_one(0, &y), BROKEN_STR));
CHECK(len == BROKEN_STR_LEN);
CHECK(x == 84);
CHECK(y == -41);
/* arg1: array with const addr */
set_header("strlen(array_const_addr[8])");
x = 42;
y = -42;
len = strlen((mul_two(0, &x), zp_ori));
(void)strlen((add_one(0, &y), zp_ori));
CHECK(len == BROKEN_STR_LEN);
CHECK(x == 84);
CHECK(y == -41);
/* arg1: array on stack */
set_header("strlen(array_on_stack[8])");
{
char p_on_stack[] = BROKEN_STR;
x = 42;
y = -42;
len = strlen((mul_two(0, &x), p_on_stack));
strlen((add_one(0, &y), p_on_stack));
CHECK(sizeof p_on_stack == 8);
CHECK(len == BROKEN_STR_LEN);
CHECK(x == 84);
CHECK(y == -41);
}
/* arg1: ptr on zp */
set_header("strlen(ptr_on_zp)");
x = 42;
y = -42;
len = strlen((mul_two(0, &x), p_zp_ori));
(void)strlen((add_one(0, &y), p_zp_ori));
CHECK(len == BROKEN_STR_LEN);
CHECK(x == 84);
CHECK(y == -41);
}
int main(void)
{
test_memcpy();
test_memset();
test_strcmp();
test_strcpy();
test_strlen();
if (failures > 0)
{
printf("failed items: %u\n", failures);
}
return failures;
}