X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FInterpreter%2FExternalFunctions.cpp;h=8add3f56d7dc8c2f1d082a86f0766dbac36cf654;hb=fb70e7deafbdce88882735ec8f658e710d65e8cc;hp=9246c0b85178befd3993ce134f47d100d79830bc;hpb=3c66c355b6e88407fd77a90bf8be0e2f7297409e;p=oota-llvm.git diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp index 9246c0b8517..8add3f56d7d 100644 --- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -1,61 +1,81 @@ //===-- ExternalFunctions.cpp - Implement External Functions --------------===// -// +// // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// //===----------------------------------------------------------------------===// -// +// // This file contains both code to deal with invoking "external" functions, but // also contains code that implements "exported" external functions. // -// External functions in the interpreter are implemented by -// using the system's dynamic loader to look up the address of the function -// we want to invoke. If a function is found, then one of the -// many lle_* wrapper functions in this file will translate its arguments from -// GenericValues to the types the function is actually expecting, before the -// function is called. +// There are currently two mechanisms for handling external functions in the +// Interpreter. The first is to implement lle_* wrapper functions that are +// specific to well-known library functions which manually translate the +// arguments from GenericValues and make the call. If such a wrapper does +// not exist, and libffi is available, then the Interpreter will attempt to +// invoke the function using libffi, after finding its address. // //===----------------------------------------------------------------------===// #include "Interpreter.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" -#include "llvm/SymbolTable.h" +#include "llvm/Config/config.h" // Detect libffi +#include "llvm/Support/ErrorHandling.h" +#include "llvm/System/DynamicLibrary.h" #include "llvm/Target/TargetData.h" -#include "Support/DynamicLinker.h" -#include "Config/dlfcn.h" -#include "Config/link.h" -#include +#include "llvm/Support/ManagedStatic.h" +#include "llvm/System/Mutex.h" #include +#include #include -using std::vector; +#include +#include + +#ifdef HAVE_FFI_CALL +#ifdef HAVE_FFI_H +#include +#define USE_LIBFFI +#elif HAVE_FFI_FFI_H +#include +#define USE_LIBFFI +#endif +#endif using namespace llvm; -typedef GenericValue (*ExFunc)(FunctionType *, const vector &); -static std::map Functions; +static ManagedStatic FunctionsLock; + +typedef GenericValue (*ExFunc)(const FunctionType *, + const std::vector &); +static ManagedStatic > ExportedFunctions; static std::map FuncNames; +#ifdef USE_LIBFFI +typedef void (*RawFunc)(); +static ManagedStatic > RawFunctions; +#endif + static Interpreter *TheInterpreter; static char getTypeID(const Type *Ty) { - switch (Ty->getPrimitiveID()) { + switch (Ty->getTypeID()) { case Type::VoidTyID: return 'V'; - case Type::BoolTyID: return 'o'; - case Type::UByteTyID: return 'B'; - case Type::SByteTyID: return 'b'; - case Type::UShortTyID: return 'S'; - case Type::ShortTyID: return 's'; - case Type::UIntTyID: return 'I'; - case Type::IntTyID: return 'i'; - case Type::ULongTyID: return 'L'; - case Type::LongTyID: return 'l'; + case Type::IntegerTyID: + switch (cast(Ty)->getBitWidth()) { + case 1: return 'o'; + case 8: return 'B'; + case 16: return 'S'; + case 32: return 'I'; + case 64: return 'L'; + default: return 'N'; + } case Type::FloatTyID: return 'F'; case Type::DoubleTyID: return 'D'; case Type::PointerTyID: return 'P'; - case Type::FunctionTyID: return 'M'; + case Type::FunctionTyID:return 'M'; case Type::StructTyID: return 'T'; case Type::ArrayTyID: return 'A'; case Type::OpaqueTyID: return 'O'; @@ -63,6 +83,11 @@ static char getTypeID(const Type *Ty) { } } +// Try to find address of external function given a Function object. +// Please note, that interpreter doesn't know how to assemble a +// real call in general case (this is JIT job), that's why it assumes, +// that all external functions has the same (and pretty "general") signature. +// The typical example of such functions are "lle_X_" ones. static ExFunc lookupFunction(const Function *F) { // Function not found, look it up... start by figuring out what the // composite function name should be. @@ -70,66 +95,218 @@ static ExFunc lookupFunction(const Function *F) { const FunctionType *FT = F->getFunctionType(); for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i) ExtName += getTypeID(FT->getContainedType(i)); - ExtName += "_" + F->getName(); + ExtName + "_" + F->getNameStr(); + sys::ScopedLock Writer(*FunctionsLock); ExFunc FnPtr = FuncNames[ExtName]; if (FnPtr == 0) - FnPtr = (ExFunc)GetAddressOfSymbol(ExtName); - if (FnPtr == 0) - FnPtr = FuncNames["lle_X_"+F->getName()]; + FnPtr = FuncNames["lle_X_" + F->getNameStr()]; if (FnPtr == 0) // Try calling a generic function... if it exists... - FnPtr = (ExFunc)GetAddressOfSymbol(("lle_X_"+F->getName()).c_str()); + FnPtr = (ExFunc)(intptr_t) + sys::DynamicLibrary::SearchForAddressOfSymbol("lle_X_"+F->getNameStr()); if (FnPtr != 0) - Functions.insert(std::make_pair(F, FnPtr)); // Cache for later + ExportedFunctions->insert(std::make_pair(F, FnPtr)); // Cache for later return FnPtr; } -GenericValue Interpreter::callExternalFunction(Function *M, +#ifdef USE_LIBFFI +static ffi_type *ffiTypeFor(const Type *Ty) { + switch (Ty->getTypeID()) { + case Type::VoidTyID: return &ffi_type_void; + case Type::IntegerTyID: + switch (cast(Ty)->getBitWidth()) { + case 8: return &ffi_type_sint8; + case 16: return &ffi_type_sint16; + case 32: return &ffi_type_sint32; + case 64: return &ffi_type_sint64; + } + case Type::FloatTyID: return &ffi_type_float; + case Type::DoubleTyID: return &ffi_type_double; + case Type::PointerTyID: return &ffi_type_pointer; + default: break; + } + // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc. + llvm_report_error("Type could not be mapped for use with libffi."); + return NULL; +} + +static void *ffiValueFor(const Type *Ty, const GenericValue &AV, + void *ArgDataPtr) { + switch (Ty->getTypeID()) { + case Type::IntegerTyID: + switch (cast(Ty)->getBitWidth()) { + case 8: { + int8_t *I8Ptr = (int8_t *) ArgDataPtr; + *I8Ptr = (int8_t) AV.IntVal.getZExtValue(); + return ArgDataPtr; + } + case 16: { + int16_t *I16Ptr = (int16_t *) ArgDataPtr; + *I16Ptr = (int16_t) AV.IntVal.getZExtValue(); + return ArgDataPtr; + } + case 32: { + int32_t *I32Ptr = (int32_t *) ArgDataPtr; + *I32Ptr = (int32_t) AV.IntVal.getZExtValue(); + return ArgDataPtr; + } + case 64: { + int64_t *I64Ptr = (int64_t *) ArgDataPtr; + *I64Ptr = (int64_t) AV.IntVal.getZExtValue(); + return ArgDataPtr; + } + } + case Type::FloatTyID: { + float *FloatPtr = (float *) ArgDataPtr; + *FloatPtr = AV.FloatVal; + return ArgDataPtr; + } + case Type::DoubleTyID: { + double *DoublePtr = (double *) ArgDataPtr; + *DoublePtr = AV.DoubleVal; + return ArgDataPtr; + } + case Type::PointerTyID: { + void **PtrPtr = (void **) ArgDataPtr; + *PtrPtr = GVTOP(AV); + return ArgDataPtr; + } + default: break; + } + // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc. + llvm_report_error("Type value could not be mapped for use with libffi."); + return NULL; +} + +static bool ffiInvoke(RawFunc Fn, Function *F, + const std::vector &ArgVals, + const TargetData *TD, GenericValue &Result) { + ffi_cif cif; + const FunctionType *FTy = F->getFunctionType(); + const unsigned NumArgs = F->arg_size(); + + // TODO: We don't have type information about the remaining arguments, because + // this information is never passed into ExecutionEngine::runFunction(). + if (ArgVals.size() > NumArgs && F->isVarArg()) { + llvm_report_error("Calling external var arg function '" + F->getName() + + "' is not supported by the Interpreter."); + } + + unsigned ArgBytes = 0; + + std::vector args(NumArgs); + for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); + A != E; ++A) { + const unsigned ArgNo = A->getArgNo(); + const Type *ArgTy = FTy->getParamType(ArgNo); + args[ArgNo] = ffiTypeFor(ArgTy); + ArgBytes += TD->getTypeStoreSize(ArgTy); + } + + SmallVector ArgData; + ArgData.resize(ArgBytes); + uint8_t *ArgDataPtr = ArgData.data(); + SmallVector values(NumArgs); + for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end(); + A != E; ++A) { + const unsigned ArgNo = A->getArgNo(); + const Type *ArgTy = FTy->getParamType(ArgNo); + values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr); + ArgDataPtr += TD->getTypeStoreSize(ArgTy); + } + + const Type *RetTy = FTy->getReturnType(); + ffi_type *rtype = ffiTypeFor(RetTy); + + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, &args[0]) == FFI_OK) { + SmallVector ret; + if (RetTy->getTypeID() != Type::VoidTyID) + ret.resize(TD->getTypeStoreSize(RetTy)); + ffi_call(&cif, Fn, ret.data(), values.data()); + switch (RetTy->getTypeID()) { + case Type::IntegerTyID: + switch (cast(RetTy)->getBitWidth()) { + case 8: Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break; + case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break; + case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break; + case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break; + } + break; + case Type::FloatTyID: Result.FloatVal = *(float *) ret.data(); break; + case Type::DoubleTyID: Result.DoubleVal = *(double*) ret.data(); break; + case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break; + default: break; + } + return true; + } + + return false; +} +#endif // USE_LIBFFI + +GenericValue Interpreter::callExternalFunction(Function *F, const std::vector &ArgVals) { TheInterpreter = this; + FunctionsLock->acquire(); + // Do a lookup to see if the function is in our cache... this should just be a // deferred annotation! - std::map::iterator FI = Functions.find(M); - ExFunc Fn = (FI == Functions.end()) ? lookupFunction(M) : FI->second; - if (Fn == 0) { - std::cout << "Tried to execute an unknown external function: " - << M->getType()->getDescription() << " " << M->getName() << "\n"; - return GenericValue(); + std::map::iterator FI = ExportedFunctions->find(F); + if (ExFunc Fn = (FI == ExportedFunctions->end()) ? lookupFunction(F) + : FI->second) { + FunctionsLock->release(); + return Fn(F->getFunctionType(), ArgVals); } - // TODO: FIXME when types are not const! - GenericValue Result = Fn(const_cast(M->getFunctionType()), - ArgVals); - return Result; +#ifdef USE_LIBFFI + std::map::iterator RF = RawFunctions->find(F); + RawFunc RawFn; + if (RF == RawFunctions->end()) { + RawFn = (RawFunc)(intptr_t) + sys::DynamicLibrary::SearchForAddressOfSymbol(F->getName()); + if (!RawnFn) + RawFn = (RawFunc)(intptr_t)getPointerToGlobalIfAvailable(F); + if (RawFn != 0) + RawFunctions->insert(std::make_pair(F, RawFn)); // Cache for later + } else { + RawFn = RF->second; + } + + FunctionsLock->release(); + + GenericValue Result; + if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getTargetData(), Result)) + return Result; +#endif // USE_LIBFFI + + if (F->getName() == "__main") + errs() << "Tried to execute an unknown external function: " + << F->getType()->getDescription() << " __main\n"; + else + llvm_report_error("Tried to execute an unknown external function: " + + F->getType()->getDescription() + " " +F->getName()); +#ifndef USE_LIBFFI + errs() << "Recompiling LLVM with --enable-libffi might help.\n"; +#endif + return GenericValue(); } //===----------------------------------------------------------------------===// // Functions "exported" to the running application... // -extern "C" { // Don't add C++ manglings to llvm mangling :) -// void putchar(sbyte) -GenericValue lle_Vb_putchar(FunctionType *M, const vector &Args) { - std::cout << Args[0].SByteVal; - return GenericValue(); -} +// Visual Studio warns about returning GenericValue in extern "C" linkage +#ifdef _MSC_VER + #pragma warning(disable : 4190) +#endif -// int putchar(int) -GenericValue lle_ii_putchar(FunctionType *M, const vector &Args) { - std::cout << ((char)Args[0].IntVal) << std::flush; - return Args[0]; -} - -// void putchar(ubyte) -GenericValue lle_VB_putchar(FunctionType *M, const vector &Args) { - std::cout << Args[0].SByteVal << std::flush; - return Args[0]; -} +extern "C" { // Don't add C++ manglings to llvm mangling :) // void atexit(Function*) -GenericValue lle_X_atexit(FunctionType *M, const vector &Args) { +GenericValue lle_X_atexit(const FunctionType *FT, + const std::vector &Args) { assert(Args.size() == 1); TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0])); GenericValue GV; @@ -138,132 +315,33 @@ GenericValue lle_X_atexit(FunctionType *M, const vector &Args) { } // void exit(int) -GenericValue lle_X_exit(FunctionType *M, const vector &Args) { +GenericValue lle_X_exit(const FunctionType *FT, + const std::vector &Args) { TheInterpreter->exitCalled(Args[0]); return GenericValue(); } // void abort(void) -GenericValue lle_X_abort(FunctionType *M, const vector &Args) { +GenericValue lle_X_abort(const FunctionType *FT, + const std::vector &Args) { + //FIXME: should we report or raise here? + //llvm_report_error("Interpreted program raised SIGABRT"); raise (SIGABRT); return GenericValue(); } -// void *malloc(uint) -GenericValue lle_X_malloc(FunctionType *M, const vector &Args) { - assert(Args.size() == 1 && "Malloc expects one argument!"); - return PTOGV(malloc(Args[0].UIntVal)); -} - -// void *calloc(uint, uint) -GenericValue lle_X_calloc(FunctionType *M, const vector &Args) { - assert(Args.size() == 2 && "calloc expects two arguments!"); - return PTOGV(calloc(Args[0].UIntVal, Args[1].UIntVal)); -} - -// void free(void *) -GenericValue lle_X_free(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - free(GVTOP(Args[0])); - return GenericValue(); -} - -// int atoi(char *) -GenericValue lle_X_atoi(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.IntVal = atoi((char*)GVTOP(Args[0])); - return GV; -} - -// double pow(double, double) -GenericValue lle_X_pow(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - GenericValue GV; - GV.DoubleVal = pow(Args[0].DoubleVal, Args[1].DoubleVal); - return GV; -} - -// double exp(double) -GenericValue lle_X_exp(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.DoubleVal = exp(Args[0].DoubleVal); - return GV; -} - -// double sqrt(double) -GenericValue lle_X_sqrt(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.DoubleVal = sqrt(Args[0].DoubleVal); - return GV; -} - -// double log(double) -GenericValue lle_X_log(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.DoubleVal = log(Args[0].DoubleVal); - return GV; -} - -// double floor(double) -GenericValue lle_X_floor(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.DoubleVal = floor(Args[0].DoubleVal); - return GV; -} - -// double drand48() -GenericValue lle_X_drand48(FunctionType *M, const vector &Args) { - assert(Args.size() == 0); - GenericValue GV; - GV.DoubleVal = drand48(); - return GV; -} - -// long lrand48() -GenericValue lle_X_lrand48(FunctionType *M, const vector &Args) { - assert(Args.size() == 0); - GenericValue GV; - GV.IntVal = lrand48(); - return GV; -} - -// void srand48(long) -GenericValue lle_X_srand48(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - srand48(Args[0].IntVal); - return GenericValue(); -} - -// void srand(uint) -GenericValue lle_X_srand(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - srand(Args[0].UIntVal); - return GenericValue(); -} - -// int puts(const char*) -GenericValue lle_X_puts(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.IntVal = puts((char*)GVTOP(Args[0])); - return GV; -} - -// int sprintf(sbyte *, sbyte *, ...) - a very rough implementation to make +// int sprintf(char *, const char *, ...) - a very rough implementation to make // output useful. -GenericValue lle_X_sprintf(FunctionType *M, const vector &Args) { +GenericValue lle_X_sprintf(const FunctionType *FT, + const std::vector &Args) { char *OutputBuffer = (char *)GVTOP(Args[0]); const char *FmtStr = (const char *)GVTOP(Args[1]); unsigned ArgNo = 2; // printf should return # chars printed. This is completely incorrect, but // close enough for now. - GenericValue GV; GV.IntVal = strlen(FmtStr); + GenericValue GV; + GV.IntVal = APInt(32, strlen(FmtStr)); while (1) { switch (*FmtStr) { case 0: return GV; // Null terminator... @@ -289,19 +367,20 @@ GenericValue lle_X_sprintf(FunctionType *M, const vector &Args) { Last = *FB++ = *FmtStr++; } *FB = 0; - + switch (Last) { case '%': - sprintf(Buffer, FmtBuf); break; + memcpy(Buffer, "%", 2); break; case 'c': - sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break; + sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue())); + break; case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': if (HowLong >= 1) { if (HowLong == 1 && - TheInterpreter->getModule().getPointerSize()==Module::Pointer64 && - sizeof(long) < sizeof(long long)) { + TheInterpreter->getTargetData()->getPointerSizeInBits() == 64 && + sizeof(long) < sizeof(int64_t)) { // Make sure we use %lld with a 64 bit argument because we might be // compiling LLI on a 32 bit compiler. unsigned Size = strlen(FmtBuf); @@ -309,115 +388,46 @@ GenericValue lle_X_sprintf(FunctionType *M, const vector &Args) { FmtBuf[Size+1] = 0; FmtBuf[Size-1] = 'l'; } - sprintf(Buffer, FmtBuf, Args[ArgNo++].ULongVal); + sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue()); } else - sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break; + sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue())); + break; case 'e': case 'E': case 'g': case 'G': case 'f': sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break; case 'p': sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break; - case 's': + case 's': sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break; - default: std::cout << ""; + default: + errs() << ""; ArgNo++; break; } - strcpy(OutputBuffer, Buffer); - OutputBuffer += strlen(Buffer); + size_t Len = strlen(Buffer); + memcpy(OutputBuffer, Buffer, Len + 1); + OutputBuffer += Len; } break; } } + return GV; } -// int printf(sbyte *, ...) - a very rough implementation to make output useful. -GenericValue lle_X_printf(FunctionType *M, const vector &Args) { +// int printf(const char *, ...) - a very rough implementation to make output +// useful. +GenericValue lle_X_printf(const FunctionType *FT, + const std::vector &Args) { char Buffer[10000]; - vector NewArgs; - NewArgs.push_back(PTOGV(Buffer)); + std::vector NewArgs; + NewArgs.push_back(PTOGV((void*)&Buffer[0])); NewArgs.insert(NewArgs.end(), Args.begin(), Args.end()); - GenericValue GV = lle_X_sprintf(M, NewArgs); - std::cout << Buffer; + GenericValue GV = lle_X_sprintf(FT, NewArgs); + outs() << Buffer; return GV; } -static void ByteswapSCANFResults(const char *Fmt, void *Arg0, void *Arg1, - void *Arg2, void *Arg3, void *Arg4, void *Arg5, - void *Arg6, void *Arg7, void *Arg8) { - void *Args[] = { Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, 0 }; - - // Loop over the format string, munging read values as appropriate (performs - // byteswaps as necessary). - unsigned ArgNo = 0; - while (*Fmt) { - if (*Fmt++ == '%') { - // Read any flag characters that may be present... - bool Suppress = false; - bool Half = false; - bool Long = false; - bool LongLong = false; // long long or long double - - while (1) { - switch (*Fmt++) { - case '*': Suppress = true; break; - case 'a': /*Allocate = true;*/ break; // We don't need to track this - case 'h': Half = true; break; - case 'l': Long = true; break; - case 'q': - case 'L': LongLong = true; break; - default: - if (Fmt[-1] > '9' || Fmt[-1] < '0') // Ignore field width specs - goto Out; - } - } - Out: - - // Read the conversion character - if (!Suppress && Fmt[-1] != '%') { // Nothing to do? - unsigned Size = 0; - const Type *Ty = 0; - - switch (Fmt[-1]) { - case 'i': case 'o': case 'u': case 'x': case 'X': case 'n': case 'p': - case 'd': - if (Long || LongLong) { - Size = 8; Ty = Type::ULongTy; - } else if (Half) { - Size = 4; Ty = Type::UShortTy; - } else { - Size = 4; Ty = Type::UIntTy; - } - break; - - case 'e': case 'g': case 'E': - case 'f': - if (Long || LongLong) { - Size = 8; Ty = Type::DoubleTy; - } else { - Size = 4; Ty = Type::FloatTy; - } - break; - - case 's': case 'c': case '[': // No byteswap needed - Size = 1; - Ty = Type::SByteTy; - break; - - default: break; - } - - if (Size) { - GenericValue GV; - void *Arg = Args[ArgNo++]; - memcpy(&GV, Arg, Size); - TheInterpreter->StoreValueToMemory(GV, (GenericValue*)Arg, Ty); - } - } - } - } -} - // int sscanf(const char *format, ...); -GenericValue lle_X_sscanf(FunctionType *M, const vector &args) { +GenericValue lle_X_sscanf(const FunctionType *FT, + const std::vector &args) { assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!"); char *Args[10]; @@ -425,15 +435,14 @@ GenericValue lle_X_sscanf(FunctionType *M, const vector &args) { Args[i] = (char*)GVTOP(args[i]); GenericValue GV; - GV.IntVal = sscanf(Args[0], Args[1], Args[2], Args[3], Args[4], - Args[5], Args[6], Args[7], Args[8], Args[9]); - ByteswapSCANFResults(Args[1], Args[2], Args[3], Args[4], - Args[5], Args[6], Args[7], Args[8], Args[9], 0); + GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4], + Args[5], Args[6], Args[7], Args[8], Args[9])); return GV; } // int scanf(const char *format, ...); -GenericValue lle_X_scanf(FunctionType *M, const vector &args) { +GenericValue lle_X_scanf(const FunctionType *FT, + const std::vector &args) { assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!"); char *Args[10]; @@ -441,307 +450,43 @@ GenericValue lle_X_scanf(FunctionType *M, const vector &args) { Args[i] = (char*)GVTOP(args[i]); GenericValue GV; - GV.IntVal = scanf(Args[0], Args[1], Args[2], Args[3], Args[4], - Args[5], Args[6], Args[7], Args[8], Args[9]); - ByteswapSCANFResults(Args[0], Args[1], Args[2], Args[3], Args[4], - Args[5], Args[6], Args[7], Args[8], Args[9]); - return GV; -} - - -// int clock(void) - Profiling implementation -GenericValue lle_i_clock(FunctionType *M, const vector &Args) { - extern int clock(void); - GenericValue GV; GV.IntVal = clock(); - return GV; -} - - -//===----------------------------------------------------------------------===// -// String Functions... -//===----------------------------------------------------------------------===// - -// int strcmp(const char *S1, const char *S2); -GenericValue lle_X_strcmp(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - GenericValue Ret; - Ret.IntVal = strcmp((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])); - return Ret; -} - -// char *strcat(char *Dest, const char *src); -GenericValue lle_X_strcat(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - return PTOGV(strcat((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]))); -} - -// char *strcpy(char *Dest, const char *src); -GenericValue lle_X_strcpy(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - return PTOGV(strcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]))); -} - -static GenericValue size_t_to_GV (size_t n) { - GenericValue Ret; - if (sizeof (size_t) == sizeof (uint64_t)) { - Ret.ULongVal = n; - } else { - assert (sizeof (size_t) == sizeof (unsigned int)); - Ret.UIntVal = n; - } - return Ret; -} - -static size_t GV_to_size_t (GenericValue GV) { - size_t count; - if (sizeof (size_t) == sizeof (uint64_t)) { - count = GV.ULongVal; - } else { - assert (sizeof (size_t) == sizeof (unsigned int)); - count = GV.UIntVal; - } - return count; -} - -// size_t strlen(const char *src); -GenericValue lle_X_strlen(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - size_t strlenResult = strlen ((char *) GVTOP (Args[0])); - return size_t_to_GV (strlenResult); -} - -// char *strdup(const char *src); -GenericValue lle_X_strdup(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - return PTOGV(strdup((char*)GVTOP(Args[0]))); -} - -// char *__strdup(const char *src); -GenericValue lle_X___strdup(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - return PTOGV(strdup((char*)GVTOP(Args[0]))); -} - -// void *memset(void *S, int C, size_t N) -GenericValue lle_X_memset(FunctionType *M, const vector &Args) { - assert(Args.size() == 3); - size_t count = GV_to_size_t (Args[2]); - return PTOGV(memset(GVTOP(Args[0]), Args[1].IntVal, count)); -} - -// void *memcpy(void *Dest, void *src, size_t Size); -GenericValue lle_X_memcpy(FunctionType *M, const vector &Args) { - assert(Args.size() == 3); - size_t count = GV_to_size_t (Args[2]); - return PTOGV(memcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), count)); -} - -//===----------------------------------------------------------------------===// -// IO Functions... -//===----------------------------------------------------------------------===// - -// getFILE - Turn a pointer in the host address space into a legit pointer in -// the interpreter address space. For the most part, this is an identity -// transformation, but if the program refers to stdio, stderr, stdin then they -// have pointers that are relative to the __iob array. If this is the case, -// change the FILE into the REAL stdio stream. -// -static FILE *getFILE(void *Ptr) { - static Module *LastMod = 0; - static PointerTy IOBBase = 0; - static unsigned FILESize; - - if (LastMod != &TheInterpreter->getModule()) { // Module change or initialize? - Module *M = LastMod = &TheInterpreter->getModule(); - - // Check to see if the currently loaded module contains an __iob symbol... - GlobalVariable *IOB = 0; - SymbolTable &ST = M->getSymbolTable(); - for (SymbolTable::iterator I = ST.begin(), E = ST.end(); I != E; ++I) { - SymbolTable::VarMap &M = I->second; - for (SymbolTable::VarMap::iterator J = M.begin(), E = M.end(); - J != E; ++J) - if (J->first == "__iob") - if ((IOB = dyn_cast(J->second))) - break; - if (IOB) break; - } - } - - // Check to see if this is a reference to __iob... - if (IOBBase) { - unsigned FDNum = ((unsigned long)Ptr-IOBBase)/FILESize; - if (FDNum == 0) - return stdin; - else if (FDNum == 1) - return stdout; - else if (FDNum == 2) - return stderr; - } - - return (FILE*)Ptr; -} - - -// FILE *fopen(const char *filename, const char *mode); -GenericValue lle_X_fopen(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - return PTOGV(fopen((const char *)GVTOP(Args[0]), - (const char *)GVTOP(Args[1]))); -} - -// int fclose(FILE *F); -GenericValue lle_X_fclose(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.IntVal = fclose(getFILE(GVTOP(Args[0]))); - return GV; -} - -// int feof(FILE *stream); -GenericValue lle_X_feof(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - - GV.IntVal = feof(getFILE(GVTOP(Args[0]))); - return GV; -} - -// size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream); -GenericValue lle_X_fread(FunctionType *M, const vector &Args) { - assert(Args.size() == 4); - size_t result; - - result = fread((void*)GVTOP(Args[0]), GV_to_size_t (Args[1]), - GV_to_size_t (Args[2]), getFILE(GVTOP(Args[3]))); - return size_t_to_GV (result); -} - -// size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream); -GenericValue lle_X_fwrite(FunctionType *M, const vector &Args) { - assert(Args.size() == 4); - size_t result; - - result = fwrite((void*)GVTOP(Args[0]), GV_to_size_t (Args[1]), - GV_to_size_t (Args[2]), getFILE(GVTOP(Args[3]))); - return size_t_to_GV (result); -} - -// char *fgets(char *s, int n, FILE *stream); -GenericValue lle_X_fgets(FunctionType *M, const vector &Args) { - assert(Args.size() == 3); - return GVTOP(fgets((char*)GVTOP(Args[0]), Args[1].IntVal, - getFILE(GVTOP(Args[2])))); -} - -// FILE *freopen(const char *path, const char *mode, FILE *stream); -GenericValue lle_X_freopen(FunctionType *M, const vector &Args) { - assert(Args.size() == 3); - return PTOGV(freopen((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), - getFILE(GVTOP(Args[2])))); -} - -// int fflush(FILE *stream); -GenericValue lle_X_fflush(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.IntVal = fflush(getFILE(GVTOP(Args[0]))); + GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4], + Args[5], Args[6], Args[7], Args[8], Args[9])); return GV; } -// int getc(FILE *stream); -GenericValue lle_X_getc(FunctionType *M, const vector &Args) { - assert(Args.size() == 1); - GenericValue GV; - GV.IntVal = getc(getFILE(GVTOP(Args[0]))); - return GV; -} - -// int _IO_getc(FILE *stream); -GenericValue lle_X__IO_getc(FunctionType *F, const vector &Args) { - return lle_X_getc(F, Args); -} - -// int fputc(int C, FILE *stream); -GenericValue lle_X_fputc(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - GenericValue GV; - GV.IntVal = fputc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); - return GV; -} - -// int ungetc(int C, FILE *stream); -GenericValue lle_X_ungetc(FunctionType *M, const vector &Args) { - assert(Args.size() == 2); - GenericValue GV; - GV.IntVal = ungetc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); - return GV; -} - -// int fprintf(FILE *,sbyte *, ...) - a very rough implementation to make output -// useful. -GenericValue lle_X_fprintf(FunctionType *M, const vector &Args) { +// int fprintf(FILE *, const char *, ...) - a very rough implementation to make +// output useful. +GenericValue lle_X_fprintf(const FunctionType *FT, + const std::vector &Args) { assert(Args.size() >= 2); char Buffer[10000]; - vector NewArgs; + std::vector NewArgs; NewArgs.push_back(PTOGV(Buffer)); NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end()); - GenericValue GV = lle_X_sprintf(M, NewArgs); + GenericValue GV = lle_X_sprintf(FT, NewArgs); - fputs(Buffer, getFILE(GVTOP(Args[0]))); + fputs(Buffer, (FILE *) GVTOP(Args[0])); return GV; } } // End extern "C" +// Done with externals; turn the warning back on +#ifdef _MSC_VER + #pragma warning(default: 4190) +#endif + void Interpreter::initializeExternalFunctions() { - FuncNames["lle_Vb_putchar"] = lle_Vb_putchar; - FuncNames["lle_ii_putchar"] = lle_ii_putchar; - FuncNames["lle_VB_putchar"] = lle_VB_putchar; + sys::ScopedLock Writer(*FunctionsLock); + FuncNames["lle_X_atexit"] = lle_X_atexit; FuncNames["lle_X_exit"] = lle_X_exit; FuncNames["lle_X_abort"] = lle_X_abort; - FuncNames["lle_X_malloc"] = lle_X_malloc; - FuncNames["lle_X_calloc"] = lle_X_calloc; - FuncNames["lle_X_free"] = lle_X_free; - FuncNames["lle_X_atoi"] = lle_X_atoi; - FuncNames["lle_X_pow"] = lle_X_pow; - FuncNames["lle_X_exp"] = lle_X_exp; - FuncNames["lle_X_log"] = lle_X_log; - FuncNames["lle_X_floor"] = lle_X_floor; - FuncNames["lle_X_srand"] = lle_X_srand; - FuncNames["lle_X_drand48"] = lle_X_drand48; - FuncNames["lle_X_srand48"] = lle_X_srand48; - FuncNames["lle_X_lrand48"] = lle_X_lrand48; - FuncNames["lle_X_sqrt"] = lle_X_sqrt; - FuncNames["lle_X_puts"] = lle_X_puts; + FuncNames["lle_X_printf"] = lle_X_printf; FuncNames["lle_X_sprintf"] = lle_X_sprintf; FuncNames["lle_X_sscanf"] = lle_X_sscanf; FuncNames["lle_X_scanf"] = lle_X_scanf; - FuncNames["lle_i_clock"] = lle_i_clock; - - FuncNames["lle_X_strcmp"] = lle_X_strcmp; - FuncNames["lle_X_strcat"] = lle_X_strcat; - FuncNames["lle_X_strcpy"] = lle_X_strcpy; - FuncNames["lle_X_strlen"] = lle_X_strlen; - FuncNames["lle_X___strdup"] = lle_X___strdup; - FuncNames["lle_X_memset"] = lle_X_memset; - FuncNames["lle_X_memcpy"] = lle_X_memcpy; - - FuncNames["lle_X_fopen"] = lle_X_fopen; - FuncNames["lle_X_fclose"] = lle_X_fclose; - FuncNames["lle_X_feof"] = lle_X_feof; - FuncNames["lle_X_fread"] = lle_X_fread; - FuncNames["lle_X_fwrite"] = lle_X_fwrite; - FuncNames["lle_X_fgets"] = lle_X_fgets; - FuncNames["lle_X_fflush"] = lle_X_fflush; - FuncNames["lle_X_fgetc"] = lle_X_getc; - FuncNames["lle_X_getc"] = lle_X_getc; - FuncNames["lle_X__IO_getc"] = lle_X__IO_getc; - FuncNames["lle_X_fputc"] = lle_X_fputc; - FuncNames["lle_X_ungetc"] = lle_X_ungetc; FuncNames["lle_X_fprintf"] = lle_X_fprintf; - FuncNames["lle_X_freopen"] = lle_X_freopen; } -