|  | //===- subzero/crosstest/test_calling_conv_main.cpp - Driver for tests ----===// | 
|  | // | 
|  | //                        The Subzero Code Generator | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains the driver for cross testing the compatibility of | 
|  | // calling conventions. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /* crosstest.py --test=test_calling_conv.cpp               \ | 
|  | --driver=test_calling_conv_main.cpp --prefix=Subzero_   \ | 
|  | --output=test_calling_conv */ | 
|  |  | 
|  | #include <cstring> | 
|  | #include <iostream> | 
|  | #include <sstream> | 
|  |  | 
|  | #include "test_calling_conv.h" | 
|  |  | 
|  | namespace Subzero_ { | 
|  | #include "test_calling_conv.h" | 
|  | } | 
|  |  | 
|  | // The crosstest code consists of caller / callee function pairs. | 
|  | // | 
|  | // The caller function initializes a list of arguments and calls the | 
|  | // function located at Callee. | 
|  | // | 
|  | // The callee function writes the argument numbered ArgNum into the | 
|  | // location pointed to by Buf. | 
|  | // | 
|  | // testCaller() tests that caller functions, as compiled by Subzero and | 
|  | // llc, pass arguments to the callee in the same way.  The Caller() and | 
|  | // Subzero_Caller() functions both call the same callee (which has been | 
|  | // compiled by llc).  The result in the global buffer is compared to | 
|  | // check that it is the same value after the calls by both callers. | 
|  | // | 
|  | // testCallee() runs the same kind of test, except that the functions | 
|  | // Callee() and Subzero_Callee() are being tested to ensure that both | 
|  | // functions receive arguments from the caller in the same way.  The | 
|  | // caller is compiled by llc. | 
|  |  | 
|  | size_t ArgNum; | 
|  | CalleePtrTy Callee; | 
|  | char *Buf; | 
|  |  | 
|  | const static size_t BUF_SIZE = 16; | 
|  |  | 
|  | std::string bufAsString(const char Buf[BUF_SIZE]) { | 
|  | std::ostringstream OS; | 
|  | for (size_t i = 0; i < BUF_SIZE; ++i) { | 
|  | if (i > 0) | 
|  | OS << " "; | 
|  | OS << (unsigned)Buf[i]; | 
|  | } | 
|  | return OS.str(); | 
|  | } | 
|  |  | 
|  | void testCaller(size_t &TotalTests, size_t &Passes, size_t &Failures) { | 
|  | static struct { | 
|  | const char *CallerName, *CalleeName; | 
|  | size_t Args; | 
|  | void (*Caller)(void); | 
|  | void (*Subzero_Caller)(void); | 
|  | CalleePtrTy Callee; | 
|  | } Funcs[] = { | 
|  | #ifdef MIPS32 | 
|  | #define X(caller, callee, argc)                                                \ | 
|  | {                                                                            \ | 
|  | STR(caller), STR(callee), argc, &caller, &Subzero_::caller,                \ | 
|  | reinterpret_cast<CalleePtrTy>(&Subzero_::callee),                      \ | 
|  | }                                                                            \ | 
|  | , | 
|  | TEST_FUNC_TABLE | 
|  | #undef X | 
|  | #else | 
|  | #define X(caller, callee, argc)                                                \ | 
|  | {                                                                            \ | 
|  | STR(caller), STR(callee), argc, &caller, &Subzero_::caller,                \ | 
|  | reinterpret_cast<CalleePtrTy>(&callee),                                \ | 
|  | }                                                                            \ | 
|  | , | 
|  | TEST_FUNC_TABLE | 
|  | #undef X | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs); | 
|  |  | 
|  | for (size_t f = 0; f < NumFuncs; ++f) { | 
|  | char BufLlc[BUF_SIZE], BufSz[BUF_SIZE]; | 
|  | Callee = Funcs[f].Callee; | 
|  |  | 
|  | for (size_t i = 0; i < Funcs[f].Args; ++i) { | 
|  | memset(BufLlc, 0xff, sizeof(BufLlc)); | 
|  | memset(BufSz, 0xff, sizeof(BufSz)); | 
|  |  | 
|  | ArgNum = i; | 
|  |  | 
|  | Buf = BufLlc; | 
|  | Funcs[f].Caller(); | 
|  |  | 
|  | Buf = BufSz; | 
|  | Funcs[f].Subzero_Caller(); | 
|  |  | 
|  | ++TotalTests; | 
|  | if (!memcmp(BufLlc, BufSz, sizeof(BufLlc))) { | 
|  | ++Passes; | 
|  | } else { | 
|  | ++Failures; | 
|  | std::cout << "testCaller(Caller=" << Funcs[f].CallerName | 
|  | << ", Callee=" << Funcs[f].CalleeName << ", ArgNum=" << ArgNum | 
|  | << ")\nsz =" << bufAsString(BufSz) | 
|  | << "\nllc=" << bufAsString(BufLlc) << "\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void testCallee(size_t &TotalTests, size_t &Passes, size_t &Failures) { | 
|  | static struct { | 
|  | const char *CallerName, *CalleeName; | 
|  | size_t Args; | 
|  | void (*Caller)(void); | 
|  | CalleePtrTy Callee, Subzero_Callee; | 
|  | } Funcs[] = { | 
|  | #define X(caller, callee, argc)                                                \ | 
|  | {                                                                            \ | 
|  | STR(caller), STR(callee), argc, &caller,                                   \ | 
|  | reinterpret_cast<CalleePtrTy>(&callee),                                \ | 
|  | reinterpret_cast<CalleePtrTy>(&Subzero_::callee)                       \ | 
|  | }                                                                            \ | 
|  | , | 
|  | TEST_FUNC_TABLE | 
|  | #undef X | 
|  | }; | 
|  |  | 
|  | const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs); | 
|  |  | 
|  | for (size_t f = 0; f < NumFuncs; ++f) { | 
|  | char BufLlc[BUF_SIZE], BufSz[BUF_SIZE]; | 
|  |  | 
|  | for (size_t i = 0; i < Funcs[f].Args; ++i) { | 
|  | memset(BufLlc, 0xff, sizeof(BufLlc)); | 
|  | memset(BufSz, 0xff, sizeof(BufSz)); | 
|  |  | 
|  | ArgNum = i; | 
|  |  | 
|  | Buf = BufLlc; | 
|  | Callee = Funcs[f].Callee; | 
|  | Funcs[f].Caller(); | 
|  |  | 
|  | Buf = BufSz; | 
|  | Callee = Funcs[f].Subzero_Callee; | 
|  | Funcs[f].Caller(); | 
|  |  | 
|  | ++TotalTests; | 
|  | if (!memcmp(BufLlc, BufSz, sizeof(BufLlc))) { | 
|  | ++Passes; | 
|  | } else { | 
|  | ++Failures; | 
|  | std::cout << "testCallee(Caller=" << Funcs[f].CallerName | 
|  | << ", Callee=" << Funcs[f].CalleeName << ", ArgNum=" << ArgNum | 
|  | << ")\nsz =" << bufAsString(BufSz) | 
|  | << "\nllc=" << bufAsString(BufLlc) << "\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int main(int argc, char *argv[]) { | 
|  | size_t TotalTests = 0; | 
|  | size_t Passes = 0; | 
|  | size_t Failures = 0; | 
|  |  | 
|  | testCaller(TotalTests, Passes, Failures); | 
|  | testCallee(TotalTests, Passes, Failures); | 
|  |  | 
|  | std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes | 
|  | << " Failures=" << Failures << "\n"; | 
|  |  | 
|  | return Failures; | 
|  | } |