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