diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp index 806592287..b6c420d53 100644 --- a/evmcc/Compiler.cpp +++ b/evmcc/Compiler.cpp @@ -137,7 +137,16 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) } } - for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();) + // Remove split points generated from jumps out of code or into data. + for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) + { + if (*it > bytecode.size() || !validJumpTargets[*it]) + it = splitPoints.erase(it); + else + ++it; + } + + for (auto it = splitPoints.cbegin(); it != splitPoints.cend(); ) { auto beginInstIdx = *it; ++it; @@ -151,28 +160,22 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode) for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) { - if (it->second >= bytecode.size()) // Jump out of code + auto blockIter = basicBlocks.find(it->second); + if (blockIter != basicBlocks.end()) { - m_directJumpTargets[it->first] = m_finalBlock.get(); + m_directJumpTargets[it->first] = &(blockIter->second); } - else if (!validJumpTargets[it->second]) // Jump into data + else { std::cerr << "Bad JUMP at PC " << it->first << ": " << it->second << " is not a valid PC\n"; m_directJumpTargets[it->first] = m_badJumpBlock.get(); } - else - { - m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second; - } } for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) { - if (*it >= bytecode.size()) - m_indirectJumpTargets.push_back(m_finalBlock.get()); - else - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); } } @@ -196,8 +199,8 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) createBasicBlocks(bytecode); // Init runtime structures. - auto memory = Memory(builder, module.get()); - auto ext = Ext(builder, module.get()); + Memory memory(builder, module.get()); + Ext ext(builder, module.get()); GasMeter gasMeter(builder, module.get()); // Jump to first instruction @@ -587,58 +590,56 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) // 1. this is not the first instruction in the block // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) // Otherwise generate a indirect jump (a switch). + BasicBlock* targetBlock = nullptr; if (currentPC != basicBlock.begin()) { auto pairIter = m_directJumpTargets.find(currentPC); if (pairIter != m_directJumpTargets.end()) { - auto targetBlock = pairIter->second; + targetBlock = pairIter->second; + } + } + if (inst == Instruction::JUMP) + { + if (targetBlock) + { // The target address is computed at compile time, // just pop it without looking... stack.pop(); - - if (inst == Instruction::JUMP) - { - builder.CreateBr(targetBlock->llvm()); - } - else // JUMPI - { - auto top = stack.pop(); - auto zero = ConstantInt::get(Type::i256, 0); - auto cond = builder.CreateICmpNE(top, zero, "nonzero"); - - // Assume the basic blocks are properly ordered: - auto nextBBIter = basicBlockPairIt; - ++nextBBIter; - assert (nextBBIter != basicBlocks.end()); - auto& followBlock = nextBBIter->second; - builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); - } - break; + builder.CreateBr(targetBlock->llvm()); + } + else + { + // FIXME: this get(0) is a temporary workaround to get some of the jump tests running. + stack.get(0); + builder.CreateBr(m_jumpTableBlock->llvm()); } } - - if (inst == Instruction::JUMPI) + else // JUMPI { - std::cerr << "Indirect JUMPI is not supported yet (at PC " - << currentPC << ")\n"; - std::exit(1); + stack.swap(1); + auto val = stack.pop(); + auto zero = ConstantInt::get(Type::i256, 0); + auto cond = builder.CreateICmpNE(val, zero, "nonzero"); + + // Assume the basic blocks are properly ordered: + auto nextBBIter = basicBlockPairIt; + ++nextBBIter; + assert (nextBBIter != basicBlocks.end()); + auto& followBlock = nextBBIter->second; + + if (targetBlock) + { + stack.pop(); + builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm()); + } + else + { + builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm()); + } } - builder.CreateBr(m_jumpTableBlock->llvm()); - /* - // Generate switch for indirect jump. - auto dest = stack.pop(); - auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) - { - auto& bb = *it; - auto dest = ConstantInt::get(Type::i256, bb->begin()); - switchInstr->addCase(dest, bb->llvm()); - } - */ break; } @@ -865,7 +866,7 @@ std::unique_ptr Compiler::compile(const dev::bytes& bytecode) } else { - builder.CreateRet(builder.getInt64(0)); + builder.CreateBr(m_badJumpBlock->llvm()); } linkBasicBlocks();