diff options
-rw-r--r-- | lib/ExecutionEngine/ExecutionEngine.cpp | 153 | ||||
-rw-r--r-- | test/ExecutionEngine/2007-12-14-BigEndian.ll | 81 | ||||
-rw-r--r-- | test/ExecutionEngine/2007-12-14-LittleEndian.ll | 81 |
3 files changed, 256 insertions, 59 deletions
diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 521e423..707ed60 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -18,6 +18,7 @@ #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Config/alloca.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/Support/Debug.h" @@ -232,6 +233,15 @@ void ExecutionEngine::runStaticConstructorsDestructors(bool isDtors) { } } +/// isTargetNullPtr - Return whether the target pointer stored at Loc is null. +static bool isTargetNullPtr(ExecutionEngine *EE, void *Loc) { + unsigned PtrSize = EE->getTargetData()->getPointerSize(); + for (unsigned i = 0; i < PtrSize; ++i) + if (*(i + (uint8_t*)Loc)) + return false; + return true; +} + /// runFunctionAsMain - This is a helper function which wraps runFunction to /// handle the common task of starting up main with the specified argc, argv, /// and envp parameters. @@ -281,7 +291,7 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn, GVArgs.push_back(GVArgc); // Arg #0 = argc. if (NumArgs > 1) { GVArgs.push_back(PTOGV(CreateArgv(this, argv))); // Arg #1 = argv. - assert(((char **)GVTOP(GVArgs[1]))[0] && + assert(!isTargetNullPtr(this, GVTOP(GVArgs[1])) && "argv[0] was null after CreateArgv"); if (NumArgs > 2) { std::vector<std::string> EnvVars; @@ -624,40 +634,44 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { return Result; } +/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst +/// with the integer held in IntVal. +static void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, + unsigned StoreBytes) { + assert((IntVal.getBitWidth()+7)/8 >= StoreBytes && "Integer too small!"); + uint8_t *Src = (uint8_t *)IntVal.getRawData(); + + if (sys::littleEndianHost()) + // Little-endian host - the source is ordered from LSB to MSB. Order the + // destination from LSB to MSB: Do a straight copy. + memcpy(Dst, Src, StoreBytes); + else { + // Big-endian host - the source is an array of 64 bit words ordered from + // LSW to MSW. Each word is ordered from MSB to LSB. Order the destination + // from MSB to LSB: Reverse the word order, but not the bytes in a word. + while (StoreBytes > sizeof(uint64_t)) { + StoreBytes -= sizeof(uint64_t); + // May not be aligned so use memcpy. + memcpy(Dst + StoreBytes, Src, sizeof(uint64_t)); + Src += sizeof(uint64_t); + } + + memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes); + } +} + /// StoreValueToMemory - Stores the data in Val of type Ty at address Ptr. Ptr /// is the address of the memory at which to store Val, cast to GenericValue *. /// It is not a pointer to a GenericValue containing the address at which to /// store Val. -/// void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue *Ptr, const Type *Ty) { - switch (Ty->getTypeID()) { - case Type::IntegerTyID: { - unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth(); - unsigned StoreBytes = (BitWidth + 7)/8; - uint8_t *Src = (uint8_t *)Val.IntVal.getRawData(); - uint8_t *Dst = (uint8_t *)Ptr; - - if (sys::littleEndianHost()) - // Little-endian host - the source is ordered from LSB to MSB. - // Order the destination from LSB to MSB: Do a straight copy. - memcpy(Dst, Src, StoreBytes); - else { - // Big-endian host - the source is an array of 64 bit words ordered from - // LSW to MSW. Each word is ordered from MSB to LSB. - // Order the destination from MSB to LSB: Reverse the word order, but not - // the bytes in a word. - while (StoreBytes > sizeof(uint64_t)) { - StoreBytes -= sizeof(uint64_t); - // May not be aligned so use memcpy. - memcpy(Dst + StoreBytes, Src, sizeof(uint64_t)); - Src += sizeof(uint64_t); - } + const unsigned StoreBytes = getTargetData()->getTypeStoreSize(Ty); - memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes); - } + switch (Ty->getTypeID()) { + case Type::IntegerTyID: + StoreIntToMemory(Val.IntVal, (uint8_t*)Ptr, StoreBytes); break; - } case Type::FloatTyID: *((float*)Ptr) = Val.FloatVal; break; @@ -675,61 +689,82 @@ void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue * Dest[4] = Src[3]; break; } - case Type::PointerTyID: + case Type::PointerTyID: + // Ensure 64 bit target pointers are fully initialized on 32 bit hosts. + if (StoreBytes != sizeof(PointerTy)) + memset(Ptr, 0, StoreBytes); + *((PointerTy*)Ptr) = Val.PointerVal; break; default: cerr << "Cannot store value of type " << *Ty << "!\n"; } + + if (sys::littleEndianHost() != getTargetData()->isLittleEndian()) + // Host and target are different endian - reverse the stored bytes. + std::reverse((uint8_t*)Ptr, StoreBytes + (uint8_t*)Ptr); +} + +/// LoadIntFromMemory - Loads the integer stored in the LoadBytes bytes starting +/// from Src into IntVal, which is assumed to be wide enough and to hold zero. +static void LoadIntFromMemory(APInt &IntVal, uint8_t *Src, unsigned LoadBytes) { + assert((IntVal.getBitWidth()+7)/8 >= LoadBytes && "Integer too small!"); + uint8_t *Dst = (uint8_t *)IntVal.getRawData(); + + if (sys::littleEndianHost()) + // Little-endian host - the destination must be ordered from LSB to MSB. + // The source is ordered from LSB to MSB: Do a straight copy. + memcpy(Dst, Src, LoadBytes); + else { + // Big-endian - the destination is an array of 64 bit words ordered from + // LSW to MSW. Each word must be ordered from MSB to LSB. The source is + // ordered from MSB to LSB: Reverse the word order, but not the bytes in + // a word. + while (LoadBytes > sizeof(uint64_t)) { + LoadBytes -= sizeof(uint64_t); + // May not be aligned so use memcpy. + memcpy(Dst, Src + LoadBytes, sizeof(uint64_t)); + Dst += sizeof(uint64_t); + } + + memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes); + } } /// FIXME: document /// -void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, +void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, GenericValue *Ptr, const Type *Ty) { - switch (Ty->getTypeID()) { - case Type::IntegerTyID: { - unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth(); - unsigned LoadBytes = (BitWidth + 7)/8; + const unsigned LoadBytes = getTargetData()->getTypeStoreSize(Ty); + + if (sys::littleEndianHost() != getTargetData()->isLittleEndian()) { + // Host and target are different endian - reverse copy the stored + // bytes into a buffer, and load from that. + uint8_t *Src = (uint8_t*)Ptr; + uint8_t *Buf = (uint8_t*)alloca(LoadBytes); + std::reverse_copy(Src, Src + LoadBytes, Buf); + Ptr = (GenericValue*)Buf; + } + switch (Ty->getTypeID()) { + case Type::IntegerTyID: // An APInt with all words initially zero. - Result.IntVal = APInt(BitWidth, 0); - - uint8_t *Src = (uint8_t *)Ptr; - uint8_t *Dst = (uint8_t *)Result.IntVal.getRawData(); - - if (sys::littleEndianHost()) - // Little-endian host - the destination must be ordered from LSB to MSB. - // The source is ordered from LSB to MSB: Do a straight copy. - memcpy(Dst, Src, LoadBytes); - else { - // Big-endian - the destination is an array of 64 bit words ordered from - // LSW to MSW. Each word must be ordered from MSB to LSB. The source is - // ordered from MSB to LSB: Reverse the word order, but not the bytes in - // a word. - while (LoadBytes > sizeof(uint64_t)) { - LoadBytes -= sizeof(uint64_t); - // May not be aligned so use memcpy. - memcpy(Dst, Src + LoadBytes, sizeof(uint64_t)); - Dst += sizeof(uint64_t); - } - - memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes); - } + Result.IntVal = APInt(cast<IntegerType>(Ty)->getBitWidth(), 0); + LoadIntFromMemory(Result.IntVal, (uint8_t*)Ptr, LoadBytes); break; - } case Type::FloatTyID: Result.FloatVal = *((float*)Ptr); break; case Type::DoubleTyID: - Result.DoubleVal = *((double*)Ptr); + Result.DoubleVal = *((double*)Ptr); break; - case Type::PointerTyID: + case Type::PointerTyID: Result.PointerVal = *((PointerTy*)Ptr); break; case Type::X86_FP80TyID: { // This is endian dependent, but it will only work on x86 anyway. + // FIXME: Does not trap if loading a trapping NaN. uint16_t *p = (uint16_t*)Ptr; union { uint16_t x[8]; diff --git a/test/ExecutionEngine/2007-12-14-BigEndian.ll b/test/ExecutionEngine/2007-12-14-BigEndian.ll new file mode 100644 index 0000000..68059fd --- /dev/null +++ b/test/ExecutionEngine/2007-12-14-BigEndian.ll @@ -0,0 +1,81 @@ +; RUN: llvm-as < %s -o - | lli -force-interpreter + +target datalayout = "E" + +define i32 @main() { +entry: + %i = alloca i93 + store i93 18364758544493064720, i93* %i + %i1 = load i93* %i + %i2 = shl i93 %i1, 32 + %i3 = or i93 %i2, 3753679480 + store i93 %i3, i93* %i + %i4 = load i93* %i + %C = icmp eq i93 %i3, %i4 + br i1 %C, label %ok1, label %fail +ok1: + %b = bitcast i93* %i to [12 x i8]* + %b0 = getelementptr [12 x i8]* %b, i32 0, i32 0 + %v0 = load i8* %b0 + %c0 = icmp eq i8 %v0, 30 + br i1 %c0, label %ok2, label %fail +ok2: + %b1 = getelementptr [12 x i8]* %b, i32 0, i32 1 + %v1 = load i8* %b1 + %c1 = icmp eq i8 %v1, 220 + br i1 %c1, label %ok3, label %fail +ok3: + %b2 = getelementptr [12 x i8]* %b, i32 0, i32 2 + %v2 = load i8* %b2 + %c2 = icmp eq i8 %v2, 186 + br i1 %c2, label %ok4, label %fail +ok4: + %b3 = getelementptr [12 x i8]* %b, i32 0, i32 3 + %v3 = load i8* %b3 + %c3 = icmp eq i8 %v3, 152 + br i1 %c3, label %ok5, label %fail +ok5: + %b4 = getelementptr [12 x i8]* %b, i32 0, i32 4 + %v4 = load i8* %b4 + %c4 = icmp eq i8 %v4, 118 + br i1 %c4, label %ok6, label %fail +ok6: + %b5 = getelementptr [12 x i8]* %b, i32 0, i32 5 + %v5 = load i8* %b5 + %c5 = icmp eq i8 %v5, 84 + br i1 %c5, label %ok7, label %fail +ok7: + %b6 = getelementptr [12 x i8]* %b, i32 0, i32 6 + %v6 = load i8* %b6 + %c6 = icmp eq i8 %v6, 50 + br i1 %c6, label %ok8, label %fail +ok8: + %b7 = getelementptr [12 x i8]* %b, i32 0, i32 7 + %v7 = load i8* %b7 + %c7 = icmp eq i8 %v7, 16 + br i1 %c7, label %ok9, label %fail +ok9: + %b8 = getelementptr [12 x i8]* %b, i32 0, i32 8 + %v8 = load i8* %b8 + %c8 = icmp eq i8 %v8, 223 + br i1 %c8, label %okA, label %fail +okA: + %b9 = getelementptr [12 x i8]* %b, i32 0, i32 9 + %v9 = load i8* %b9 + %c9 = icmp eq i8 %v9, 188 + br i1 %c9, label %okB, label %fail +okB: + %bA = getelementptr [12 x i8]* %b, i32 0, i32 10 + %vA = load i8* %bA + %cA = icmp eq i8 %vA, 154 + br i1 %cA, label %okC, label %fail +okC: + %bB = getelementptr [12 x i8]* %b, i32 0, i32 11 + %vB = load i8* %bB + %cB = icmp eq i8 %vB, 120 + br i1 %cB, label %okD, label %fail +okD: + ret i32 0 +fail: + ret i32 1 +} diff --git a/test/ExecutionEngine/2007-12-14-LittleEndian.ll b/test/ExecutionEngine/2007-12-14-LittleEndian.ll new file mode 100644 index 0000000..afaed51 --- /dev/null +++ b/test/ExecutionEngine/2007-12-14-LittleEndian.ll @@ -0,0 +1,81 @@ +; RUN: llvm-as < %s -o - | lli -force-interpreter + +target datalayout = "e" + +define i32 @main() { +entry: + %i = alloca i93 + store i93 18364758544493064720, i93* %i + %i1 = load i93* %i + %i2 = shl i93 %i1, 32 + %i3 = or i93 %i2, 3753679480 + store i93 %i3, i93* %i + %i4 = load i93* %i + %C = icmp eq i93 %i3, %i4 + br i1 %C, label %ok1, label %fail +ok1: + %b = bitcast i93* %i to [12 x i8]* + %b0 = getelementptr [12 x i8]* %b, i32 0, i32 0 + %v0 = load i8* %b0 + %c0 = icmp eq i8 %v0, 120 + br i1 %c0, label %ok2, label %fail +ok2: + %b1 = getelementptr [12 x i8]* %b, i32 0, i32 1 + %v1 = load i8* %b1 + %c1 = icmp eq i8 %v1, 154 + br i1 %c1, label %ok3, label %fail +ok3: + %b2 = getelementptr [12 x i8]* %b, i32 0, i32 2 + %v2 = load i8* %b2 + %c2 = icmp eq i8 %v2, 188 + br i1 %c2, label %ok4, label %fail +ok4: + %b3 = getelementptr [12 x i8]* %b, i32 0, i32 3 + %v3 = load i8* %b3 + %c3 = icmp eq i8 %v3, 223 + br i1 %c3, label %ok5, label %fail +ok5: + %b4 = getelementptr [12 x i8]* %b, i32 0, i32 4 + %v4 = load i8* %b4 + %c4 = icmp eq i8 %v4, 16 + br i1 %c4, label %ok6, label %fail +ok6: + %b5 = getelementptr [12 x i8]* %b, i32 0, i32 5 + %v5 = load i8* %b5 + %c5 = icmp eq i8 %v5, 50 + br i1 %c5, label %ok7, label %fail +ok7: + %b6 = getelementptr [12 x i8]* %b, i32 0, i32 6 + %v6 = load i8* %b6 + %c6 = icmp eq i8 %v6, 84 + br i1 %c6, label %ok8, label %fail +ok8: + %b7 = getelementptr [12 x i8]* %b, i32 0, i32 7 + %v7 = load i8* %b7 + %c7 = icmp eq i8 %v7, 118 + br i1 %c7, label %ok9, label %fail +ok9: + %b8 = getelementptr [12 x i8]* %b, i32 0, i32 8 + %v8 = load i8* %b8 + %c8 = icmp eq i8 %v8, 152 + br i1 %c8, label %okA, label %fail +okA: + %b9 = getelementptr [12 x i8]* %b, i32 0, i32 9 + %v9 = load i8* %b9 + %c9 = icmp eq i8 %v9, 186 + br i1 %c9, label %okB, label %fail +okB: + %bA = getelementptr [12 x i8]* %b, i32 0, i32 10 + %vA = load i8* %bA + %cA = icmp eq i8 %vA, 220 + br i1 %cA, label %okC, label %fail +okC: + %bB = getelementptr [12 x i8]* %b, i32 0, i32 11 + %vB = load i8* %bB + %cB = icmp eq i8 %vB, 30 + br i1 %cB, label %okD, label %fail +okD: + ret i32 0 +fail: + ret i32 1 +} |