//===- 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; }