summaryrefslogtreecommitdiffhomepage
path: root/asm/intel64/encode.cpp
blob: b26bf9c04893ac10a790b57e567bfe0370641b13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Intel specific conversion: Abstract Graph -> Machine specific segment
#include "encode.h"

#include "asm/assembler.h"
#include "minicc.h"

#include <boost/endian/conversion.hpp>

#include <exception>

void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment)
{
 segment.clear();

 for (const std::shared_ptr<FlowGraph::Node>& node: graph) {
  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");
   }
  } else {
   throw std::runtime_error("ICE: encode: flowgraph node is null");
  }
 }
}