From e8ff67cb484f62df3978ad83b92df5637dbe70d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <pawel.bylica@imapp.pl>
Date: Mon, 29 Sep 2014 14:39:17 +0200
Subject: [PATCH] Stack interface and implementation

---
 evmcc/Compiler.cpp |  23 ++++-----
 evmcc/Stack.cpp    | 118 ++++++++++++++++++++++++++++++++++++++++-----
 evmcc/Stack.h      |  26 ++++++++++
 3 files changed, 143 insertions(+), 24 deletions(-)
 create mode 100644 evmcc/Stack.h

diff --git a/evmcc/Compiler.cpp b/evmcc/Compiler.cpp
index 7478dd683..4c3a8a5f2 100644
--- a/evmcc/Compiler.cpp
+++ b/evmcc/Compiler.cpp
@@ -3,6 +3,8 @@
 
 #include <llvm/IR/IRBuilder.h>
 
+#include "Stack.h"
+
 namespace evmcc
 {
 
@@ -49,7 +51,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
 	auto stack2 = new GlobalVariable(*module, Types.word256arr, false,
 		GlobalValue::LinkageTypes::PrivateLinkage,
 		ConstantAggregateZero::get(Types.word256arr), "stack");
-	auto stackTop = new GlobalVariable(*module, Types.size, false,
+	auto stackTop2 = new GlobalVariable(*module, Types.size, false,
 		GlobalValue::LinkageTypes::PrivateLinkage,
 		ConstantInt::get(Types.size, 0), "stackTop");
 
@@ -57,13 +59,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
 	auto mallocVal = Function::Create(FunctionType::get(Types.word8ptr, { Types.size }, false),
 		GlobalValue::LinkageTypes::ExternalLinkage, "malloc", module.get());
 
-	// Create stack_create declaration
-	auto stackCreate = Function::Create(FunctionType::get(Types.word8ptr, false),
-		GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", module.get());
-
-	auto stackPush = Function::Create(FunctionType::get(Types.Void, std::vector<Type*>{ Types.word8ptr, Types.word256 }, false),
-		GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", module.get());
-
 	// Create main function
 	FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false);
 	Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get());
@@ -77,14 +72,20 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
 	builder.CreateStore(mallocMemCall, memory);
 	builder.CreateStore(ConstantInt::get(Types.size, 100), memSize);
 
-	auto stack = builder.CreateCall(stackCreate, "stack");
+	auto stack = Stack(builder, module.get());
 
 	uint64_t words[] = { 1, 2, 3, 4 };
 	auto val = llvm::APInt(256, 4, words);
 	auto c = ConstantInt::get(Types.word256, val);
 
-	Value* args[] = { stack, c };
-	builder.CreateCall(stackPush, args);
+	stack.push(c);
+	stack.push(ConstantInt::get(Types.word256, 0x1122334455667788));
+
+	auto top = stack.top();
+	stack.push(top);	// dup
+
+	stack.pop();
+
 
 	/*
 	std::vector<Value*> mallocStackArgs = { ConstantInt::get(sizeTy, 200) };
diff --git a/evmcc/Stack.cpp b/evmcc/Stack.cpp
index e3faffd7e..d23456de6 100644
--- a/evmcc/Stack.cpp
+++ b/evmcc/Stack.cpp
@@ -1,8 +1,13 @@
 
+#include "Stack.h"
+
 #include <vector>
 #include <iostream>
 #include <iomanip>
 #include <cstdint>
+#include <cassert>
+
+#include <llvm/IR/Function.h>
 
 #ifdef _MSC_VER
 	#define EXPORT __declspec(dllexport)
@@ -10,6 +15,9 @@
 	#define EXPORT
 #endif
 
+namespace evmcc
+{
+
 struct i256
 {
 	uint64_t a;
@@ -17,30 +25,114 @@ struct i256
 	uint64_t c;
 	uint64_t d;
 };
+static_assert(sizeof(i256) == 32, "Wrong i265 size");
+
+using StackImpl = std::vector<i256>;
+
+
+Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module)
+	: m_builder(_builder)
+{
+	// TODO: Clean up LLVM types
+	auto stackPtrTy = m_builder.getInt8PtrTy();
+	auto i256Ty = m_builder.getIntNTy(256);
+	auto i256PtrTy = i256Ty->getPointerTo();
+	auto voidTy = m_builder.getVoidTy();
+
+	auto stackCreate = llvm::Function::Create(llvm::FunctionType::get(stackPtrTy, false),
+		llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_create", _module);
+
+	llvm::Type* argsTypes[] = {stackPtrTy, i256PtrTy};
+	auto funcType = llvm::FunctionType::get(voidTy, argsTypes, false);
+	m_stackPush = llvm::Function::Create(funcType,
+		llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module);
 
-using Stack = std::vector<i256>;
+	m_stackTop = llvm::Function::Create(funcType,
+		llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_top", _module);
+
+	m_stackPop = llvm::Function::Create(funcType,
+		llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module);
+
+	m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr");
+	m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val");
+}
+
+
+void Stack::push(llvm::Value* _value)
+{
+	m_builder.CreateStore(_value, m_args[1]);	  // copy value to memory
+	m_builder.CreateCall(m_stackPush, m_args);
+}
+
+
+llvm::Value* Stack::top()
+{
+	m_builder.CreateCall(m_stackTop, m_args);
+	return m_builder.CreateLoad(m_args[1]);
+}
+
+
+llvm::Value* Stack::pop()
+{
+	m_builder.CreateCall(m_stackPop, m_args);
+	return m_builder.CreateLoad(m_args[1]);
+}
+
+
+void debugStack(const char* op, const i256& word)
+{
+	std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << op << ": "
+		<< std::dec << word.a
+		<< " HEX: " << std::hex << std::setfill('0');
+	if (word.b || word.c || word.d)
+	{
+		std::cerr << std::setw(16) << word.d << " "
+			<< std::setw(16) << word.c << " "
+			<< std::setw(16) << word.b << " ";
+	}
+	std::cerr << std::setw(16) << word.a << "\n";
+}
+
+}
 
 extern "C"
 {
+	using namespace evmcc;
 
 EXPORT void* evmccrt_stack_create()
 {
-	std::cerr << "STACK create: ";
-	auto stack = new Stack;
-	std::cerr << stack << "\n";
+	auto stack = new StackImpl;
+	std::cerr << "STACK create\n";
 	return stack;
 }
 
-EXPORT void evmccrt_stack_push(void* _stack, uint64_t _partA, uint64_t _partB, uint64_t _partC, uint64_t _partD)
+EXPORT void evmccrt_stack_push(void* _stack, void* _pWord)
+{
+	auto stack = static_cast<StackImpl*>(_stack);
+	auto word = static_cast<i256*>(_pWord);
+	debugStack("push", *word);
+	stack->push_back(*word);
+}
+
+EXPORT void evmccrt_stack_top(void* _stack, void* _pWord)
+{
+	auto stack = static_cast<StackImpl*>(_stack);
+	assert(!stack->empty());
+	auto word = &stack->back();
+	debugStack("top", *word);
+	auto outWord = static_cast<i256*>(_pWord);
+	*outWord = *word;
+}
+
+EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord)
 {
-	std::cerr << "STACK push: " << _partA << " (" << std::hex << std::setfill('0')
-			  << std::setw(16) << _partD << " " 
-			  << std::setw(16) << _partC << " " 
-			  << std::setw(16) << _partB << " "
-			  << std::setw(16) << _partA;
-	auto stack = static_cast<Stack*>(_stack);
-	stack->push_back({_partA, _partB, _partC, _partD});
-	std::cerr << ")\n";
+	auto stack = static_cast<StackImpl*>(_stack);
+	assert(!stack->empty());
+	auto word = &stack->back();
+	debugStack("pop", *word);
+	auto outWord = static_cast<i256*>(_pWord);
+	stack->pop_back();
+	*outWord = *word;
 }
 
 }	// extern "C"
diff --git a/evmcc/Stack.h b/evmcc/Stack.h
new file mode 100644
index 000000000..e8b6a8e2d
--- /dev/null
+++ b/evmcc/Stack.h
@@ -0,0 +1,26 @@
+
+#pragma once
+
+#include <llvm/IR/IRBuilder.h>
+
+namespace evmcc
+{
+
+class Stack
+{
+public:
+	Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module);
+
+	void push(llvm::Value* _value);
+	llvm::Value* top();
+	llvm::Value* pop();
+
+private:
+	llvm::IRBuilder<>& m_builder;
+	llvm::Value* m_args[2];
+	llvm::Function* m_stackPush;
+	llvm::Function* m_stackTop;
+	llvm::Function* m_stackPop;
+};
+
+}
\ No newline at end of file