2002-04-07 20:49:59 +00:00
|
|
|
//===-- ExternalFunctions.cpp - Implement External Functions --------------===//
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2005-04-21 22:43:08 +00:00
|
|
|
//
|
2002-04-07 20:49:59 +00:00
|
|
|
// This file contains both code to deal with invoking "external" functions, but
|
|
|
|
// also contains code that implements "exported" external functions.
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
2005-04-21 22:43:08 +00:00
|
|
|
// External functions in the interpreter are implemented by
|
2003-10-10 17:03:10 +00:00
|
|
|
// 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.
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Interpreter.h"
|
|
|
|
#include "llvm/DerivedTypes.h"
|
2003-10-14 21:42:11 +00:00
|
|
|
#include "llvm/Module.h"
|
2006-11-27 23:54:50 +00:00
|
|
|
#include "llvm/Support/Streams.h"
|
2004-11-29 14:11:29 +00:00
|
|
|
#include "llvm/System/DynamicLibrary.h"
|
2002-10-02 21:12:13 +00:00
|
|
|
#include "llvm/Target/TargetData.h"
|
2007-07-27 18:26:35 +00:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2003-11-05 01:18:49 +00:00
|
|
|
#include <csignal>
|
2003-10-14 21:42:11 +00:00
|
|
|
#include <map>
|
2006-12-02 02:22:01 +00:00
|
|
|
#include <cmath>
|
2008-02-20 11:08:44 +00:00
|
|
|
#include <cstring>
|
2007-12-12 06:16:47 +00:00
|
|
|
|
|
|
|
#ifdef __linux__
|
2007-12-12 04:55:43 +00:00
|
|
|
#include <cxxabi.h>
|
2007-12-12 06:16:47 +00:00
|
|
|
#endif
|
|
|
|
|
2002-01-20 22:54:45 +00:00
|
|
|
using std::vector;
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2003-12-14 23:25:48 +00:00
|
|
|
using namespace llvm;
|
2003-11-11 22:41:34 +00:00
|
|
|
|
2002-03-29 03:57:15 +00:00
|
|
|
typedef GenericValue (*ExFunc)(FunctionType *, const vector<GenericValue> &);
|
2007-07-27 18:26:35 +00:00
|
|
|
static ManagedStatic<std::map<const Function *, ExFunc> > Functions;
|
2002-01-20 22:54:45 +00:00
|
|
|
static std::map<std::string, ExFunc> FuncNames;
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2001-10-27 04:15:57 +00:00
|
|
|
static Interpreter *TheInterpreter;
|
|
|
|
|
2001-09-10 04:50:17 +00:00
|
|
|
static char getTypeID(const Type *Ty) {
|
2004-06-17 18:19:28 +00:00
|
|
|
switch (Ty->getTypeID()) {
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::VoidTyID: return 'V';
|
For PR1064:
Implement the arbitrary bit-width integer feature. The feature allows
integers of any bitwidth (up to 64) to be defined instead of just 1, 8,
16, 32, and 64 bit integers.
This change does several things:
1. Introduces a new Derived Type, IntegerType, to represent the number of
bits in an integer. The Type classes SubclassData field is used to
store the number of bits. This allows 2^23 bits in an integer type.
2. Removes the five integer Type::TypeID values for the 1, 8, 16, 32 and
64-bit integers. These are replaced with just IntegerType which is not
a primitive any more.
3. Adjust the rest of LLVM to account for this change.
Note that while this incremental change lays the foundation for arbitrary
bit-width integers, LLVM has not yet been converted to actually deal with
them in any significant way. Most optimization passes, for example, will
still only deal with the byte-width integer types. Future increments
will rectify this situation.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33113 91177308-0d34-0410-b5e6-96231b3b80d8
2007-01-12 07:05:14 +00:00
|
|
|
case Type::IntegerTyID:
|
|
|
|
switch (cast<IntegerType>(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';
|
|
|
|
}
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::FloatTyID: return 'F';
|
|
|
|
case Type::DoubleTyID: return 'D';
|
|
|
|
case Type::PointerTyID: return 'P';
|
2006-12-31 05:51:36 +00:00
|
|
|
case Type::FunctionTyID:return 'M';
|
2001-09-10 04:50:17 +00:00
|
|
|
case Type::StructTyID: return 'T';
|
|
|
|
case Type::ArrayTyID: return 'A';
|
|
|
|
case Type::OpaqueTyID: return 'O';
|
|
|
|
default: return 'U';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-30 23:03:25 +00:00
|
|
|
// 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.
|
2003-10-10 17:03:10 +00:00
|
|
|
static ExFunc lookupFunction(const Function *F) {
|
2001-09-10 04:50:17 +00:00
|
|
|
// Function not found, look it up... start by figuring out what the
|
|
|
|
// composite function name should be.
|
2002-01-20 22:54:45 +00:00
|
|
|
std::string ExtName = "lle_";
|
2003-10-10 17:03:10 +00:00
|
|
|
const FunctionType *FT = F->getFunctionType();
|
|
|
|
for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i)
|
|
|
|
ExtName += getTypeID(FT->getContainedType(i));
|
|
|
|
ExtName += "_" + F->getName();
|
2001-09-10 04:50:17 +00:00
|
|
|
|
2001-10-30 20:28:00 +00:00
|
|
|
ExFunc FnPtr = FuncNames[ExtName];
|
|
|
|
if (FnPtr == 0)
|
2003-10-10 17:03:10 +00:00
|
|
|
FnPtr = FuncNames["lle_X_"+F->getName()];
|
2001-09-10 04:50:17 +00:00
|
|
|
if (FnPtr == 0) // Try calling a generic function... if it exists...
|
2006-06-01 17:27:11 +00:00
|
|
|
FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol(
|
2004-11-29 14:11:29 +00:00
|
|
|
("lle_X_"+F->getName()).c_str());
|
2007-05-19 01:36:17 +00:00
|
|
|
if (FnPtr == 0)
|
|
|
|
FnPtr = (ExFunc)(intptr_t)
|
|
|
|
sys::DynamicLibrary::SearchForAddressOfSymbol(F->getName());
|
2001-09-10 04:50:17 +00:00
|
|
|
if (FnPtr != 0)
|
2007-07-27 18:26:35 +00:00
|
|
|
Functions->insert(std::make_pair(F, FnPtr)); // Cache for later
|
2001-09-10 04:50:17 +00:00
|
|
|
return FnPtr;
|
|
|
|
}
|
|
|
|
|
2005-01-21 19:59:37 +00:00
|
|
|
GenericValue Interpreter::callExternalFunction(Function *F,
|
2003-05-14 14:21:30 +00:00
|
|
|
const std::vector<GenericValue> &ArgVals) {
|
2001-10-27 04:15:57 +00:00
|
|
|
TheInterpreter = this;
|
|
|
|
|
2002-04-07 20:49:59 +00:00
|
|
|
// Do a lookup to see if the function is in our cache... this should just be a
|
2003-10-10 17:42:19 +00:00
|
|
|
// deferred annotation!
|
2007-07-27 18:26:35 +00:00
|
|
|
std::map<const Function *, ExFunc>::iterator FI = Functions->find(F);
|
|
|
|
ExFunc Fn = (FI == Functions->end()) ? lookupFunction(F) : FI->second;
|
2001-09-10 04:50:17 +00:00
|
|
|
if (Fn == 0) {
|
2006-12-07 01:30:32 +00:00
|
|
|
cerr << "Tried to execute an unknown external function: "
|
|
|
|
<< F->getType()->getDescription() << " " << F->getName() << "\n";
|
2005-01-21 19:59:37 +00:00
|
|
|
if (F->getName() == "__main")
|
|
|
|
return GenericValue();
|
|
|
|
abort();
|
2001-09-10 04:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: FIXME when types are not const!
|
2005-01-21 19:59:37 +00:00
|
|
|
GenericValue Result = Fn(const_cast<FunctionType*>(F->getFunctionType()),
|
2002-04-07 20:49:59 +00:00
|
|
|
ArgVals);
|
2001-10-30 20:28:00 +00:00
|
|
|
return Result;
|
2001-09-10 04:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2002-03-29 03:57:15 +00:00
|
|
|
// Functions "exported" to the running application...
|
2001-09-10 04:50:17 +00:00
|
|
|
//
|
|
|
|
extern "C" { // Don't add C++ manglings to llvm mangling :)
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// void putchar(ubyte)
|
2007-04-21 17:11:45 +00:00
|
|
|
GenericValue lle_X_putchar(FunctionType *FT, const vector<GenericValue> &Args){
|
2007-03-06 03:08:12 +00:00
|
|
|
cout << ((char)Args[0].IntVal.getZExtValue()) << std::flush;
|
2001-10-27 04:15:57 +00:00
|
|
|
return Args[0];
|
2001-10-15 05:51:48 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 01:36:17 +00:00
|
|
|
// void _IO_putc(int c, FILE* fp)
|
|
|
|
GenericValue lle_X__IO_putc(FunctionType *FT, const vector<GenericValue> &Args){
|
|
|
|
#ifdef __linux__
|
|
|
|
_IO_putc((char)Args[0].IntVal.getZExtValue(), (FILE*) Args[1].PointerVal);
|
|
|
|
#else
|
|
|
|
assert(0 && "Can't call _IO_putc on this platform");
|
|
|
|
#endif
|
|
|
|
return Args[0];
|
|
|
|
}
|
|
|
|
|
2003-05-14 14:21:30 +00:00
|
|
|
// void atexit(Function*)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_atexit(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-05-14 14:21:30 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = 0;
|
2003-05-14 14:21:30 +00:00
|
|
|
return GV;
|
2001-10-18 21:55:32 +00:00
|
|
|
}
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// void exit(int)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_exit(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-10-27 04:15:57 +00:00
|
|
|
TheInterpreter->exitCalled(Args[0]);
|
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// void abort(void)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_abort(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-11-05 01:18:49 +00:00
|
|
|
raise (SIGABRT);
|
2002-05-20 21:17:16 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2001-10-27 08:28:11 +00:00
|
|
|
// void *malloc(uint)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_malloc(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-10-30 20:28:00 +00:00
|
|
|
assert(Args.size() == 1 && "Malloc expects one argument!");
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "malloc must return pointer");
|
2007-03-06 03:08:12 +00:00
|
|
|
return PTOGV(malloc(Args[0].IntVal.getZExtValue()));
|
2001-10-27 08:28:11 +00:00
|
|
|
}
|
|
|
|
|
2003-04-23 19:55:24 +00:00
|
|
|
// void *calloc(uint, uint)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_calloc(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 19:55:24 +00:00
|
|
|
assert(Args.size() == 2 && "calloc expects two arguments!");
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "calloc must return pointer");
|
2007-03-06 03:08:12 +00:00
|
|
|
return PTOGV(calloc(Args[0].IntVal.getZExtValue(),
|
|
|
|
Args[1].IntVal.getZExtValue()));
|
2003-04-23 19:55:24 +00:00
|
|
|
}
|
|
|
|
|
2007-03-30 16:41:50 +00:00
|
|
|
// void *calloc(uint, uint)
|
|
|
|
GenericValue lle_X_realloc(FunctionType *FT, const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 2 && "calloc expects two arguments!");
|
|
|
|
assert(isa<PointerType>(FT->getReturnType()) &&"realloc must return pointer");
|
|
|
|
return PTOGV(realloc(GVTOP(Args[0]), Args[1].IntVal.getZExtValue()));
|
|
|
|
}
|
|
|
|
|
2001-10-27 08:28:11 +00:00
|
|
|
// void free(void *)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_free(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-06 21:52:18 +00:00
|
|
|
assert(Args.size() == 1);
|
2003-01-13 00:59:47 +00:00
|
|
|
free(GVTOP(Args[0]));
|
2001-10-27 08:28:11 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2001-11-26 18:18:18 +00:00
|
|
|
// int atoi(char *)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_atoi(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-26 18:18:18 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, atoi((char*)GVTOP(Args[0])));
|
2001-11-26 18:18:18 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-10-27 08:28:11 +00:00
|
|
|
// double pow(double, double)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_pow(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-06 21:52:18 +00:00
|
|
|
assert(Args.size() == 2);
|
2001-10-27 08:28:11 +00:00
|
|
|
GenericValue GV;
|
2001-10-29 20:27:45 +00:00
|
|
|
GV.DoubleVal = pow(Args[0].DoubleVal, Args[1].DoubleVal);
|
2001-10-27 08:28:11 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2007-12-12 04:55:43 +00:00
|
|
|
// double sin(double)
|
|
|
|
GenericValue lle_X_sin(FunctionType *FT, const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = sin(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// double cos(double)
|
|
|
|
GenericValue lle_X_cos(FunctionType *FT, const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = cos(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2002-02-18 19:06:25 +00:00
|
|
|
// double exp(double)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_exp(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-02-18 19:06:25 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = exp(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-11-06 21:52:18 +00:00
|
|
|
// double sqrt(double)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_sqrt(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-06 21:52:18 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = sqrt(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
2001-10-27 08:28:11 +00:00
|
|
|
|
2001-11-06 22:53:25 +00:00
|
|
|
// double log(double)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_log(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-06 22:53:25 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = log(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-11-26 18:18:18 +00:00
|
|
|
// double floor(double)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_floor(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-26 18:18:18 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = floor(Args[0].DoubleVal);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2004-10-27 23:03:44 +00:00
|
|
|
#ifdef HAVE_RAND48
|
|
|
|
|
2001-11-06 22:53:25 +00:00
|
|
|
// double drand48()
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_drand48(FunctionType *FT, const vector<GenericValue> &Args) {
|
2008-01-29 13:02:09 +00:00
|
|
|
assert(Args.empty());
|
2001-11-06 22:53:25 +00:00
|
|
|
GenericValue GV;
|
|
|
|
GV.DoubleVal = drand48();
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-11-13 05:46:08 +00:00
|
|
|
// long lrand48()
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_lrand48(FunctionType *FT, const vector<GenericValue> &Args) {
|
2008-01-29 13:02:09 +00:00
|
|
|
assert(Args.empty());
|
2001-11-13 05:46:08 +00:00
|
|
|
GenericValue GV;
|
2007-12-10 14:43:10 +00:00
|
|
|
GV.IntVal = APInt(32, lrand48());
|
2001-11-13 05:46:08 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// void srand48(long)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_srand48(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-13 05:46:08 +00:00
|
|
|
assert(Args.size() == 1);
|
2007-12-10 14:43:10 +00:00
|
|
|
srand48(Args[0].IntVal.getZExtValue());
|
2001-11-13 05:46:08 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2004-10-27 23:03:44 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// int rand()
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_rand(FunctionType *FT, const vector<GenericValue> &Args) {
|
2008-01-29 13:02:09 +00:00
|
|
|
assert(Args.empty());
|
2004-10-27 23:03:44 +00:00
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, rand());
|
2004-10-27 23:03:44 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-11-26 18:18:18 +00:00
|
|
|
// void srand(uint)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_srand(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-11-26 18:18:18 +00:00
|
|
|
assert(Args.size() == 1);
|
2007-03-06 03:08:12 +00:00
|
|
|
srand(Args[0].IntVal.getZExtValue());
|
2001-11-26 18:18:18 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
2001-11-06 22:53:25 +00:00
|
|
|
|
2003-01-13 00:59:47 +00:00
|
|
|
// int puts(const char*)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_puts(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-01-13 00:59:47 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, puts((char*)GVTOP(Args[0])));
|
2003-01-13 00:59:47 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2001-12-13 00:43:47 +00:00
|
|
|
// int sprintf(sbyte *, sbyte *, ...) - a very rough implementation to make
|
|
|
|
// output useful.
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_sprintf(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-01-13 00:59:47 +00:00
|
|
|
char *OutputBuffer = (char *)GVTOP(Args[0]);
|
|
|
|
const char *FmtStr = (const char *)GVTOP(Args[1]);
|
2001-12-13 00:43:47 +00:00
|
|
|
unsigned ArgNo = 2;
|
2001-10-29 20:27:45 +00:00
|
|
|
|
|
|
|
// printf should return # chars printed. This is completely incorrect, but
|
|
|
|
// close enough for now.
|
2007-03-06 03:08:12 +00:00
|
|
|
GenericValue GV;
|
|
|
|
GV.IntVal = APInt(32, strlen(FmtStr));
|
2001-10-29 20:27:45 +00:00
|
|
|
while (1) {
|
|
|
|
switch (*FmtStr) {
|
|
|
|
case 0: return GV; // Null terminator...
|
|
|
|
default: // Normal nonspecial character
|
2001-12-13 00:43:47 +00:00
|
|
|
sprintf(OutputBuffer++, "%c", *FmtStr++);
|
2001-10-29 20:27:45 +00:00
|
|
|
break;
|
|
|
|
case '\\': { // Handle escape codes
|
2001-12-13 00:43:47 +00:00
|
|
|
sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));
|
|
|
|
FmtStr += 2; OutputBuffer += 2;
|
2001-10-29 20:27:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '%': { // Handle format specifiers
|
2001-11-07 19:46:27 +00:00
|
|
|
char FmtBuf[100] = "", Buffer[1000] = "";
|
|
|
|
char *FB = FmtBuf;
|
|
|
|
*FB++ = *FmtStr++;
|
|
|
|
char Last = *FB++ = *FmtStr++;
|
|
|
|
unsigned HowLong = 0;
|
|
|
|
while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&
|
|
|
|
Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&
|
|
|
|
Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&
|
|
|
|
Last != 'p' && Last != 's' && Last != '%') {
|
|
|
|
if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's
|
|
|
|
Last = *FB++ = *FmtStr++;
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
2001-11-07 19:46:27 +00:00
|
|
|
*FB = 0;
|
2005-04-21 22:43:08 +00:00
|
|
|
|
2001-11-07 19:46:27 +00:00
|
|
|
switch (Last) {
|
|
|
|
case '%':
|
2008-08-05 23:36:35 +00:00
|
|
|
strcpy(Buffer, "%"); break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'c':
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
|
|
|
|
break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'd': case 'i':
|
|
|
|
case 'u': case 'o':
|
|
|
|
case 'x': case 'X':
|
2002-08-02 23:08:32 +00:00
|
|
|
if (HowLong >= 1) {
|
2003-08-24 14:02:47 +00:00
|
|
|
if (HowLong == 1 &&
|
2006-08-16 01:24:12 +00:00
|
|
|
TheInterpreter->getTargetData()->getPointerSizeInBits() == 64 &&
|
2006-05-24 19:21:13 +00:00
|
|
|
sizeof(long) < sizeof(int64_t)) {
|
2002-08-02 23:08:32 +00:00
|
|
|
// 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);
|
|
|
|
FmtBuf[Size] = FmtBuf[Size-1];
|
|
|
|
FmtBuf[Size+1] = 0;
|
|
|
|
FmtBuf[Size-1] = 'l';
|
|
|
|
}
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue());
|
2002-08-02 23:08:32 +00:00
|
|
|
} else
|
2007-03-06 03:08:12 +00:00
|
|
|
sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
|
|
|
|
break;
|
2001-11-07 19:46:27 +00:00
|
|
|
case 'e': case 'E': case 'g': case 'G': case 'f':
|
|
|
|
sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;
|
|
|
|
case 'p':
|
2003-01-13 00:59:47 +00:00
|
|
|
sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
|
2005-04-21 22:43:08 +00:00
|
|
|
case 's':
|
2003-01-13 00:59:47 +00:00
|
|
|
sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
|
2006-12-07 01:30:32 +00:00
|
|
|
default: cerr << "<unknown printf code '" << *FmtStr << "'!>";
|
2001-11-07 19:46:27 +00:00
|
|
|
ArgNo++; break;
|
|
|
|
}
|
2001-12-13 00:43:47 +00:00
|
|
|
strcpy(OutputBuffer, Buffer);
|
|
|
|
OutputBuffer += strlen(Buffer);
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-04-21 17:11:45 +00:00
|
|
|
return GV;
|
2001-10-29 20:27:45 +00:00
|
|
|
}
|
|
|
|
|
2001-12-13 00:43:47 +00:00
|
|
|
// int printf(sbyte *, ...) - a very rough implementation to make output useful.
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_printf(FunctionType *FT, const vector<GenericValue> &Args) {
|
2001-12-13 00:43:47 +00:00
|
|
|
char Buffer[10000];
|
|
|
|
vector<GenericValue> NewArgs;
|
2007-04-21 17:11:45 +00:00
|
|
|
NewArgs.push_back(PTOGV((void*)&Buffer[0]));
|
2001-12-13 00:43:47 +00:00
|
|
|
NewArgs.insert(NewArgs.end(), Args.begin(), Args.end());
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue GV = lle_X_sprintf(FT, NewArgs);
|
2006-12-07 01:30:32 +00:00
|
|
|
cout << Buffer;
|
2001-12-13 00:43:47 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2003-03-31 22:12:37 +00:00
|
|
|
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
|
2003-08-18 14:43:39 +00:00
|
|
|
// byteswaps as necessary).
|
2003-03-31 22:12:37 +00:00
|
|
|
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) {
|
2006-12-31 05:51:36 +00:00
|
|
|
Size = 8; Ty = Type::Int64Ty;
|
2003-03-31 22:12:37 +00:00
|
|
|
} else if (Half) {
|
2006-12-31 05:51:36 +00:00
|
|
|
Size = 4; Ty = Type::Int16Ty;
|
2003-03-31 22:12:37 +00:00
|
|
|
} else {
|
2006-12-31 05:51:36 +00:00
|
|
|
Size = 4; Ty = Type::Int32Ty;
|
2003-03-31 22:12:37 +00:00
|
|
|
}
|
|
|
|
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;
|
2006-12-31 05:51:36 +00:00
|
|
|
Ty = Type::Int8Ty;
|
2003-03-31 22:12:37 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Size) {
|
|
|
|
GenericValue GV;
|
|
|
|
void *Arg = Args[ArgNo++];
|
|
|
|
memcpy(&GV, Arg, Size);
|
|
|
|
TheInterpreter->StoreValueToMemory(GV, (GenericValue*)Arg, Ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
// int sscanf(const char *format, ...);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_sscanf(FunctionType *FT, const vector<GenericValue> &args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");
|
|
|
|
|
2003-03-31 22:12:37 +00:00
|
|
|
char *Args[10];
|
2002-03-08 22:51:07 +00:00
|
|
|
for (unsigned i = 0; i < args.size(); ++i)
|
2003-03-31 22:12:37 +00:00
|
|
|
Args[i] = (char*)GVTOP(args[i]);
|
2002-03-08 22:51:07 +00:00
|
|
|
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
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]));
|
2003-03-31 22:12:37 +00:00
|
|
|
ByteswapSCANFResults(Args[1], Args[2], Args[3], Args[4],
|
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9], 0);
|
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// int scanf(const char *format, ...);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_scanf(FunctionType *FT, const vector<GenericValue> &args) {
|
2003-03-31 22:12:37 +00:00
|
|
|
assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");
|
|
|
|
|
|
|
|
char *Args[10];
|
|
|
|
for (unsigned i = 0; i < args.size(); ++i)
|
|
|
|
Args[i] = (char*)GVTOP(args[i]);
|
|
|
|
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
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]));
|
2003-03-31 22:12:37 +00:00
|
|
|
ByteswapSCANFResults(Args[0], Args[1], Args[2], Args[3], Args[4],
|
|
|
|
Args[5], Args[6], Args[7], Args[8], Args[9]);
|
2002-03-08 22:51:07 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-23 21:38:07 +00:00
|
|
|
// int clock(void) - Profiling implementation
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_i_clock(FunctionType *FT, const vector<GenericValue> &Args) {
|
2005-01-16 01:31:31 +00:00
|
|
|
extern unsigned int clock(void);
|
2007-03-06 03:08:12 +00:00
|
|
|
GenericValue GV;
|
|
|
|
GV.IntVal = APInt(32, clock());
|
2002-01-23 21:38:07 +00:00
|
|
|
return GV;
|
|
|
|
}
|
2001-12-13 00:43:47 +00:00
|
|
|
|
2003-04-23 19:55:24 +00:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// String Functions...
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// int strcmp(const char *S1, const char *S2);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_strcmp(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 19:55:24 +00:00
|
|
|
assert(Args.size() == 2);
|
|
|
|
GenericValue Ret;
|
2007-03-06 03:08:12 +00:00
|
|
|
Ret.IntVal = APInt(32, strcmp((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])));
|
2003-04-23 19:55:24 +00:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// char *strcat(char *Dest, const char *src);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_strcat(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 19:55:24 +00:00
|
|
|
assert(Args.size() == 2);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) &&"strcat must return pointer");
|
2003-04-23 19:55:24 +00:00
|
|
|
return PTOGV(strcat((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])));
|
|
|
|
}
|
|
|
|
|
|
|
|
// char *strcpy(char *Dest, const char *src);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_strcpy(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 19:55:24 +00:00
|
|
|
assert(Args.size() == 2);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) &&"strcpy must return pointer");
|
2003-04-23 19:55:24 +00:00
|
|
|
return PTOGV(strcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])));
|
|
|
|
}
|
|
|
|
|
2004-05-01 06:42:15 +00:00
|
|
|
static GenericValue size_t_to_GV (size_t n) {
|
2003-04-23 19:55:24 +00:00
|
|
|
GenericValue Ret;
|
2003-12-12 15:38:06 +00:00
|
|
|
if (sizeof (size_t) == sizeof (uint64_t)) {
|
2007-03-06 03:08:12 +00:00
|
|
|
Ret.IntVal = APInt(64, n);
|
2003-12-12 15:38:06 +00:00
|
|
|
} else {
|
|
|
|
assert (sizeof (size_t) == sizeof (unsigned int));
|
2007-03-06 03:08:12 +00:00
|
|
|
Ret.IntVal = APInt(32, n);
|
2003-12-12 15:38:06 +00:00
|
|
|
}
|
2003-04-23 19:55:24 +00:00
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2005-04-21 22:43:08 +00:00
|
|
|
static size_t GV_to_size_t (GenericValue GV) {
|
2004-05-01 06:42:15 +00:00
|
|
|
size_t count;
|
|
|
|
if (sizeof (size_t) == sizeof (uint64_t)) {
|
2007-03-06 03:08:12 +00:00
|
|
|
count = (size_t)GV.IntVal.getZExtValue();
|
2004-05-01 06:42:15 +00:00
|
|
|
} else {
|
|
|
|
assert (sizeof (size_t) == sizeof (unsigned int));
|
2007-03-06 03:08:12 +00:00
|
|
|
count = (size_t)GV.IntVal.getZExtValue();
|
2004-05-01 06:42:15 +00:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// size_t strlen(const char *src);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_strlen(FunctionType *FT, const vector<GenericValue> &Args) {
|
2004-05-01 06:42:15 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
size_t strlenResult = strlen ((char *) GVTOP (Args[0]));
|
|
|
|
return size_t_to_GV (strlenResult);
|
|
|
|
}
|
|
|
|
|
2003-09-05 18:42:01 +00:00
|
|
|
// char *strdup(const char *src);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_strdup(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-09-05 18:42:01 +00:00
|
|
|
assert(Args.size() == 1);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "strdup must return pointer");
|
2003-09-05 18:42:01 +00:00
|
|
|
return PTOGV(strdup((char*)GVTOP(Args[0])));
|
|
|
|
}
|
|
|
|
|
2003-04-25 18:23:38 +00:00
|
|
|
// char *__strdup(const char *src);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X___strdup(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-25 18:23:38 +00:00
|
|
|
assert(Args.size() == 1);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) &&"_strdup must return pointer");
|
2003-04-25 18:23:38 +00:00
|
|
|
return PTOGV(strdup((char*)GVTOP(Args[0])));
|
|
|
|
}
|
|
|
|
|
2003-04-23 19:55:24 +00:00
|
|
|
// void *memset(void *S, int C, size_t N)
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_memset(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 19:55:24 +00:00
|
|
|
assert(Args.size() == 3);
|
2004-05-01 06:42:15 +00:00
|
|
|
size_t count = GV_to_size_t (Args[2]);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "memset must return pointer");
|
2007-03-06 03:08:12 +00:00
|
|
|
return PTOGV(memset(GVTOP(Args[0]), uint32_t(Args[1].IntVal.getZExtValue()),
|
|
|
|
count));
|
2003-04-23 19:55:24 +00:00
|
|
|
}
|
|
|
|
|
2003-04-23 20:23:16 +00:00
|
|
|
// void *memcpy(void *Dest, void *src, size_t Size);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_memcpy(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-23 20:23:16 +00:00
|
|
|
assert(Args.size() == 3);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "memcpy must return pointer");
|
2004-05-01 06:42:15 +00:00
|
|
|
size_t count = GV_to_size_t (Args[2]);
|
|
|
|
return PTOGV(memcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), count));
|
2003-04-23 20:23:16 +00:00
|
|
|
}
|
2003-04-23 19:55:24 +00:00
|
|
|
|
2008-02-20 07:55:26 +00:00
|
|
|
// void *memcpy(void *Dest, void *src, size_t Size);
|
|
|
|
GenericValue lle_X_memmove(FunctionType *FT, const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 3);
|
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "memmove must return pointer");
|
|
|
|
size_t count = GV_to_size_t (Args[2]);
|
|
|
|
return PTOGV(memmove((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), count));
|
|
|
|
}
|
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// IO Functions...
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2002-10-02 21:12:13 +00:00
|
|
|
// getFILE - Turn a pointer in the host address space into a legit pointer in
|
2004-05-25 08:46:15 +00:00
|
|
|
// the interpreter address space. This is an identity transformation.
|
|
|
|
#define getFILE(ptr) ((FILE*)ptr)
|
2002-10-02 21:12:13 +00:00
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
// FILE *fopen(const char *filename, const char *mode);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fopen(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 2);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) && "fopen must return pointer");
|
2003-01-13 00:59:47 +00:00
|
|
|
return PTOGV(fopen((const char *)GVTOP(Args[0]),
|
2005-04-22 04:08:30 +00:00
|
|
|
(const char *)GVTOP(Args[1])));
|
2002-03-08 22:51:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// int fclose(FILE *F);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fclose(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, fclose(getFILE(GVTOP(Args[0]))));
|
2002-03-08 22:51:07 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2002-11-08 19:10:26 +00:00
|
|
|
// int feof(FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_feof(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-11-08 19:10:26 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
|
|
|
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, feof(getFILE(GVTOP(Args[0]))));
|
2002-11-08 19:10:26 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
// size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fread(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 4);
|
2004-05-01 06:42:15 +00:00
|
|
|
size_t result;
|
2002-03-08 22:51:07 +00:00
|
|
|
|
2004-05-01 06:42:15 +00:00
|
|
|
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);
|
2002-03-08 22:51:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fwrite(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 4);
|
2004-05-01 06:42:15 +00:00
|
|
|
size_t result;
|
2002-03-08 22:51:07 +00:00
|
|
|
|
2004-05-01 06:42:15 +00:00
|
|
|
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);
|
2002-03-08 22:51:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// char *fgets(char *s, int n, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fgets(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 3);
|
2007-12-14 15:41:34 +00:00
|
|
|
return PTOGV(fgets((char*)GVTOP(Args[0]), Args[1].IntVal.getZExtValue(),
|
2005-04-22 04:08:30 +00:00
|
|
|
getFILE(GVTOP(Args[2]))));
|
2002-03-08 22:51:07 +00:00
|
|
|
}
|
|
|
|
|
2002-11-07 19:33:50 +00:00
|
|
|
// FILE *freopen(const char *path, const char *mode, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_freopen(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-11-07 19:33:50 +00:00
|
|
|
assert(Args.size() == 3);
|
2007-03-30 16:41:50 +00:00
|
|
|
assert(isa<PointerType>(FT->getReturnType()) &&"freopen must return pointer");
|
2003-01-13 00:59:47 +00:00
|
|
|
return PTOGV(freopen((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]),
|
2005-04-22 04:08:30 +00:00
|
|
|
getFILE(GVTOP(Args[2]))));
|
2002-11-07 19:33:50 +00:00
|
|
|
}
|
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
// int fflush(FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fflush(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-03-08 22:51:07 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, fflush(getFILE(GVTOP(Args[0]))));
|
2002-10-02 21:12:13 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// int getc(FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_getc(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-10-02 21:12:13 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, getc(getFILE(GVTOP(Args[0]))));
|
2002-03-08 22:51:07 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2003-04-23 19:20:50 +00:00
|
|
|
// int _IO_getc(FILE *stream);
|
|
|
|
GenericValue lle_X__IO_getc(FunctionType *F, const vector<GenericValue> &Args) {
|
|
|
|
return lle_X_getc(F, Args);
|
|
|
|
}
|
|
|
|
|
2002-11-06 22:59:28 +00:00
|
|
|
// int fputc(int C, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fputc(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-11-06 22:59:28 +00:00
|
|
|
assert(Args.size() == 2);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, fputc(Args[0].IntVal.getZExtValue(),
|
|
|
|
getFILE(GVTOP(Args[1]))));
|
2002-11-06 22:59:28 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// int ungetc(int C, FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_ungetc(FunctionType *FT, const vector<GenericValue> &Args) {
|
2002-11-06 22:59:28 +00:00
|
|
|
assert(Args.size() == 2);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, ungetc(Args[0].IntVal.getZExtValue(),
|
|
|
|
getFILE(GVTOP(Args[1]))));
|
2002-11-06 22:59:28 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2004-06-16 02:56:40 +00:00
|
|
|
// int ferror (FILE *stream);
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_ferror(FunctionType *FT, const vector<GenericValue> &Args) {
|
2004-06-16 02:56:40 +00:00
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-03-06 03:08:12 +00:00
|
|
|
GV.IntVal = APInt(32, ferror (getFILE(GVTOP(Args[0]))));
|
2004-06-16 02:56:40 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2002-11-06 23:05:03 +00:00
|
|
|
// int fprintf(FILE *,sbyte *, ...) - a very rough implementation to make output
|
|
|
|
// useful.
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue lle_X_fprintf(FunctionType *FT, const vector<GenericValue> &Args) {
|
2003-04-21 22:43:20 +00:00
|
|
|
assert(Args.size() >= 2);
|
2002-11-06 23:05:03 +00:00
|
|
|
char Buffer[10000];
|
|
|
|
vector<GenericValue> NewArgs;
|
2003-01-13 00:59:47 +00:00
|
|
|
NewArgs.push_back(PTOGV(Buffer));
|
2002-11-06 23:05:03 +00:00
|
|
|
NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end());
|
2007-03-30 16:41:50 +00:00
|
|
|
GenericValue GV = lle_X_sprintf(FT, NewArgs);
|
2002-11-06 23:05:03 +00:00
|
|
|
|
2003-01-13 00:59:47 +00:00
|
|
|
fputs(Buffer, getFILE(GVTOP(Args[0])));
|
2002-11-06 23:05:03 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
2007-12-12 04:55:43 +00:00
|
|
|
// int __cxa_guard_acquire (__guard *g);
|
|
|
|
GenericValue lle_X___cxa_guard_acquire(FunctionType *FT,
|
|
|
|
const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 1);
|
|
|
|
GenericValue GV;
|
2007-12-12 06:16:47 +00:00
|
|
|
#ifdef __linux__
|
2007-12-12 04:55:43 +00:00
|
|
|
GV.IntVal = APInt(32, __cxxabiv1::__cxa_guard_acquire (
|
|
|
|
(__cxxabiv1::__guard*)GVTOP(Args[0])));
|
2007-12-12 06:16:47 +00:00
|
|
|
#else
|
|
|
|
assert(0 && "Can't call __cxa_guard_acquire on this platform");
|
|
|
|
#endif
|
2007-12-12 04:55:43 +00:00
|
|
|
return GV;
|
|
|
|
}
|
|
|
|
|
|
|
|
// void __cxa_guard_release (__guard *g);
|
|
|
|
GenericValue lle_X___cxa_guard_release(FunctionType *FT,
|
|
|
|
const vector<GenericValue> &Args) {
|
|
|
|
assert(Args.size() == 1);
|
2007-12-12 06:16:47 +00:00
|
|
|
#ifdef __linux__
|
2007-12-12 04:55:43 +00:00
|
|
|
__cxxabiv1::__cxa_guard_release ((__cxxabiv1::__guard*)GVTOP(Args[0]));
|
2007-12-12 06:16:47 +00:00
|
|
|
#else
|
|
|
|
assert(0 && "Can't call __cxa_guard_release on this platform");
|
|
|
|
#endif
|
2007-12-12 04:55:43 +00:00
|
|
|
return GenericValue();
|
|
|
|
}
|
|
|
|
|
2001-09-10 04:50:17 +00:00
|
|
|
} // End extern "C"
|
2001-10-30 20:28:00 +00:00
|
|
|
|
|
|
|
|
2003-05-08 16:18:31 +00:00
|
|
|
void Interpreter::initializeExternalFunctions() {
|
2007-04-21 17:11:45 +00:00
|
|
|
FuncNames["lle_X_putchar"] = lle_X_putchar;
|
2007-05-19 01:36:17 +00:00
|
|
|
FuncNames["lle_X__IO_putc"] = lle_X__IO_putc;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_exit"] = lle_X_exit;
|
2002-05-20 21:17:16 +00:00
|
|
|
FuncNames["lle_X_abort"] = lle_X_abort;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_malloc"] = lle_X_malloc;
|
2003-04-23 19:55:24 +00:00
|
|
|
FuncNames["lle_X_calloc"] = lle_X_calloc;
|
2007-03-30 16:41:50 +00:00
|
|
|
FuncNames["lle_X_realloc"] = lle_X_realloc;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_free"] = lle_X_free;
|
2001-11-26 18:18:18 +00:00
|
|
|
FuncNames["lle_X_atoi"] = lle_X_atoi;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_pow"] = lle_X_pow;
|
2007-12-12 04:55:43 +00:00
|
|
|
FuncNames["lle_X_sin"] = lle_X_sin;
|
|
|
|
FuncNames["lle_X_cos"] = lle_X_cos;
|
2002-02-18 19:06:25 +00:00
|
|
|
FuncNames["lle_X_exp"] = lle_X_exp;
|
2001-11-13 05:46:08 +00:00
|
|
|
FuncNames["lle_X_log"] = lle_X_log;
|
2001-11-26 18:18:18 +00:00
|
|
|
FuncNames["lle_X_floor"] = lle_X_floor;
|
|
|
|
FuncNames["lle_X_srand"] = lle_X_srand;
|
2004-10-27 23:03:44 +00:00
|
|
|
FuncNames["lle_X_rand"] = lle_X_rand;
|
|
|
|
#ifdef HAVE_RAND48
|
2001-11-13 05:46:08 +00:00
|
|
|
FuncNames["lle_X_drand48"] = lle_X_drand48;
|
|
|
|
FuncNames["lle_X_srand48"] = lle_X_srand48;
|
|
|
|
FuncNames["lle_X_lrand48"] = lle_X_lrand48;
|
2004-10-27 23:03:44 +00:00
|
|
|
#endif
|
2001-11-06 21:52:18 +00:00
|
|
|
FuncNames["lle_X_sqrt"] = lle_X_sqrt;
|
2003-01-13 00:59:47 +00:00
|
|
|
FuncNames["lle_X_puts"] = lle_X_puts;
|
2001-11-03 10:15:32 +00:00
|
|
|
FuncNames["lle_X_printf"] = lle_X_printf;
|
2001-12-13 00:43:47 +00:00
|
|
|
FuncNames["lle_X_sprintf"] = lle_X_sprintf;
|
2002-03-08 22:51:07 +00:00
|
|
|
FuncNames["lle_X_sscanf"] = lle_X_sscanf;
|
2003-03-31 22:12:37 +00:00
|
|
|
FuncNames["lle_X_scanf"] = lle_X_scanf;
|
2002-01-23 21:38:07 +00:00
|
|
|
FuncNames["lle_i_clock"] = lle_i_clock;
|
2003-04-23 19:55:24 +00:00
|
|
|
|
|
|
|
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;
|
2003-05-08 16:18:31 +00:00
|
|
|
FuncNames["lle_X___strdup"] = lle_X___strdup;
|
2003-04-23 19:55:24 +00:00
|
|
|
FuncNames["lle_X_memset"] = lle_X_memset;
|
2003-04-23 20:23:16 +00:00
|
|
|
FuncNames["lle_X_memcpy"] = lle_X_memcpy;
|
2008-02-20 07:55:26 +00:00
|
|
|
FuncNames["lle_X_memmove"] = lle_X_memmove;
|
2003-04-23 19:55:24 +00:00
|
|
|
|
2002-03-08 22:51:07 +00:00
|
|
|
FuncNames["lle_X_fopen"] = lle_X_fopen;
|
|
|
|
FuncNames["lle_X_fclose"] = lle_X_fclose;
|
2002-11-08 19:10:26 +00:00
|
|
|
FuncNames["lle_X_feof"] = lle_X_feof;
|
2002-03-08 22:51:07 +00:00
|
|
|
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;
|
2002-11-06 22:59:28 +00:00
|
|
|
FuncNames["lle_X_fgetc"] = lle_X_getc;
|
2002-10-02 21:12:13 +00:00
|
|
|
FuncNames["lle_X_getc"] = lle_X_getc;
|
2003-04-23 19:20:50 +00:00
|
|
|
FuncNames["lle_X__IO_getc"] = lle_X__IO_getc;
|
2002-11-06 22:59:28 +00:00
|
|
|
FuncNames["lle_X_fputc"] = lle_X_fputc;
|
|
|
|
FuncNames["lle_X_ungetc"] = lle_X_ungetc;
|
2002-11-06 23:05:03 +00:00
|
|
|
FuncNames["lle_X_fprintf"] = lle_X_fprintf;
|
2002-11-07 19:33:50 +00:00
|
|
|
FuncNames["lle_X_freopen"] = lle_X_freopen;
|
2007-12-12 04:55:43 +00:00
|
|
|
|
|
|
|
FuncNames["lle_X___cxa_guard_acquire"] = lle_X___cxa_guard_acquire;
|
|
|
|
FuncNames["lle_X____cxa_guard_release"] = lle_X___cxa_guard_release;
|
2001-10-30 20:28:00 +00:00
|
|
|
}
|
2003-11-11 22:41:34 +00:00
|
|
|
|