blob: 60f09edb684d739bf8bff85d1aaf17c2b7444103 [file] [log] [blame]
/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Tests if the ABI for returning structures matches.
*
* We have 4 modules, two compiled by one compiler and two by the other.
* CC1: MODULE0 and MODULE3, CC2: MODULE1 and MODULE2
* Overall structure is this:
* MODULE 1 || MODULE 2
* main():
* test_type()
* ^^--return/check--^^
* mod0_type() <--return/check-- mod1_type()
* ^^--return/check--^^
* mod3_type() --return/check--> mod2_type()
*
* So, CC1 returns stuff to CC2 -> CC2 -> CC1 -> CC1
*
* To see the pre-processor-generated source for MODULE${X}
*
* gcc file.c -E -o - -DMODULE${X} | indent | less
*/
#include "native_client/tests/callingconv_case_by_case/useful_structs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Trick inter-procedural constant propagation by adding some branching.
* This shouldn't happen with LLVM since we have split every function into
* separate native .o files, but... just in case the build changes.
* Also tag each function as noinline... just in case.
*/
#if defined(MODULE0)
int should_be_true;
#else
extern int should_be_true;
#endif
/**********************************************************************/
/* The actual test code structure (which is divided into 4 modules). */
#define GENERATE_FOR_MODULE3(TYPE) \
TYPE mod3_##TYPE(void) __attribute__((noinline)); \
TYPE mod3_##TYPE(void) { \
if (should_be_true) { \
TYPE z = k##TYPE; \
CHECK_##TYPE(z); \
printf("Made it to mod3_" #TYPE "\n"); \
return z; \
} else { \
TYPE z; \
printf("should_be_true is not true for mod3_" #TYPE "\n"); \
memset((void*)&z, 0, sizeof z); \
return z; \
} \
}
#define GENERATE_FOR_MODULE2(TYPE) \
extern TYPE mod3_##TYPE(void) __attribute__((noinline)); \
TYPE mod2_##TYPE(void) __attribute__((noinline)); \
TYPE mod2_##TYPE(void) { \
if (should_be_true) { \
TYPE z = mod3_##TYPE(); \
CHECK_##TYPE(z); \
printf("Made it to mod2_" #TYPE "\n"); \
return z; \
} else { \
TYPE z; \
printf("should_be_true is not true for mod2_" #TYPE "\n"); \
memset((void*)&z, 0, sizeof z); \
return z; \
} \
}
#define GENERATE_FOR_MODULE1(TYPE) \
extern TYPE mod2_##TYPE(void) __attribute__((noinline)); \
TYPE mod1_##TYPE(void) __attribute__((noinline)); \
TYPE mod1_##TYPE(void) { \
if (should_be_true) { \
TYPE z = mod2_##TYPE(); \
CHECK_##TYPE(z); \
printf("Made it to mod1_" #TYPE "\n"); \
return z; \
} else { \
TYPE z; \
printf("should_be_true is not true for mod1_" #TYPE "\n"); \
memset((void*)&z, 0, sizeof z); \
return z; \
} \
}
#define GENERATE_FOR_MODULE0(TYPE) \
extern TYPE mod1_##TYPE(void) __attribute__((noinline)); \
TYPE mod0_##TYPE(void) __attribute__((noinline)); \
TYPE mod0_##TYPE(void) { \
if (should_be_true) { \
TYPE z = mod1_##TYPE(); \
CHECK_##TYPE(z); \
printf("Made it to mod0_" #TYPE "\n"); \
return z; \
} else { \
TYPE z; \
printf("should_be_true is not true for mod0_" #TYPE "\n"); \
memset((void*)&z, 0, sizeof z); \
return z; \
} \
} \
void test_##TYPE(void) { \
TYPE z; \
z = mod0_##TYPE(); \
CHECK_##TYPE(z); \
}
#undef DO_FOR_TYPE
#if defined(MODULE0)
#define DO_FOR_TYPE GENERATE_FOR_MODULE0
#elif defined(MODULE1)
#define DO_FOR_TYPE GENERATE_FOR_MODULE1
#elif defined(MODULE2)
#define DO_FOR_TYPE GENERATE_FOR_MODULE2
#elif defined(MODULE3)
#define DO_FOR_TYPE GENERATE_FOR_MODULE3
#else
#error "Must define MODULE0. or MODULE1, 2 or 3 in preprocessor!"
#endif /* defined(MODULE0) */
#include "native_client/tests/callingconv_case_by_case/for_each_type.h"
#undef DO_FOR_TYPE
/* Place Main in Module 0 */
#if defined(MODULE0)
int main(int argc, char* argv[]) {
/* Trick inliners by making calls only happen based on external values. */
should_be_true = 0;
/* This should always be true when running this test. */
if (argc != 55) {
should_be_true = 1;
}
/* Set NOT_DECLARING_DEFINING to tell for_each_type.h that this is not
* for declarations and definition specific stuff like extern "C".
*/
#define NOT_DECLARING_DEFINING 1
#define CALL_TEST(TYPE) \
test_##TYPE();
#define DO_FOR_TYPE CALL_TEST
#include "native_client/tests/callingconv_case_by_case/for_each_type.h"
#undef DO_FOR_TYPE
#undef NOT_DECLARING_DEFINING
return 0;
}
#endif /* defined(MODULE1) */