diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | asm/intel64/encode.cpp | 141 | ||||
-rw-r--r-- | cpp.cpp | 22 | ||||
-rw-r--r-- | flowgraph/node.cpp | 13 | ||||
-rw-r--r-- | flowgraph/node.h | 24 | ||||
-rw-r--r-- | flowgraph/storage.h | 18 | ||||
-rw-r--r-- | systemtest/config/unix.exp | 19 | ||||
-rw-r--r-- | systemtest/mcc-execute.tests/exitcodes.exp | 17 | ||||
-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.cpp | 6 | ||||
-rw-r--r-- | tests/test-flowgraph.cpp | 14 |
12 files changed, 186 insertions, 99 deletions
@@ -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"); } } } @@ -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); } |