summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--asm/intel64/encode.cpp141
-rw-r--r--cpp.cpp22
-rw-r--r--flowgraph/node.cpp13
-rw-r--r--flowgraph/node.h24
-rw-r--r--flowgraph/storage.h18
-rw-r--r--systemtest/config/unix.exp19
-rw-r--r--systemtest/mcc-execute.tests/exitcodes.exp17
-rw-r--r--systemtest/mcc-execute.tests/test-addition.cpp (renamed from systemtest/mcc-execute.tests/test1.cpp)0
-rw-r--r--systemtest/mcc-execute.tests/test-return-1.cpp (renamed from systemtest/mcc-execute.tests/test.cpp)0
-rw-r--r--tests/test-cpp.cpp6
-rw-r--r--tests/test-flowgraph.cpp14
12 files changed, 186 insertions, 99 deletions
diff --git a/Makefile b/Makefile
index 6c646c0..e7d50dd 100644
--- a/Makefile
+++ b/Makefile
@@ -98,12 +98,12 @@ TESTSRC=\
SRC=$(PROGSRC) mcc.cpp
all: test-$(PROJECTNAME) mcc
- ./test-$(PROJECTNAME) --gtest_filter='CppTest.compile'
+ ./test-$(PROJECTNAME) # --gtest_filter='CppTest.compile_1'
systemtest:
- #./mcc systemtest/mcc-execute.tests/test.cpp
- ./mcc systemtest/mcc-execute.tests/test1.cpp
- runtest --all --srcdir systemtest --tool mcc
+ ./mcc systemtest/mcc-execute.tests/test-return-1.cpp
+ ./mcc systemtest/mcc-execute.tests/test-addition.cpp
+ runtest --srcdir systemtest --tool mcc # --all
# testsuite ----------------------------------------------
test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)
@@ -133,7 +133,8 @@ ADD_DEP=Makefile
clean:
-rm -f test-$(PROJECTNAME) mcc tempfile.txt
-find . -name '*.o' -o -name '*.d' -o -name '*.gcno' -o -name '*.gcda' | xargs rm -f
- -rm -f systemtest/mcc-execute.tests/test1
+ -rm -f systemtest/mcc-execute.tests/test-return-1
+ -rm -f systemtest/mcc-execute.tests/test-addition
-rm -f *.log *.sum
zip: clean
diff --git a/asm/intel64/encode.cpp b/asm/intel64/encode.cpp
index 702efaf..b26bf9c 100644
--- a/asm/intel64/encode.cpp
+++ b/asm/intel64/encode.cpp
@@ -13,61 +13,94 @@ void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment)
segment.clear();
for (const std::shared_ptr<FlowGraph::Node>& node: graph) {
- try {
- FlowGraph::BinaryOperation& op {dynamic_cast<FlowGraph::BinaryOperation&>(*node)};
-
- auto operands {op.operands()};
- // TODO: ignore destination (0) for now
-
- if (operands[1].type() != FlowGraph::DataType::Int) {
- std::runtime_error("Bad type for operand 1: "s + std::to_string(int(operands[1].type())));
- }
-
- if (operands[2].type() != FlowGraph::DataType::Int) {
- std::runtime_error("Bad type for operand 2: "s + std::to_string(int(operands[2].type())));
- }
-
- if (!operands[1].storage())
- throw std::runtime_error("ICE: Operand 1 storage is 0");
- if (!operands[2].storage())
- throw std::runtime_error("ICE: Operand 2 storage is 0");
-
- uint32_t immediate1{};
- try {
- FlowGraph::Constant& value1 {dynamic_cast<FlowGraph::Constant&>(*operands[1].storage())};
- if (value1.value().size() < sizeof(uint32_t))
- throw std::runtime_error("ICE: Int data from operand 1 needs at least 4 bytes, got "s + std::to_string(value1.value().size()));
-
- immediate1 = boost::endian::little_to_native(*(reinterpret_cast<const uint32_t*>(value1.value().data())));
- } catch (const std::bad_cast& ex) {
- std::runtime_error("Bad value for operand 1: Constant expected");
- }
-
- uint32_t immediate2{};
- try {
- FlowGraph::Constant& value2 {dynamic_cast<FlowGraph::Constant&>(*operands[2].storage())};
- if (value2.value().size() < sizeof(uint32_t))
- throw std::runtime_error("ICE: Int data from operand 2 needs at least 4 bytes, got "s + std::to_string(value2.value().size()));
-
- immediate2 = boost::endian::little_to_native(*(reinterpret_cast<const uint32_t*>(value2.value().data())));
- } catch (const std::bad_cast& ex) {
- std::runtime_error("Bad value for operand 2: Constant expected");
+ if (node.get()) {
+ auto& node_deref = *node.get();
+ if (typeid(node_deref) == typeid(FlowGraph::UnaryOperation)) {
+ FlowGraph::UnaryOperation& op {dynamic_cast<FlowGraph::UnaryOperation&>(*node)};
+ auto operands {op.operands()};
+
+ if (operands[1].type() != FlowGraph::DataType::Int) {
+ std::runtime_error("Bad type for operand 1: "s + std::to_string(int(operands[1].type())));
+ }
+
+ if (!operands[1].storage())
+ throw std::runtime_error("ICE: Operand 1 storage is 0");
+
+ uint32_t immediate1{};
+ try {
+ FlowGraph::Constant& value1 {dynamic_cast<FlowGraph::Constant&>(*operands[1].storage())};
+ if (value1.value().size() < sizeof(uint32_t))
+ throw std::runtime_error("ICE: Int data from operand 1 needs at least 4 bytes, got "s + std::to_string(value1.value().size()));
+
+ immediate1 = boost::endian::little_to_native(*(reinterpret_cast<const uint32_t*>(value1.value().data())));
+ } catch (const std::bad_cast& ex) {
+ std::runtime_error("Bad value for operand 1: Constant expected");
+ }
+
+ if (op.type() == FlowGraph::UnaryOperationType::Store) {
+ Asm::Args args1{{Asm::Args::Register32("edi"), Asm::Args::Immediate32(immediate1)}};
+ segment.push_back(makeOp("mov", args1));
+ } else
+ throw std::runtime_error("ICE: Asm: Unsupported unary operation type: "s + std::to_string(static_cast<int>(op.type())));
+
+ } else if (typeid(node_deref) == typeid(FlowGraph::BinaryOperation)) {
+ FlowGraph::BinaryOperation& op {dynamic_cast<FlowGraph::BinaryOperation&>(*node)};
+
+ auto operands {op.operands()};
+ // TODO: ignore destination (0) for now
+
+ if (operands[1].type() != FlowGraph::DataType::Int) {
+ std::runtime_error("Bad type for operand 1: "s + std::to_string(int(operands[1].type())));
+ }
+
+ if (operands[2].type() != FlowGraph::DataType::Int) {
+ std::runtime_error("Bad type for operand 2: "s + std::to_string(int(operands[2].type())));
+ }
+
+ if (!operands[1].storage())
+ throw std::runtime_error("ICE: Operand 1 storage is 0");
+ if (!operands[2].storage())
+ throw std::runtime_error("ICE: Operand 2 storage is 0");
+
+ uint32_t immediate1{};
+ try {
+ FlowGraph::Constant& value1 {dynamic_cast<FlowGraph::Constant&>(*operands[1].storage())};
+ if (value1.value().size() < sizeof(uint32_t))
+ throw std::runtime_error("ICE: Int data from operand 1 needs at least 4 bytes, got "s + std::to_string(value1.value().size()));
+
+ immediate1 = boost::endian::little_to_native(*(reinterpret_cast<const uint32_t*>(value1.value().data())));
+ } catch (const std::bad_cast& ex) {
+ std::runtime_error("Bad value for operand 1: Constant expected");
+ }
+
+ uint32_t immediate2{};
+ try {
+ FlowGraph::Constant& value2 {dynamic_cast<FlowGraph::Constant&>(*operands[2].storage())};
+ if (value2.value().size() < sizeof(uint32_t))
+ throw std::runtime_error("ICE: Int data from operand 2 needs at least 4 bytes, got "s + std::to_string(value2.value().size()));
+
+ immediate2 = boost::endian::little_to_native(*(reinterpret_cast<const uint32_t*>(value2.value().data())));
+ } catch (const std::bad_cast& ex) {
+ std::runtime_error("Bad value for operand 2: Constant expected");
+ }
+
+ Asm::Args args1{{Asm::Args::Register32("edi"), Asm::Args::Immediate32(immediate1)}};
+ segment.push_back(makeOp("mov", args1));
+
+ Asm::Args args2{{Asm::Args::Register32("edi"), Asm::Args::Immediate32(immediate2)}};
+
+ if (op.type() == FlowGraph::BinaryOperationType::Add)
+ segment.push_back(makeOp("add", args2));
+ else if (op.type() == FlowGraph::BinaryOperationType::Multiply)
+ segment.push_back(makeOp("mul", args2));
+ else
+ throw std::runtime_error("ICE: Asm: Unsupported binary operation type: "s + std::to_string(static_cast<int>(op.type())));
+
+ } else {
+ throw std::runtime_error("ICE: Encoding: Unsupported node");
}
-
- Asm::Args args1{{Asm::Args::Register32("edi"), Asm::Args::Immediate32(immediate1)}};
- segment.push_back(makeOp("mov", args1));
-
- Asm::Args args2{{Asm::Args::Register32("edi"), Asm::Args::Immediate32(immediate2)}};
-
- if (op.type() == FlowGraph::BinaryOperationType::Add)
- segment.push_back(makeOp("add", args2));
- else if (op.type() == FlowGraph::BinaryOperationType::Multiply)
- segment.push_back(makeOp("mul", args2));
- else
- throw std::runtime_error("ICE: Asm: Unsupported binary operation type: "s + std::to_string(static_cast<int>(FlowGraph::BinaryOperationType::Multiply)));
-
- } catch (const std::bad_cast& ex) {
- std::runtime_error("ICE: Encoding: Unsupported node: "s + ex.what());
+ } else {
+ throw std::runtime_error("ICE: encode: flowgraph node is null");
}
}
}
diff --git a/cpp.cpp b/cpp.cpp
index 0b078ee..887dbbd 100644
--- a/cpp.cpp
+++ b/cpp.cpp
@@ -315,6 +315,7 @@ bool CPP::childTypesOfChildMatch(index_t index, index_t child_index, const std::
return childTypesOfNodeMatch(m_nodes[index].child_ids[child_index], pattern);
}
+// Get value for specified node, at bnf rule index child_index
std::any CPP::getValue(index_t node_id, index_t child_index)
{
size_t num_values_on_top {m_nodes[node_id].child_ids.size()};
@@ -506,9 +507,19 @@ std::unordered_map<std::string, std::function<std::any(index_t)>> CPP::getNodeEv
{ "expression", [&](index_t index) -> std::any
{
if (childTypesOfNodeMatch(index, {"assignment-expression"})) {
- std::shared_ptr<FlowGraph::Node> node {std::any_cast<std::shared_ptr<FlowGraph::Node>>(getValue(index, 0))};
- mCPPContext.graph.push_back(node);
- return getValue(index, 0);
+ if (getValue(index, 0).type() == typeid(FlowGraph::Data)) { // got Data -> make trivial Node out of it and return it
+ FlowGraph::LocalScope scope; // TODO: move to context!
+ FlowGraph::Data destination{FlowGraph::MakeTemporaryInt(scope)};
+ FlowGraph::Data source {std::any_cast<FlowGraph::Data>(getValue(index, 0))};
+
+ std::shared_ptr<FlowGraph::Node> node {std::make_shared<FlowGraph::UnaryOperation>(FlowGraph::UnaryOperationType::Store, destination, source)};
+ mCPPContext.graph.push_back(node);
+ return node;
+ } else {
+ std::shared_ptr<FlowGraph::Node> node {std::any_cast<std::shared_ptr<FlowGraph::Node>>(getValue(index, 0))};
+ mCPPContext.graph.push_back(node);
+ return getValue(index, 0);
+ }
}
throw std::runtime_error("ICE: Unsupported childs: "s + ruleString(index)); // TODO
}
@@ -592,9 +603,10 @@ void CPP::link()
mCode = std::vector<uint8_t>{
0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, // mov $0x3c,%rax # syscall 60
0x48, 0x31, 0xff, // xor %rdi,%rdi # exit code 0
- } + mSegment.getCode() + std::vector<uint8_t>{ // add to edi
+ } + mSegment.getCode() + std::vector<uint8_t>{ // # leave exit code in edi
0x0f, 0x05, // syscall
- };
+ }
+ ;
}
// phases of translation, according to standard
diff --git a/flowgraph/node.cpp b/flowgraph/node.cpp
index 795a252..9b68d74 100644
--- a/flowgraph/node.cpp
+++ b/flowgraph/node.cpp
@@ -14,17 +14,22 @@ Data FlowGraph::MakeConstantInt(int i)
return Data(DataType::Int, std::make_shared<Constant>(value));
}
-Data FlowGraph::MakeLocalPointer(const std::string& name)
+Data FlowGraph::MakeLocalPointer(FlowGraph::LocalScope& scope, const std::string& name)
{
- return Data(DataType::Pointer, std::make_shared<LocalStorage>(name));
+ return Data(DataType::Pointer, std::make_shared<LocalStorage>(scope, name));
}
-Data FlowGraph::MakeLocalSize(const std::string& name)
+Data FlowGraph::MakeLocalSize(FlowGraph::LocalScope& scope, const std::string& name)
{
- return Data(DataType::Size, std::make_shared<LocalStorage>(name));
+ return Data(DataType::Size, std::make_shared<LocalStorage>(scope, name));
}
Data FlowGraph::MakeTemporaryInt(FlowGraph::LocalScope& scope)
{
return Data(DataType::Int, std::make_shared<TemporaryStorage>(scope));
}
+
+LocalScope& CreateScopeOp::scope()
+{
+ return m_scope;
+}
diff --git a/flowgraph/node.h b/flowgraph/node.h
index 9ae5479..98c684d 100644
--- a/flowgraph/node.h
+++ b/flowgraph/node.h
@@ -43,8 +43,8 @@ namespace FlowGraph {
};
Data MakeConstantInt(int i);
- Data MakeLocalPointer(const std::string& name);
- Data MakeLocalSize(const std::string& name);
+ Data MakeLocalPointer(FlowGraph::LocalScope& scope, const std::string& name);
+ Data MakeLocalSize(FlowGraph::LocalScope& scope, const std::string& name);
Data MakeTemporaryInt(LocalScope& scope);
class MemCopy: public Node
@@ -114,7 +114,8 @@ namespace FlowGraph {
{
Increment,
Decrement,
- Negate
+ Negate,
+ Store // just take Data as-is to store it at destination
};
class UnaryOperation: public Node
@@ -159,4 +160,21 @@ namespace FlowGraph {
BinaryOperationType m_type;
};
+ // Open a new scope, with stack frame
+ class CreateScopeOp: public Node
+ {
+ public:
+ CreateScopeOp() {}
+ LocalScope& scope();
+ private:
+ LocalScope m_scope;
+ };
+
+ // Close current scope, closing stack frame
+ class DestroyScopeOp: public Node
+ {
+ public:
+ DestroyScopeOp() {}
+ };
+
} // namespace FlowGraph
diff --git a/flowgraph/storage.h b/flowgraph/storage.h
index 28aae1e..fd3c085 100644
--- a/flowgraph/storage.h
+++ b/flowgraph/storage.h
@@ -37,15 +37,6 @@ namespace FlowGraph {
std::string m_name;
};
- class LocalStorage : public Storage
- {
- public:
- LocalStorage(const std::string& name): m_name(name) {}
- const std::string& name() const { return m_name; }
- private:
- std::string m_name;
- };
-
// Provide a context for local temporaries name generation
class LocalScope
{
@@ -56,6 +47,15 @@ namespace FlowGraph {
size_t m_index{ 0 };
};
+ class LocalStorage : public Storage
+ {
+ public:
+ LocalStorage(LocalScope& scope, const std::string& name): m_name(name) {}
+ const std::string& name() const { return m_name; }
+ private:
+ std::string m_name;
+ };
+
// intermediate results, anonymous values
// use generated name
class TemporaryStorage : public Storage
diff --git a/systemtest/config/unix.exp b/systemtest/config/unix.exp
index e69de29..2de93b0 100644
--- a/systemtest/config/unix.exp
+++ b/systemtest/config/unix.exp
@@ -0,0 +1,19 @@
+proc runtest_exit_code { test_name command_line exit_code } {
+
+ spawn $command_line
+
+ expect eof
+
+ lassign [wait] pid spawnid os_error_flag value
+
+ if {$os_error_flag == 0} {
+ if {$value == $exit_code} {
+ pass "$test_name: Returned expected value $value"
+ } else {
+ fail "$test_name: Returned bad value $value, expected: $exit_code"
+ }
+ } else {
+ fail "$test_name: errno: $value"
+ }
+
+}
diff --git a/systemtest/mcc-execute.tests/exitcodes.exp b/systemtest/mcc-execute.tests/exitcodes.exp
index 6e8b632..48d19a1 100644
--- a/systemtest/mcc-execute.tests/exitcodes.exp
+++ b/systemtest/mcc-execute.tests/exitcodes.exp
@@ -1,18 +1,5 @@
# https://www.embecosm.com/appnotes/ean8/ean8-howto-dejagnu-1.0.html
-spawn systemtest/mcc-execute.tests/test1
-
-expect eof
-
-lassign [wait] pid spawnid os_error_flag value
-
-if {$os_error_flag == 0} {
- if {$value == 3} {
- pass "exit status: $value"
- } else {
- fail "exit status: $value"
- }
-} else {
- fail "errno: $value"
-}
+runtest_exit_code "Return 1" "systemtest/mcc-execute.tests/test-return-1" 1
+runtest_exit_code "Addition" "systemtest/mcc-execute.tests/test-addition" 3
diff --git a/systemtest/mcc-execute.tests/test1.cpp b/systemtest/mcc-execute.tests/test-addition.cpp
index 3a03f6f..3a03f6f 100644
--- a/systemtest/mcc-execute.tests/test1.cpp
+++ b/systemtest/mcc-execute.tests/test-addition.cpp
diff --git a/systemtest/mcc-execute.tests/test.cpp b/systemtest/mcc-execute.tests/test-return-1.cpp
index 40cbb54..40cbb54 100644
--- a/systemtest/mcc-execute.tests/test.cpp
+++ b/systemtest/mcc-execute.tests/test-return-1.cpp
diff --git a/tests/test-cpp.cpp b/tests/test-cpp.cpp
index 39e1513..5755516 100644
--- a/tests/test-cpp.cpp
+++ b/tests/test-cpp.cpp
@@ -86,6 +86,12 @@ TEST_F(CppTest, compile) {
cpp.compile("int main() { return 1 + 2; }");
}
+TEST_F(CppTest, compile_1) {
+ CPP cpp;
+
+ cpp.compile("int main() { return 1; }");
+}
+
TEST_F(CppTest, compile_2_times) {
CPP cpp;
diff --git a/tests/test-flowgraph.cpp b/tests/test-flowgraph.cpp
index f0cc204..021d6dd 100644
--- a/tests/test-flowgraph.cpp
+++ b/tests/test-flowgraph.cpp
@@ -40,12 +40,18 @@ protected:
TEST_F(FlowGraphTest, build_graph) {
Graph graph;
- Data pointer{ MakeLocalPointer("malloc1") };
- Data size{ MakeLocalSize("size1") };
- std::shared_ptr<Node> malloc1 {std::make_shared<AllocateDynamic>(pointer, size) };
- std::shared_ptr<Node> free1{ std::make_shared<DeallocateDynamic>(pointer) };
+ std::shared_ptr<CreateScopeOp> createScope{std::make_shared<CreateScopeOp>()};
+ graph.push_back(createScope);
+ Data pointer{ MakeLocalPointer(createScope->scope(), "malloc1") };
+ Data size{ MakeLocalSize(createScope->scope(), "size1") };
+ std::shared_ptr<Node> malloc1 {std::make_shared<AllocateDynamic>(pointer, size) };
graph.push_back(malloc1);
+
+ std::shared_ptr<Node> free1{ std::make_shared<DeallocateDynamic>(pointer) };
graph.push_back(free1);
+
+ std::shared_ptr<Node> destroyScope{std::make_shared<DestroyScopeOp>()};
+ graph.push_back(destroyScope);
}