summaryrefslogtreecommitdiffhomepage
path: root/asm/intel64/encode.cpp
blob: 702efaffd0821f56d964b3860e8a2b5dfc77f453 (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
// 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) {
  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");
   }

   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());
  }
 }
}