LCOV - code coverage report
Current view: top level - lib/ExecutionEngine/Interpreter - ExternalFunctions.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 128 223 57.4 %
Date: 2018-10-20 13:21:21 Functions: 10 17 58.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- ExternalFunctions.cpp - Implement External Functions --------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : //  This file contains both code to deal with invoking "external" functions, but
      11             : //  also contains code that implements "exported" external functions.
      12             : //
      13             : //  There are currently two mechanisms for handling external functions in the
      14             : //  Interpreter.  The first is to implement lle_* wrapper functions that are
      15             : //  specific to well-known library functions which manually translate the
      16             : //  arguments from GenericValues and make the call.  If such a wrapper does
      17             : //  not exist, and libffi is available, then the Interpreter will attempt to
      18             : //  invoke the function using libffi, after finding its address.
      19             : //
      20             : //===----------------------------------------------------------------------===//
      21             : 
      22             : #include "Interpreter.h"
      23             : #include "llvm/ADT/APInt.h"
      24             : #include "llvm/ADT/ArrayRef.h"
      25             : #include "llvm/Config/config.h" // Detect libffi
      26             : #include "llvm/ExecutionEngine/GenericValue.h"
      27             : #include "llvm/IR/DataLayout.h"
      28             : #include "llvm/IR/DerivedTypes.h"
      29             : #include "llvm/IR/Function.h"
      30             : #include "llvm/IR/Type.h"
      31             : #include "llvm/Support/Casting.h"
      32             : #include "llvm/Support/DynamicLibrary.h"
      33             : #include "llvm/Support/ErrorHandling.h"
      34             : #include "llvm/Support/ManagedStatic.h"
      35             : #include "llvm/Support/Mutex.h"
      36             : #include "llvm/Support/UniqueLock.h"
      37             : #include "llvm/Support/raw_ostream.h"
      38             : #include <cassert>
      39             : #include <cmath>
      40             : #include <csignal>
      41             : #include <cstdint>
      42             : #include <cstdio>
      43             : #include <cstring>
      44             : #include <map>
      45             : #include <string>
      46             : #include <utility>
      47             : #include <vector>
      48             : 
      49             : #ifdef HAVE_FFI_CALL
      50             : #ifdef HAVE_FFI_H
      51             : #include <ffi.h>
      52             : #define USE_LIBFFI
      53             : #elif HAVE_FFI_FFI_H
      54             : #include <ffi/ffi.h>
      55             : #define USE_LIBFFI
      56             : #endif
      57             : #endif
      58             : 
      59             : using namespace llvm;
      60             : 
      61             : static ManagedStatic<sys::Mutex> FunctionsLock;
      62             : 
      63             : typedef GenericValue (*ExFunc)(FunctionType *, ArrayRef<GenericValue>);
      64             : static ManagedStatic<std::map<const Function *, ExFunc> > ExportedFunctions;
      65             : static ManagedStatic<std::map<std::string, ExFunc> > FuncNames;
      66             : 
      67             : #ifdef USE_LIBFFI
      68             : typedef void (*RawFunc)();
      69             : static ManagedStatic<std::map<const Function *, RawFunc> > RawFunctions;
      70             : #endif
      71             : 
      72             : static Interpreter *TheInterpreter;
      73             : 
      74          82 : static char getTypeID(Type *Ty) {
      75          82 :   switch (Ty->getTypeID()) {
      76             :   case Type::VoidTyID:    return 'V';
      77             :   case Type::IntegerTyID:
      78          26 :     switch (cast<IntegerType>(Ty)->getBitWidth()) {
      79             :       case 1:  return 'o';
      80           0 :       case 8:  return 'B';
      81           0 :       case 16: return 'S';
      82          26 :       case 32: return 'I';
      83           0 :       case 64: return 'L';
      84           0 :       default: return 'N';
      85             :     }
      86          15 :   case Type::FloatTyID:   return 'F';
      87          15 :   case Type::DoubleTyID:  return 'D';
      88           7 :   case Type::PointerTyID: return 'P';
      89           0 :   case Type::FunctionTyID:return 'M';
      90           0 :   case Type::StructTyID:  return 'T';
      91           0 :   case Type::ArrayTyID:   return 'A';
      92           0 :   default: return 'U';
      93             :   }
      94             : }
      95             : 
      96             : // Try to find address of external function given a Function object.
      97             : // Please note, that interpreter doesn't know how to assemble a
      98             : // real call in general case (this is JIT job), that's why it assumes,
      99             : // that all external functions has the same (and pretty "general") signature.
     100             : // The typical example of such functions are "lle_X_" ones.
     101          40 : static ExFunc lookupFunction(const Function *F) {
     102             :   // Function not found, look it up... start by figuring out what the
     103             :   // composite function name should be.
     104          40 :   std::string ExtName = "lle_";
     105             :   FunctionType *FT = F->getFunctionType();
     106         122 :   for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i)
     107         164 :     ExtName += getTypeID(FT->getContainedType(i));
     108          40 :   ExtName += ("_" + F->getName()).str();
     109             : 
     110          40 :   sys::ScopedLock Writer(*FunctionsLock);
     111          40 :   ExFunc FnPtr = (*FuncNames)[ExtName];
     112          40 :   if (!FnPtr)
     113          40 :     FnPtr = (*FuncNames)[("lle_X_" + F->getName()).str()];
     114          40 :   if (!FnPtr)  // Try calling a generic function... if it exists...
     115          14 :     FnPtr = (ExFunc)(intptr_t)sys::DynamicLibrary::SearchForAddressOfSymbol(
     116          28 :         ("lle_X_" + F->getName()).str());
     117          40 :   if (FnPtr)
     118          26 :     ExportedFunctions->insert(std::make_pair(F, FnPtr));  // Cache for later
     119          40 :   return FnPtr;
     120             : }
     121             : 
     122             : #ifdef USE_LIBFFI
     123          30 : static ffi_type *ffiTypeFor(Type *Ty) {
     124          30 :   switch (Ty->getTypeID()) {
     125             :     case Type::VoidTyID: return &ffi_type_void;
     126             :     case Type::IntegerTyID:
     127             :       switch (cast<IntegerType>(Ty)->getBitWidth()) {
     128             :         case 8:  return &ffi_type_sint8;
     129           0 :         case 16: return &ffi_type_sint16;
     130           0 :         case 32: return &ffi_type_sint32;
     131           0 :         case 64: return &ffi_type_sint64;
     132             :       }
     133             :     case Type::FloatTyID:   return &ffi_type_float;
     134          15 :     case Type::DoubleTyID:  return &ffi_type_double;
     135           0 :     case Type::PointerTyID: return &ffi_type_pointer;
     136             :     default: break;
     137             :   }
     138             :   // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
     139           0 :   report_fatal_error("Type could not be mapped for use with libffi.");
     140             :   return NULL;
     141             : }
     142             : 
     143          16 : static void *ffiValueFor(Type *Ty, const GenericValue &AV,
     144             :                          void *ArgDataPtr) {
     145          16 :   switch (Ty->getTypeID()) {
     146             :     case Type::IntegerTyID:
     147             :       switch (cast<IntegerType>(Ty)->getBitWidth()) {
     148           0 :         case 8: {
     149             :           int8_t *I8Ptr = (int8_t *) ArgDataPtr;
     150           0 :           *I8Ptr = (int8_t) AV.IntVal.getZExtValue();
     151           0 :           return ArgDataPtr;
     152             :         }
     153           0 :         case 16: {
     154             :           int16_t *I16Ptr = (int16_t *) ArgDataPtr;
     155           0 :           *I16Ptr = (int16_t) AV.IntVal.getZExtValue();
     156           0 :           return ArgDataPtr;
     157             :         }
     158           0 :         case 32: {
     159             :           int32_t *I32Ptr = (int32_t *) ArgDataPtr;
     160           0 :           *I32Ptr = (int32_t) AV.IntVal.getZExtValue();
     161           0 :           return ArgDataPtr;
     162             :         }
     163           0 :         case 64: {
     164             :           int64_t *I64Ptr = (int64_t *) ArgDataPtr;
     165           0 :           *I64Ptr = (int64_t) AV.IntVal.getZExtValue();
     166           0 :           return ArgDataPtr;
     167             :         }
     168           8 :       }
     169             :     case Type::FloatTyID: {
     170             :       float *FloatPtr = (float *) ArgDataPtr;
     171           8 :       *FloatPtr = AV.FloatVal;
     172           8 :       return ArgDataPtr;
     173             :     }
     174           8 :     case Type::DoubleTyID: {
     175             :       double *DoublePtr = (double *) ArgDataPtr;
     176           8 :       *DoublePtr = AV.DoubleVal;
     177           8 :       return ArgDataPtr;
     178             :     }
     179           0 :     case Type::PointerTyID: {
     180             :       void **PtrPtr = (void **) ArgDataPtr;
     181           0 :       *PtrPtr = GVTOP(AV);
     182           0 :       return ArgDataPtr;
     183             :     }
     184             :     default: break;
     185             :   }
     186             :   // TODO: Support other types such as StructTyID, ArrayTyID, OpaqueTyID, etc.
     187           0 :   report_fatal_error("Type value could not be mapped for use with libffi.");
     188             :   return NULL;
     189             : }
     190             : 
     191          14 : static bool ffiInvoke(RawFunc Fn, Function *F, ArrayRef<GenericValue> ArgVals,
     192             :                       const DataLayout &TD, GenericValue &Result) {
     193             :   ffi_cif cif;
     194             :   FunctionType *FTy = F->getFunctionType();
     195          14 :   const unsigned NumArgs = F->arg_size();
     196             : 
     197             :   // TODO: We don't have type information about the remaining arguments, because
     198             :   // this information is never passed into ExecutionEngine::runFunction().
     199          14 :   if (ArgVals.size() > NumArgs && F->isVarArg()) {
     200           0 :     report_fatal_error("Calling external var arg function '" + F->getName()
     201             :                       + "' is not supported by the Interpreter.");
     202             :   }
     203             : 
     204             :   unsigned ArgBytes = 0;
     205             : 
     206          14 :   std::vector<ffi_type*> args(NumArgs);
     207          16 :   for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
     208          30 :        A != E; ++A) {
     209          16 :     const unsigned ArgNo = A->getArgNo();
     210          16 :     Type *ArgTy = FTy->getParamType(ArgNo);
     211          32 :     args[ArgNo] = ffiTypeFor(ArgTy);
     212          16 :     ArgBytes += TD.getTypeStoreSize(ArgTy);
     213             :   }
     214             : 
     215             :   SmallVector<uint8_t, 128> ArgData;
     216          14 :   ArgData.resize(ArgBytes);
     217          14 :   uint8_t *ArgDataPtr = ArgData.data();
     218          14 :   SmallVector<void*, 16> values(NumArgs);
     219          16 :   for (Function::const_arg_iterator A = F->arg_begin(), E = F->arg_end();
     220          30 :        A != E; ++A) {
     221          16 :     const unsigned ArgNo = A->getArgNo();
     222          16 :     Type *ArgTy = FTy->getParamType(ArgNo);
     223          32 :     values[ArgNo] = ffiValueFor(ArgTy, ArgVals[ArgNo], ArgDataPtr);
     224          16 :     ArgDataPtr += TD.getTypeStoreSize(ArgTy);
     225             :   }
     226             : 
     227          14 :   Type *RetTy = FTy->getReturnType();
     228          14 :   ffi_type *rtype = ffiTypeFor(RetTy);
     229             : 
     230          14 :   if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, NumArgs, rtype, &args[0]) == FFI_OK) {
     231             :     SmallVector<uint8_t, 128> ret;
     232          14 :     if (RetTy->getTypeID() != Type::VoidTyID)
     233          14 :       ret.resize(TD.getTypeStoreSize(RetTy));
     234          14 :     ffi_call(&cif, Fn, ret.data(), values.data());
     235          14 :     switch (RetTy->getTypeID()) {
     236             :       case Type::IntegerTyID:
     237             :         switch (cast<IntegerType>(RetTy)->getBitWidth()) {
     238           0 :           case 8:  Result.IntVal = APInt(8 , *(int8_t *) ret.data()); break;
     239           0 :           case 16: Result.IntVal = APInt(16, *(int16_t*) ret.data()); break;
     240           0 :           case 32: Result.IntVal = APInt(32, *(int32_t*) ret.data()); break;
     241           0 :           case 64: Result.IntVal = APInt(64, *(int64_t*) ret.data()); break;
     242             :         }
     243             :         break;
     244           7 :       case Type::FloatTyID:   Result.FloatVal   = *(float *) ret.data(); break;
     245           7 :       case Type::DoubleTyID:  Result.DoubleVal  = *(double*) ret.data(); break;
     246           0 :       case Type::PointerTyID: Result.PointerVal = *(void **) ret.data(); break;
     247             :       default: break;
     248             :     }
     249             :     return true;
     250             :   }
     251             : 
     252             :   return false;
     253             : }
     254             : #endif // USE_LIBFFI
     255             : 
     256          47 : GenericValue Interpreter::callExternalFunction(Function *F,
     257             :                                                ArrayRef<GenericValue> ArgVals) {
     258          47 :   TheInterpreter = this;
     259             : 
     260          47 :   unique_lock<sys::Mutex> Guard(*FunctionsLock);
     261             : 
     262             :   // Do a lookup to see if the function is in our cache... this should just be a
     263             :   // deferred annotation!
     264          47 :   std::map<const Function *, ExFunc>::iterator FI = ExportedFunctions->find(F);
     265          47 :   if (ExFunc Fn = (FI == ExportedFunctions->end()) ? lookupFunction(F)
     266             :                                                    : FI->second) {
     267             :     Guard.unlock();
     268          33 :     return Fn(F->getFunctionType(), ArgVals);
     269             :   }
     270             : 
     271             : #ifdef USE_LIBFFI
     272          14 :   std::map<const Function *, RawFunc>::iterator RF = RawFunctions->find(F);
     273             :   RawFunc RawFn;
     274          14 :   if (RF == RawFunctions->end()) {
     275          14 :     RawFn = (RawFunc)(intptr_t)
     276          14 :       sys::DynamicLibrary::SearchForAddressOfSymbol(F->getName());
     277          14 :     if (!RawFn)
     278           0 :       RawFn = (RawFunc)(intptr_t)getPointerToGlobalIfAvailable(F);
     279          14 :     if (RawFn != 0)
     280          14 :       RawFunctions->insert(std::make_pair(F, RawFn));  // Cache for later
     281             :   } else {
     282           0 :     RawFn = RF->second;
     283             :   }
     284             : 
     285             :   Guard.unlock();
     286             : 
     287          14 :   GenericValue Result;
     288          14 :   if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result))
     289             :     return Result;
     290             : #endif // USE_LIBFFI
     291             : 
     292           0 :   if (F->getName() == "__main")
     293           0 :     errs() << "Tried to execute an unknown external function: "
     294           0 :       << *F->getType() << " __main\n";
     295             :   else
     296           0 :     report_fatal_error("Tried to execute an unknown external function: " +
     297           0 :                        F->getName());
     298             : #ifndef USE_LIBFFI
     299             :   errs() << "Recompiling LLVM with --enable-libffi might help.\n";
     300             : #endif
     301             :   return GenericValue();
     302             : }
     303             : 
     304             : //===----------------------------------------------------------------------===//
     305             : //  Functions "exported" to the running application...
     306             : //
     307             : 
     308             : // void atexit(Function*)
     309           0 : static GenericValue lle_X_atexit(FunctionType *FT,
     310             :                                  ArrayRef<GenericValue> Args) {
     311             :   assert(Args.size() == 1);
     312           0 :   TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));
     313             :   GenericValue GV;
     314           0 :   GV.IntVal = 0;
     315           0 :   return GV;
     316             : }
     317             : 
     318             : // void exit(int)
     319          19 : static GenericValue lle_X_exit(FunctionType *FT, ArrayRef<GenericValue> Args) {
     320          19 :   TheInterpreter->exitCalled(Args[0]);
     321           0 :   return GenericValue();
     322             : }
     323             : 
     324             : // void abort(void)
     325           0 : static GenericValue lle_X_abort(FunctionType *FT, ArrayRef<GenericValue> Args) {
     326             :   //FIXME: should we report or raise here?
     327             :   //report_fatal_error("Interpreted program raised SIGABRT");
     328           0 :   raise (SIGABRT);
     329           0 :   return GenericValue();
     330             : }
     331             : 
     332             : // int sprintf(char *, const char *, ...) - a very rough implementation to make
     333             : // output useful.
     334          14 : static GenericValue lle_X_sprintf(FunctionType *FT,
     335             :                                   ArrayRef<GenericValue> Args) {
     336          14 :   char *OutputBuffer = (char *)GVTOP(Args[0]);
     337          14 :   const char *FmtStr = (const char *)GVTOP(Args[1]);
     338             :   unsigned ArgNo = 2;
     339             : 
     340             :   // printf should return # chars printed.  This is completely incorrect, but
     341             :   // close enough for now.
     342             :   GenericValue GV;
     343          28 :   GV.IntVal = APInt(32, strlen(FmtStr));
     344             :   while (true) {
     345         101 :     switch (*FmtStr) {
     346          14 :     case 0: return GV;             // Null terminator...
     347          76 :     default:                       // Normal nonspecial character
     348          76 :       sprintf(OutputBuffer++, "%c", *FmtStr++);
     349          76 :       break;
     350           0 :     case '\\': {                   // Handle escape codes
     351           0 :       sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));
     352           0 :       FmtStr += 2; OutputBuffer += 2;
     353           0 :       break;
     354             :     }
     355          11 :     case '%': {                    // Handle format specifiers
     356          11 :       char FmtBuf[100] = "", Buffer[1000] = "";
     357             :       char *FB = FmtBuf;
     358          11 :       *FB++ = *FmtStr++;
     359          11 :       char Last = *FB++ = *FmtStr++;
     360             :       unsigned HowLong = 0;
     361          67 :       while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&
     362          18 :              Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&
     363          10 :              Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&
     364          31 :              Last != 'p' && Last != 's' && Last != '%') {
     365          10 :         if (Last == 'l' || Last == 'L') HowLong++;  // Keep track of l's
     366          10 :         Last = *FB++ = *FmtStr++;
     367             :       }
     368          11 :       *FB = 0;
     369             : 
     370             :       switch (Last) {
     371           0 :       case '%':
     372           0 :         memcpy(Buffer, "%", 2); break;
     373           0 :       case 'c':
     374           0 :         sprintf(Buffer, FmtBuf, uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
     375           0 :         break;
     376          11 :       case 'd': case 'i':
     377             :       case 'u': case 'o':
     378             :       case 'x': case 'X':
     379          11 :         if (HowLong >= 1) {
     380           2 :           if (HowLong == 1 &&
     381           2 :               TheInterpreter->getDataLayout().getPointerSizeInBits() == 64 &&
     382             :               sizeof(long) < sizeof(int64_t)) {
     383             :             // Make sure we use %lld with a 64 bit argument because we might be
     384             :             // compiling LLI on a 32 bit compiler.
     385             :             unsigned Size = strlen(FmtBuf);
     386             :             FmtBuf[Size] = FmtBuf[Size-1];
     387             :             FmtBuf[Size+1] = 0;
     388             :             FmtBuf[Size-1] = 'l';
     389             :           }
     390           4 :           sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal.getZExtValue());
     391             :         } else
     392          18 :           sprintf(Buffer, FmtBuf,uint32_t(Args[ArgNo++].IntVal.getZExtValue()));
     393             :         break;
     394           0 :       case 'e': case 'E': case 'g': case 'G': case 'f':
     395           0 :         sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;
     396           0 :       case 'p':
     397           0 :         sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
     398           0 :       case 's':
     399           0 :         sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
     400           0 :       default:
     401           0 :         errs() << "<unknown printf code '" << *FmtStr << "'!>";
     402           0 :         ArgNo++; break;
     403             :       }
     404          11 :       size_t Len = strlen(Buffer);
     405          11 :       memcpy(OutputBuffer, Buffer, Len + 1);
     406          11 :       OutputBuffer += Len;
     407             :       }
     408          11 :       break;
     409             :     }
     410             :   }
     411             :   return GV;
     412             : }
     413             : 
     414             : // int printf(const char *, ...) - a very rough implementation to make output
     415             : // useful.
     416          14 : static GenericValue lle_X_printf(FunctionType *FT,
     417             :                                  ArrayRef<GenericValue> Args) {
     418             :   char Buffer[10000];
     419          14 :   std::vector<GenericValue> NewArgs;
     420          14 :   NewArgs.push_back(PTOGV((void*)&Buffer[0]));
     421          14 :   NewArgs.insert(NewArgs.end(), Args.begin(), Args.end());
     422          14 :   GenericValue GV = lle_X_sprintf(FT, NewArgs);
     423          14 :   outs() << Buffer;
     424          14 :   return GV;
     425             : }
     426             : 
     427             : // int sscanf(const char *format, ...);
     428           0 : static GenericValue lle_X_sscanf(FunctionType *FT,
     429             :                                  ArrayRef<GenericValue> args) {
     430             :   assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");
     431             : 
     432             :   char *Args[10];
     433           0 :   for (unsigned i = 0; i < args.size(); ++i)
     434           0 :     Args[i] = (char*)GVTOP(args[i]);
     435             : 
     436             :   GenericValue GV;
     437           0 :   GV.IntVal = APInt(32, sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
     438             :                     Args[5], Args[6], Args[7], Args[8], Args[9]));
     439           0 :   return GV;
     440             : }
     441             : 
     442             : // int scanf(const char *format, ...);
     443           0 : static GenericValue lle_X_scanf(FunctionType *FT, ArrayRef<GenericValue> args) {
     444             :   assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");
     445             : 
     446             :   char *Args[10];
     447           0 :   for (unsigned i = 0; i < args.size(); ++i)
     448           0 :     Args[i] = (char*)GVTOP(args[i]);
     449             : 
     450             :   GenericValue GV;
     451           0 :   GV.IntVal = APInt(32, scanf( Args[0], Args[1], Args[2], Args[3], Args[4],
     452             :                     Args[5], Args[6], Args[7], Args[8], Args[9]));
     453           0 :   return GV;
     454             : }
     455             : 
     456             : // int fprintf(FILE *, const char *, ...) - a very rough implementation to make
     457             : // output useful.
     458           0 : static GenericValue lle_X_fprintf(FunctionType *FT,
     459             :                                   ArrayRef<GenericValue> Args) {
     460             :   assert(Args.size() >= 2);
     461             :   char Buffer[10000];
     462           0 :   std::vector<GenericValue> NewArgs;
     463           0 :   NewArgs.push_back(PTOGV(Buffer));
     464           0 :   NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end());
     465           0 :   GenericValue GV = lle_X_sprintf(FT, NewArgs);
     466             : 
     467           0 :   fputs(Buffer, (FILE *) GVTOP(Args[0]));
     468           0 :   return GV;
     469             : }
     470             : 
     471           0 : static GenericValue lle_X_memset(FunctionType *FT,
     472             :                                  ArrayRef<GenericValue> Args) {
     473           0 :   int val = (int)Args[1].IntVal.getSExtValue();
     474             :   size_t len = (size_t)Args[2].IntVal.getZExtValue();
     475           0 :   memset((void *)GVTOP(Args[0]), val, len);
     476             :   // llvm.memset.* returns void, lle_X_* returns GenericValue,
     477             :   // so here we return GenericValue with IntVal set to zero
     478             :   GenericValue GV;
     479           0 :   GV.IntVal = 0;
     480           0 :   return GV;
     481             : }
     482             : 
     483           0 : static GenericValue lle_X_memcpy(FunctionType *FT,
     484             :                                  ArrayRef<GenericValue> Args) {
     485           0 :   memcpy(GVTOP(Args[0]), GVTOP(Args[1]),
     486           0 :          (size_t)(Args[2].IntVal.getLimitedValue()));
     487             : 
     488             :   // llvm.memcpy* returns void, lle_X_* returns GenericValue,
     489             :   // so here we return GenericValue with IntVal set to zero
     490             :   GenericValue GV;
     491           0 :   GV.IntVal = 0;
     492           0 :   return GV;
     493             : }
     494             : 
     495          24 : void Interpreter::initializeExternalFunctions() {
     496          24 :   sys::ScopedLock Writer(*FunctionsLock);
     497          24 :   (*FuncNames)["lle_X_atexit"]       = lle_X_atexit;
     498          24 :   (*FuncNames)["lle_X_exit"]         = lle_X_exit;
     499          24 :   (*FuncNames)["lle_X_abort"]        = lle_X_abort;
     500             : 
     501          24 :   (*FuncNames)["lle_X_printf"]       = lle_X_printf;
     502          24 :   (*FuncNames)["lle_X_sprintf"]      = lle_X_sprintf;
     503          24 :   (*FuncNames)["lle_X_sscanf"]       = lle_X_sscanf;
     504          24 :   (*FuncNames)["lle_X_scanf"]        = lle_X_scanf;
     505          24 :   (*FuncNames)["lle_X_fprintf"]      = lle_X_fprintf;
     506          24 :   (*FuncNames)["lle_X_memset"]       = lle_X_memset;
     507          24 :   (*FuncNames)["lle_X_memcpy"]       = lle_X_memcpy;
     508          24 : }

Generated by: LCOV version 1.13