diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 02c85165d6..736e0a572c 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -32,6 +32,7 @@ BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc) : void BasicBlock::Stack::push(llvm::Value* _value) { + assert(_value->getType() == Type::i256); m_backend.push_back(_value); } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index f3e9121250..34970c6026 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include "Ext.h" #include "GasMeter.h" #include "Utils.h" +#include "Endianness.h" namespace dev { @@ -420,21 +421,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, const auto byteNum = stack.pop(); auto value = stack.pop(); - /* - if (byteNum < 32) - use select - { - value <<= byteNum*8 - value >>= 31*8 - push value - } - else push 0 - */ - - // TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439 - - auto shbits = m_builder.CreateShl(byteNum, Constant::get(3)); - value = m_builder.CreateShl(value, shbits); - value = m_builder.CreateLShr(value, Constant::get(31 * 8)); + // + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto byte = m_builder.CreateExtractElement(bytes, byteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::i256); auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); diff --git a/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp new file mode 100644 index 0000000000..7de7b95141 --- /dev/null +++ b/libevmjit/Endianness.cpp @@ -0,0 +1,24 @@ + +#include "Endianness.h" + +#include + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + // TODO: Native is Little Endian + auto bswap = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::i256); + return _builder.CreateCall(bswap, _word); +} + +} +} +} diff --git a/libevmjit/Endianness.h b/libevmjit/Endianness.h new file mode 100644 index 0000000000..7b449b4d85 --- /dev/null +++ b/libevmjit/Endianness.h @@ -0,0 +1,22 @@ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Endianness +{ +public: + + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +}