summaryrefslogtreecommitdiff
path: root/support/regression/tests/cse.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /support/regression/tests/cse.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'support/regression/tests/cse.c')
-rw-r--r--support/regression/tests/cse.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/support/regression/tests/cse.c b/support/regression/tests/cse.c
new file mode 100644
index 0000000..9d80f23
--- /dev/null
+++ b/support/regression/tests/cse.c
@@ -0,0 +1,401 @@
+/* Test CSE - make sure CSE does not use stale data
+
+ */
+
+#include <testfwk.h>
+
+/* Need to locate a variable at an absolute address, but without */
+/* the linker's help. Pick an address and address space that is */
+/* likely free based on cpu and compile model. If ABSADDR is */
+/* left undefined, the tests that needs it will be skipped. */
+#if defined(SDCC) || defined(__SDCC)
+# if defined(SDCC_mcs51) || defined(__SDCC_mcs51)
+# if defined(SDCC_MODEL_LARGE) || defined(__SDCC_MODEL_LARGE)
+# define ABSADDRSPACE __xdata
+# define ABSADDR 0x8000
+# else
+# define ABSADDRSPACE __data
+# define ABSADDR 0x70
+# endif
+# endif
+# if defined(SDCC_ds390) || defined(__SDCC_ds390)
+# define ABSADDRSPACE __xdata
+# define ABSADDR 0x8000
+# endif
+# if defined(SDCC_hc08) || defined(__SDCC_s08)
+# define ABSADDRSPACE __xdata
+# define ABSADDR 0x7f00
+# endif
+# if defined(SDCC_z80) || defined(__SDCC_z80)
+# define ABSADDRSPACE __xdata
+# define ABSADDR 0x7f00
+# endif
+#endif
+
+
+typedef struct {
+ unsigned char x1;
+ unsigned char x2;
+ unsigned char *p;
+} packet_t;
+
+unsigned char gx;
+unsigned char *px;
+
+packet_t gpacket;
+#ifdef ABSADDR
+# define apacket1 (*((ABSADDRSPACE packet_t *)ABSADDR))
+ABSADDRSPACE packet_t __at ABSADDR apacket2;
+#endif
+
+unsigned char a1,a2,a3,a4,a5;
+
+void
+setgx(unsigned char x)
+{
+ gx = x;
+}
+
+unsigned char
+passthrough(unsigned char i)
+{
+ return i;
+}
+
+void
+zeroAndKeepAddress(unsigned char *p)
+{
+ px = p;
+ *p = 0;
+}
+
+void
+keepAddressFromPacket(packet_t *pp)
+{
+ px = pp->p;
+}
+
+void
+incIndirect(void)
+{
+ (*px)++;
+}
+
+packet_t *
+getaddrgpacket(void)
+{
+ return &gpacket;
+}
+
+void
+incx1(packet_t *pp)
+{
+ pp->x1++;
+}
+
+void
+incx2(packet_t *pp)
+{
+ pp->x2++;
+}
+
+void
+incgpx1(void)
+{
+ gpacket.x1++;
+}
+
+/* Be sneaky and define this later so that the addrtaken flag of gx is not */
+/* set until after the test functions are compiled. Not important now, but */
+/* this should remove the temptation to misuse reliance on addrtaken later. */
+unsigned char * getaddrgx(void);
+
+
+/* The ASSERT macro, since it branches based on a condition, will break up a */
+/* extended basic block. So to test for CSE problems within a single EBBlock */
+/* we will save intermediate results in global variables a1..a5 and do all */
+/* of the ASSERTs at the end of the function. For some tests it may make */
+/* more sense to use local variables, but I'm intentionally trying to keep */
+/* register pressure low. */
+
+void
+test_FuncCall1(void)
+{
+ unsigned char lx;
+
+ gx = 1;
+ setgx(2);
+ /* Cannot CSE global variable assignment across function call */
+ a1 = gx; /* ASSERT(gx == 2) */
+
+ lx = gx;
+ setgx(3);
+ /* Cannot CSE global variable read across function call */
+ a2 = gx; /* ASSERT(gx == 3) */
+ a3 = lx; /* ASSERT(lx == 2) */
+
+ lx = gx<<1;
+ a4 = lx; /* ASSERT(lx == 6) */
+ setgx(1);
+ lx = gx<<1;
+ /* Cannot CSE expression based on global variable across function call */
+ a5 = lx; /* ASSERT(lx == 2) */
+
+ ASSERT(a1 == 2);
+ ASSERT(a2 == 3);
+ ASSERT(a3 == 2);
+ ASSERT(a4 == 6);
+ ASSERT(a5 == 2);
+}
+
+void
+test_FuncCall2(void)
+{
+ unsigned char lx,ly;
+
+ lx = passthrough(2);
+ ly = lx<<1;
+ zeroAndKeepAddress(&lx);
+
+ /* Cannot CSE local variable if a pointer to it was passed as parameter */
+ a1 = lx; /* ASSERT(lx == 0) */
+
+ incIndirect();
+ /* Cannot CSE local variable across function call even if its address */
+ /* was not a parameter if its address was taken at all */
+ a2 = lx; /* ASSERT(lx == 1) */
+
+
+ a3 = ly; /* ASSERT(ly == 4) */
+ ly = lx<<1;
+ /* Cannot CSE expression based on local variable whose address was */
+ /* taken across function call */
+ a4 = ly; /* ASSERT(ly == 2) */
+
+ ASSERT(a1 == 0);
+ ASSERT(a2 == 1);
+ ASSERT(a3 == 4);
+ ASSERT(a4 == 2);
+}
+
+void
+test_FuncCall3(void)
+{
+ unsigned char lx,ly;
+
+ lx = passthrough(2);
+ ly = lx<<1;
+ px = &lx;
+ incIndirect();
+ /* Cannot CSE local variable across function call if address was taken at all */
+ a1 = lx; /* ASSERT(lx == 3) */
+
+ a2 = ly; /* ASSERT(ly == 4) */
+ ly = lx<<1;
+ /* Cannot CSE expression based on local variable whose address was */
+ /* taken across function call */
+ a3 = ly; /* ASSERT(ly == 6) */
+
+ ASSERT(a1 == 3);
+ ASSERT(a2 == 4);
+ ASSERT(a3 == 6);
+}
+
+void
+test_FuncCall4(void)
+{
+ packet_t packet1,packet2;
+
+ packet1.p = &packet2.x1;
+ keepAddressFromPacket(&packet1);
+ packet2.x1 = 1;
+ packet2.x2 = 3;
+ incIndirect();
+ /* Cannot CSE members of local variables whose address was taken */
+ /* across function call */
+ a1 = packet2.x1; /* ASSERT(packet2.x1 == 2) */
+ a2 = packet2.x2; /* ASSERT(packet2.x2 == 3) */
+
+ ASSERT(a1 == 2);
+ ASSERT(a2 == 3);
+}
+
+void
+test_FuncCall5(void)
+{
+ packet_t *pp;
+ unsigned char i;
+
+ gpacket.x1 = 1;
+ gpacket.x2 = 10;
+ pp = getaddrgpacket();
+
+ i = pp->x1;
+ a1 = i; /* ASSERT(i == 1) */
+ incx1(pp);
+ i = pp->x1;
+ a2 = i; /* ASSERT(i == 2) */
+ i = pp->x2;
+ a3 = i; /* ASSERT(i == 10) */
+ incx2(pp);
+ i = pp->x2;
+ a4 = i; /* ASSERT(i == 11) */
+
+ ASSERT(a1 == 1);
+ ASSERT(a2 == 2);
+ ASSERT(a3 == 10);
+ ASSERT(a4 == 11);
+}
+
+void
+test_FuncCall6(void)
+{
+ unsigned char lx;
+
+ lx = passthrough(1);
+ gpacket.x1 = lx;
+ incgpx1();
+ lx = gpacket.x1;
+ ASSERT(lx == 2);
+}
+
+/* test_Struct1 through test_Struct4 are checking for cases in which */
+/* operand keys are erroneously equal or unassigned, causing CSE to */
+/* use the wrong substitution. */
+void
+test_Struct1(void)
+{
+ packet_t packet;
+ unsigned char one;
+ unsigned char ten;
+
+ one = passthrough(1);
+ ten = passthrough(10);
+
+ gx = 100;
+ packet.x1 = one;
+ packet.x2 = ten;
+ setgx(packet.x2);
+ /* CSE of "apacket.x2" allowed above , but make sure it was x2 not x1*/
+ ASSERT(gx == 10);
+}
+
+void
+test_Struct2(void)
+{
+ unsigned char one;
+ unsigned char ten;
+
+ one = passthrough(1);
+ ten = passthrough(10);
+
+ gx = 100;
+ gpacket.x1 = one;
+ gpacket.x2 = ten;
+ setgx(gpacket.x2);
+ /* CSE of "apacket.x2" allowed above , but make sure it was x2 not x1*/
+ ASSERT(gx == 10);
+}
+
+void
+test_Struct3(void)
+{
+#ifdef ABSADDR
+ unsigned char one;
+ unsigned char ten;
+
+ one = passthrough(1);
+ ten = passthrough(10);
+ apacket1.x2 = ten;
+
+ setgx(100);
+ apacket1.x1 = one;
+ setgx(apacket1.x2);
+ /* CSE must not substitute x1 in place of x2 */
+ ASSERT(gx == 10);
+#endif
+}
+
+void
+test_Struct4(void)
+{
+#ifdef ABSADDR
+ unsigned char one;
+ unsigned char ten;
+
+ one = passthrough(1);
+ ten = passthrough(10);
+ apacket2.x2 = ten;
+
+ setgx(100);
+ apacket2.x1 = one;
+ setgx(apacket2.x2);
+ /* CSE must not substitute x1 in place of x2 */
+ ASSERT(gx == 10);
+#endif
+}
+
+void
+test_Struct5(void)
+{
+#ifndef __SDCC_pdk14 // Lack of memory - see RFE #605
+ packet_t *pp1;
+ packet_t *pp2;
+ unsigned char lx;
+
+ pp1 = getaddrgpacket();
+ pp2 = getaddrgpacket();
+
+ /* Since the declarations of pp1 and pp2 did not use the restrict */
+ /* qualifier, the compiler must assume they might point to the */
+ /* same object and so should not CSE pointer dereferences across */
+ /* other pointer dereferenced assingments of the same type. */
+ gpacket.x1 = 0;
+ pp1->x1 = 1;
+ lx = pp2->x1;
+ a1 = lx;
+
+ pp1->x1 = 2;
+ lx = pp2->x1;
+ a2 = lx;
+
+ pp2->x1 = 3;
+ lx = pp1->x1;
+ a3 = lx;
+
+ ASSERT(a1 == 1);
+ ASSERT(a2 == 2);
+ ASSERT(a3 == 3);
+#endif
+}
+
+void
+test_Global1(void)
+{
+#ifndef __SDCC_pdk14 // Lack of memory - see RFE #605
+ unsigned char lx;
+ unsigned char *px;
+
+ /* Since the declaration of px did not use the restrict */
+ /* qualifier, the compiler must assume it might point */
+ /* to a global variable and so should not CSE any */
+ /* read of or expression using a global variable. */
+ gx = 0;
+ px = getaddrgx();
+ lx = gx<<1;
+ a1 = lx;
+ *px = 1;
+ lx = gx<<1;
+ a2 = lx;
+
+ ASSERT(a1 == 0);
+ ASSERT(a2 == 2);
+#endif
+}
+
+/* Hide taking the address of gx by defining this function last */
+unsigned char
+*getaddrgx(void)
+{
+ return &gx;
+}