From 6eb64ddcda93810a3c44f919049e3306deee2bf7 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 16:57:13 +0100 Subject: [PATCH 1/5] Codegen for GAS --- evmcc/Compiler.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 0fa2c5c03..91758984d 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -659,6 +659,13 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::GAS: + { + auto value = builder.CreateLoad(gasMeter.getLLVMGasVar()); + stack.push(value); + break; + } + case Instruction::ADDRESS: { auto value = ext.address(); From 2031240485a4290345ad2828d84477767b0b1a68 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Mon, 13 Oct 2014 17:22:56 +0100 Subject: [PATCH 2/5] Implemented ADDMOD, MULMOD and GAS [Delivers #80566276] --- evmcc/Compiler.cpp | 30 ++++++++++++++++++++++++++++++ evmcc/GasMeter.cpp | 7 ++++++- evmcc/GasMeter.h | 2 ++ evmcc/test/arith/addmod.evm | 1 + evmcc/test/arith/addmod.lll | 12 ++++++++++++ evmcc/test/arith/mulmod.evm | 1 + evmcc/test/arith/mulmod.lll | 12 ++++++++++++ 7 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 evmcc/test/arith/addmod.evm create mode 100644 evmcc/test/arith/addmod.lll create mode 100644 evmcc/test/arith/mulmod.evm create mode 100644 evmcc/test/arith/mulmod.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 91758984d..b5270d85a 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -434,6 +434,36 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::ADDMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto sum = builder.CreateAdd(val1, val2); + auto mod = stack.pop(); + + auto sum128 = builder.CreateTrunc(sum, Type::lowPrecision); + auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = builder.CreateURem(sum128, mod128); + auto res256 = builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } + + case Instruction::MULMOD: + { + auto val1 = stack.pop(); + auto val2 = stack.pop(); + auto prod = builder.CreateMul(val1, val2); + auto mod = stack.pop(); + + auto prod128 = builder.CreateTrunc(prod, Type::lowPrecision); + auto mod128 = builder.CreateTrunc(mod, Type::lowPrecision); + auto res128 = builder.CreateURem(prod128, mod128); + auto res256 = builder.CreateZExt(res128, Type::i256); + stack.push(res256); + break; + } + case Instruction::SHA3: { auto inOff = stack.pop(); diff --git a/evmcc/GasMeter.cpp b/evmcc/GasMeter.cpp index 13d81b080..918be7bf7 100644 --- a/evmcc/GasMeter.cpp +++ b/evmcc/GasMeter.cpp @@ -130,4 +130,9 @@ void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilde _builder.CreateCall(m_gasCheckFunc, cost); } -} \ No newline at end of file +llvm::GlobalVariable* GasMeter::getLLVMGasVar() +{ + return m_gas; +} + +} diff --git a/evmcc/GasMeter.h b/evmcc/GasMeter.h index 1fcbe6459..c3ea9f84f 100644 --- a/evmcc/GasMeter.h +++ b/evmcc/GasMeter.h @@ -25,6 +25,8 @@ public: /// Generate code that checks the cost of additional memory used by program void checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder); + llvm::GlobalVariable* getLLVMGasVar(); + private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow diff --git a/evmcc/test/arith/addmod.evm b/evmcc/test/arith/addmod.evm new file mode 100644 index 000000000..4ca71e065 --- /dev/null +++ b/evmcc/test/arith/addmod.evm @@ -0,0 +1 @@ +60646107b760271460005560006001f2 diff --git a/evmcc/test/arith/addmod.lll b/evmcc/test/arith/addmod.lll new file mode 100644 index 000000000..11a6b2cb9 --- /dev/null +++ b/evmcc/test/arith/addmod.lll @@ -0,0 +1,12 @@ +;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e +(asm +100 +1975 +39 +ADDMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/arith/mulmod.evm b/evmcc/test/arith/mulmod.evm new file mode 100644 index 000000000..e34a06154 --- /dev/null +++ b/evmcc/test/arith/mulmod.evm @@ -0,0 +1 @@ +6064601b60251560005560006001f2 diff --git a/evmcc/test/arith/mulmod.lll b/evmcc/test/arith/mulmod.lll new file mode 100644 index 000000000..5e87f0843 --- /dev/null +++ b/evmcc/test/arith/mulmod.lll @@ -0,0 +1,12 @@ +;; Should return (27 * 37) `mod` 100 = 99 = 0x63 +(asm +100 +27 +37 +MULMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file From a5c239ffc9bf90aad71795cce10ba8ca570a56d6 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 09:24:33 +0100 Subject: [PATCH 3/5] Fixes in inline asm in some jump tests. --- evmcc/test/jump/loop1.evm | 2 +- evmcc/test/jump/loop1.lll | 16 ++++++++-------- evmcc/test/jump/loop2.evm | 2 +- evmcc/test/jump/loop2.lll | 22 +++++++++++----------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/evmcc/test/jump/loop1.evm b/evmcc/test/jump/loop1.evm index b209951fa..e7cbc4aa9 100644 --- a/evmcc/test/jump/loop1.evm +++ b/evmcc/test/jump/loop1.evm @@ -1 +1 @@ -600a600181038060025900 +600a600181038060025960005460015460025460035400 diff --git a/evmcc/test/jump/loop1.lll b/evmcc/test/jump/loop1.lll index 1d9483eb8..8ce24e4cd 100644 --- a/evmcc/test/jump/loop1.lll +++ b/evmcc/test/jump/loop1.lll @@ -12,14 +12,14 @@ DUP1 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE -;;3 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE +3 +MSTORE STOP ) diff --git a/evmcc/test/jump/loop2.evm b/evmcc/test/jump/loop2.evm index c95047707..6a55228a8 100644 --- a/evmcc/test/jump/loop2.evm +++ b/evmcc/test/jump/loop2.evm @@ -1 +1 @@ -600a80600160800360a060025900 +600a80600190038060025960005460015460025460035400 diff --git a/evmcc/test/jump/loop2.lll b/evmcc/test/jump/loop2.lll index 29d5e0ace..b53e6713d 100644 --- a/evmcc/test/jump/loop2.lll +++ b/evmcc/test/jump/loop2.lll @@ -5,22 +5,22 @@ ;; 2 DUP1 -1 -SWAP +1 +SWAP1 SUB -DUP +DUP1 2 JUMPI ;; stack = 1 2 3 4 5 6 7 8 9 10 -;;0 -;;MSTORE -;;1 -;;MSTORE -;;2 -;;MSTORE -;;3 -;;MSTORE +0 +MSTORE +1 +MSTORE +2 +MSTORE +3 +MSTORE STOP ) From d005896a0b5c33623abad685dca19c8f2768048f Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 14:52:15 +0100 Subject: [PATCH 4/5] Initial implementation for CALLDATACOPY [Delivers #80644732] --- evmcc/Compiler.cpp | 30 ++++++++++++++++++++++++++++++ evmcc/Ext.cpp | 6 +++--- evmcc/Ext.h | 1 + evmcc/Memory.cpp | 5 +++++ evmcc/Memory.h | 1 + 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 5857040f8..47cbbf5c1 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -736,6 +736,36 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) break; } + case Instruction::CALLDATACOPY: + { + auto zero256 = ConstantInt::get(Type::i256, 0); + + auto destMemIdx = stack.pop(); + auto srcDataIdx = stack.pop(); + auto reqByteCount = stack.pop(); + + // FIXME: ensure memory size reqMemSize. + auto reqMemSize = builder.CreateAdd(destMemIdx, reqByteCount); + auto reqMemWord = builder.CreateSub(reqMemSize, ConstantInt::get(Type::i256, 32)); + memory.loadWord(reqMemWord); + + auto memPtr = memory.getData(); + auto destPtr = builder.CreateGEP(memPtr, destMemIdx); + + auto calldataPtr = ext.calldata(); + auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx); + + auto calldataSize = ext.calldatasize(); + // remaining data bytes: + auto remDataSize = builder.CreateSub(calldataSize, srcDataIdx); + auto remSizeNegative = builder.CreateICmpSLT(remDataSize, zero256); + auto bytesToCopy = builder.CreateSelect(remSizeNegative, zero256, remDataSize); + + builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); + + break; + } + case Instruction::CALLDATALOAD: { auto index = stack.pop(); diff --git a/evmcc/Ext.cpp b/evmcc/Ext.cpp index 1d309947d..bb2a54870 100644 --- a/evmcc/Ext.cpp +++ b/evmcc/Ext.cpp @@ -14,7 +14,6 @@ using llvm::types::i; using Linkage = llvm::GlobalValue::LinkageTypes; using dev::h256; using dev::u256; - namespace evmcc { @@ -70,7 +69,7 @@ Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module) i256Ty, // i256 number; i256Ty, // i256 difficulty; i256Ty, // i256 gaslimit; - //m_builder.getInt8PtrTy() + m_builder.getInt8PtrTy() // byte* calldata }; auto extDataTy = StructType::create(elements, "ext.Data"); @@ -125,6 +124,7 @@ Value* Ext::timestamp() { return getDataElem(8, "timestamp"); } Value* Ext::number() { return getDataElem(9, "number"); } Value* Ext::difficulty() { return getDataElem(10, "difficulty"); } Value* Ext::gaslimit() { return getDataElem(11, "gaslimit"); } +Value* Ext::calldata() { return getDataElem(12, "calldata"); } Value* Ext::calldataload(Value* _index) { @@ -218,7 +218,7 @@ EXPORT void ext_init(ExtData* _extData) _extData->number = eth2llvm(ext.currentBlock.number); _extData->difficulty = eth2llvm(ext.currentBlock.difficulty); _extData->gaslimit = eth2llvm(ext.currentBlock.gasLimit); - //_extData->calldata = ext.data.data(); + _extData->calldata = ext.data.data(); } EXPORT void ext_store(i256* _index, i256* _value) diff --git a/evmcc/Ext.h b/evmcc/Ext.h index 302991854..5c683ffdf 100644 --- a/evmcc/Ext.h +++ b/evmcc/Ext.h @@ -31,6 +31,7 @@ public: llvm::Value* number(); llvm::Value* difficulty(); llvm::Value* gaslimit(); + llvm::Value* calldata(); llvm::Value* balance(llvm::Value* _address); void suicide(llvm::Value* _address); diff --git a/evmcc/Memory.cpp b/evmcc/Memory.cpp index 4d4a34928..0098ed1f9 100644 --- a/evmcc/Memory.cpp +++ b/evmcc/Memory.cpp @@ -126,6 +126,11 @@ void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) dump(0); } +llvm::Value* Memory::getData() +{ + return m_builder.CreateLoad(m_data); +} + llvm::Value* Memory::getSize() { return m_builder.CreateLoad(m_size); diff --git a/evmcc/Memory.h b/evmcc/Memory.h index c01bd6ef8..8b22294d7 100644 --- a/evmcc/Memory.h +++ b/evmcc/Memory.h @@ -18,6 +18,7 @@ public: llvm::Value* loadWord(llvm::Value* _addr); void storeWord(llvm::Value* _addr, llvm::Value* _word); void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getData(); llvm::Value* getSize(); void registerReturnData(llvm::Value* _index, llvm::Value* _size); From 2b383751b4374a55eb0964c6f097364986ebebb8 Mon Sep 17 00:00:00 2001 From: artur-zawlocki Date: Tue, 14 Oct 2014 15:19:18 +0100 Subject: [PATCH 5/5] Fixes in CALLDATACOPY [Delivers #80644732] --- evmcc/Compiler.cpp | 16 +++++++++------- evmcc/test/ext/calldatacopy1.evm | 1 + evmcc/test/ext/calldatacopy1.lll | 13 +++++++++++++ evmcc/test/ext/calldatacopy2.evm | 1 + evmcc/test/ext/calldatacopy2.lll | 13 +++++++++++++ 5 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 evmcc/test/ext/calldatacopy1.evm create mode 100644 evmcc/test/ext/calldatacopy1.lll create mode 100644 evmcc/test/ext/calldatacopy2.evm create mode 100644 evmcc/test/ext/calldatacopy2.lll diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 3037145c2..3bb0a843c 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -742,24 +742,26 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) auto destMemIdx = stack.pop(); auto srcDataIdx = stack.pop(); - auto reqByteCount = stack.pop(); + auto reqBytes = stack.pop(); // FIXME: ensure memory size reqMemSize. - auto reqMemSize = builder.CreateAdd(destMemIdx, reqByteCount); - auto reqMemWord = builder.CreateSub(reqMemSize, ConstantInt::get(Type::i256, 32)); - memory.loadWord(reqMemWord); + auto reqMemSize = builder.CreateAdd(destMemIdx, reqBytes, "req_mem_size"); + memory.require(reqMemSize); auto memPtr = memory.getData(); - auto destPtr = builder.CreateGEP(memPtr, destMemIdx); + auto destPtr = builder.CreateGEP(memPtr, destMemIdx, "dest_mem_ptr"); auto calldataPtr = ext.calldata(); - auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx); + auto srcPtr = builder.CreateGEP(calldataPtr, srcDataIdx, "src_idx"); auto calldataSize = ext.calldatasize(); // remaining data bytes: auto remDataSize = builder.CreateSub(calldataSize, srcDataIdx); auto remSizeNegative = builder.CreateICmpSLT(remDataSize, zero256); - auto bytesToCopy = builder.CreateSelect(remSizeNegative, zero256, remDataSize); + auto remDataBytes = builder.CreateSelect(remSizeNegative, zero256, remDataSize, "rem_data_bytes"); + + auto tooLittleDataBytes = builder.CreateICmpULT(remDataBytes, reqBytes); + auto bytesToCopy = builder.CreateSelect(tooLittleDataBytes, remDataBytes, reqBytes, "bytes_to_copy"); builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); diff --git a/evmcc/test/ext/calldatacopy1.evm b/evmcc/test/ext/calldatacopy1.evm new file mode 100644 index 000000000..73c4d76b8 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.evm @@ -0,0 +1 @@ +60146000600a37600053600a6014f2 diff --git a/evmcc/test/ext/calldatacopy1.lll b/evmcc/test/ext/calldatacopy1.lll new file mode 100644 index 000000000..da3666c71 --- /dev/null +++ b/evmcc/test/ext/calldatacopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in calldata array +10 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmcc/test/ext/calldatacopy2.evm b/evmcc/test/ext/calldatacopy2.evm new file mode 100644 index 000000000..e8eea8da7 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000376000536000600af2 diff --git a/evmcc/test/ext/calldatacopy2.lll b/evmcc/test/ext/calldatacopy2.lll new file mode 100644 index 000000000..6bbea48d8 --- /dev/null +++ b/evmcc/test/ext/calldatacopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in calldata array +0 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file