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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
// 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::Negate) {
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()};
#if 0
if (op.type() == FlowGraph::BinaryOperationType::Add) {
segment.push_back(loadmakeOp("add", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Immediate32(immediate2)}}));
} else if (op.type() == FlowGraph::BinaryOperationType::Multiply) {
segment.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("ebx"), Asm::Args::Immediate32(immediate2)}}));
segment.push_back(makeOp("mul", Asm::Args{{Asm::Args::Register32("ebx")}}));
} else
throw std::runtime_error("ICE: Asm: Unsupported binary operation type: "s + std::to_string(static_cast<int>(op.type())));
#endif
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");
}
segment.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Immediate32(immediate1)}}));
if (op.type() == FlowGraph::BinaryOperationType::Add) {
segment.push_back(makeOp("add", Asm::Args{{Asm::Args::Register32("eax"), Asm::Args::Immediate32(immediate2)}}));
} else if (op.type() == FlowGraph::BinaryOperationType::Multiply) {
segment.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("ebx"), Asm::Args::Immediate32(immediate2)}}));
segment.push_back(makeOp("mul", Asm::Args{{Asm::Args::Register32("ebx")}}));
} else
throw std::runtime_error("ICE: Asm: Unsupported binary operation type: "s + std::to_string(static_cast<int>(op.type())));
} else if (typeid(node_deref) == typeid(FlowGraph::CreateScopeOp)) {
//FlowGraph::CreateScopeOp& op {dynamic_cast<FlowGraph::CreateScopeOp&>(*node)};
segment.push_back(makeOp("push", Asm::Args{{Asm::Args::Register64("rbp")}}));
segment.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register64("rbp"), Asm::Args::Register64("rsp")}}));
} else if (typeid(node_deref) == typeid(FlowGraph::DestroyScopeOp)) {
//FlowGraph::DestroyScopeOp& op {dynamic_cast<FlowGraph::DestroyScopeOp&>(*node)};
segment.push_back(makeOp("pop", Asm::Args{{Asm::Args::Register64("rbp")}}));
// Move eax for exit() via rdi
segment.push_back(makeOp("xor", Asm::Args{{Asm::Args::Register64("rdi"), Asm::Args::Register64("rdi")}}));
segment.push_back(makeOp("mov", Asm::Args{{Asm::Args::Register32("edi"), Asm::Args::Register32("eax")}}));
} else if (typeid(node_deref) == typeid(FlowGraph::DataNode)) {
// ignore: Immediate data is used in subsequent nodes
} else {
throw std::runtime_error("ICE: Encoding: Unsupported node: "s + demangle(typeid(node_deref)));
}
} else {
throw std::runtime_error("ICE: encode: flowgraph node is null");
}
}
}
|