summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-11-18 17:55:27 +0100
committerRoland Reichwein <mail@reichwein.it>2020-11-18 17:55:27 +0100
commit031bfef600e7021c8bd72e2e663f368e7386b131 (patch)
tree4e724c3b13278e5c6fb90a9380d19dc1d253b4b3
parent927eb99e75325164a541c2638e1e607294019381 (diff)
Added Asm ops
-rw-r--r--Makefile13
-rw-r--r--TODO4
-rw-r--r--asm/assembler.h16
-rw-r--r--asm/intel64/all_ops.h12
-rw-r--r--asm/intel64/and.cpp84
-rw-r--r--asm/intel64/and.h31
-rw-r--r--asm/intel64/bsf.cpp47
-rw-r--r--asm/intel64/bsf.h31
-rw-r--r--asm/intel64/bsr.cpp47
-rw-r--r--asm/intel64/bsr.h31
-rw-r--r--asm/intel64/encode.cpp45
-rw-r--r--asm/intel64/neg.cpp59
-rw-r--r--asm/intel64/neg.h31
-rw-r--r--asm/intel64/not.cpp59
-rw-r--r--asm/intel64/not.h31
-rw-r--r--asm/intel64/rcl.cpp61
-rw-r--r--asm/intel64/rcl.h31
-rw-r--r--asm/intel64/rcr.cpp61
-rw-r--r--asm/intel64/rcr.h31
-rw-r--r--asm/intel64/rol.cpp61
-rw-r--r--asm/intel64/rol.h31
-rw-r--r--asm/intel64/ror.cpp61
-rw-r--r--asm/intel64/ror.h31
-rw-r--r--asm/intel64/sal_shl.cpp79
-rw-r--r--asm/intel64/sal_shl.h31
-rw-r--r--asm/intel64/sar.cpp61
-rw-r--r--asm/intel64/sar.h31
-rw-r--r--asm/intel64/shr.cpp61
-rw-r--r--asm/intel64/shr.h31
-rw-r--r--asm/intel64/trivials.cpp12
-rw-r--r--asm/intel64/trivials.h5
-rw-r--r--asm/parse.cpp8
-rw-r--r--asm/parse.h8
-rw-r--r--flowgraph/node.h6
34 files changed, 1213 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 1ef9a12..c2d1850 100644
--- a/Makefile
+++ b/Makefile
@@ -48,6 +48,9 @@ PROGSRC=\
asm/assembler.cpp \
asm/chunk.cpp \
asm/intel64/add.cpp \
+ asm/intel64/and.cpp \
+ asm/intel64/bsf.cpp \
+ asm/intel64/bsr.cpp \
asm/intel64/dec.cpp \
asm/intel64/div.cpp \
asm/intel64/idiv.cpp \
@@ -57,14 +60,24 @@ PROGSRC=\
asm/intel64/jmp.cpp \
asm/intel64/mov.cpp \
asm/intel64/mul.cpp \
+ asm/intel64/neg.cpp \
+ asm/intel64/not.cpp \
asm/intel64/pop.cpp \
asm/intel64/push.cpp \
+ asm/intel64/rcl.cpp \
+ asm/intel64/rcr.cpp \
+ asm/intel64/rol.cpp \
+ asm/intel64/ror.cpp \
+ asm/intel64/sal_shl.cpp \
+ asm/intel64/sar.cpp \
+ asm/intel64/shr.cpp \
asm/intel64/sub.cpp \
asm/intel64/trivials.cpp \
asm/intel64/xor.cpp \
asm/intel64/codes.cpp \
asm/intel64/encode.cpp \
asm/operators.cpp \
+ asm/parse.cpp \
asm/segment.cpp \
bnf.cpp \
cpp.cpp \
diff --git a/TODO b/TODO
index 0607485..3c8bc93 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
-Fix stack
encode.cpp: UnaryOperation
asm parser
-ICE class
+
+Fix stack
grammer.cpp: match() : return point of match error ("Compile error")
diff --git a/asm/assembler.h b/asm/assembler.h
index e719ea4..ea23fbc 100644
--- a/asm/assembler.h
+++ b/asm/assembler.h
@@ -95,6 +95,22 @@ public:
std::string m_name;
};
+ // 64 bit Ptr to 8 bit Memory
+ class Mem8Ptr64
+ {
+ public:
+ Mem8Ptr64(const std::string& reg, int32_t offs = 0): m_reg(reg), m_offs(offs) {}
+ Mem8Ptr64(const std::string& reg, const std::string& reg2 = ""s, int32_t offs = 0): m_reg(reg), m_reg2(reg2), m_offs(offs) {}
+ std::string reg() { return m_reg; }
+ std::string reg2() { return m_reg2; }
+ int32_t offs() { return m_offs; }
+
+ private:
+ std::string m_reg;
+ std::string m_reg2;
+ int32_t m_offs;
+ };
+
// 64 bit Ptr to 32 bit Memory
class Mem32Ptr64
{
diff --git a/asm/intel64/all_ops.h b/asm/intel64/all_ops.h
index 779506d..4da0a0b 100644
--- a/asm/intel64/all_ops.h
+++ b/asm/intel64/all_ops.h
@@ -1,6 +1,9 @@
#pragma once
#include "add.h"
+#include "and.h"
+#include "bsf.h"
+#include "bsr.h"
#include "dec.h"
#include "div.h"
#include "idiv.h"
@@ -8,10 +11,19 @@
#include "inc.h"
#include "int.h"
#include "jmp.h"
+#include "neg.h"
+#include "not.h"
#include "mov.h"
#include "mul.h"
#include "pop.h"
#include "push.h"
+#include "rcl.h"
+#include "rcr.h"
+#include "rol.h"
+#include "ror.h"
+#include "sal_shl.h"
+#include "sar.h"
+#include "shr.h"
#include "sub.h"
#include "trivials.h"
#include "xor.h"
diff --git a/asm/intel64/and.cpp b/asm/intel64/and.cpp
new file mode 100644
index 0000000..a2e110b
--- /dev/null
+++ b/asm/intel64/and.cpp
@@ -0,0 +1,84 @@
+#include "and.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+#include <asm/intel64/codes.h>
+
+using namespace std::string_literals;
+
+Op_and::Op_and(const Asm::Args& args)
+{
+ if (args[0].type() == typeid(Asm::Args::Register8) && args[1].type() == typeid(Asm::Args::Register8)) { // and reg8, reg8
+ // r/m8, r8: ModRM:r/m (w), ModRM:reg (r)
+ machine_code = std::vector<uint8_t>{ 0x20 } +
+ ModRM(std::any_cast<Asm::Args::Register8>(args[1]).name(), std::any_cast<Asm::Args::Register8>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Register32)) { // and reg32, reg32
+ // r/m32, r32: ModRM:r/m (w), ModRM:reg (r)
+ machine_code = std::vector<uint8_t>{ 0x21 } +
+ ModRM(std::any_cast<Asm::Args::Register32>(args[1]).name(), std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Register64)) { // and reg64, reg64
+ // r/m64, r64: ModRM:r/m (w), ModRM:reg (r)
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x21 } +
+ ModRM(std::any_cast<Asm::Args::Register64>(args[1]).name(), std::any_cast<Asm::Args::Register64>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Immediate32)) { // and reg32, imm32
+ machine_code = std::vector<uint8_t>{ 0x81 } + ModRM("/4", std::any_cast<Asm::Args::Register32>(args[0]).name()) + std::any_cast<Asm::Args::Immediate32>(args[1]).getCode();
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Mem32Ptr64)) { // and reg32, [reg64]
+ machine_code = std::vector<uint8_t>{ 0x23 } + ModRM(std::any_cast<Asm::Args::Register32>(args[0]).name(), std::any_cast<Asm::Args::Mem32Ptr64>(args[1]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Mem64Ptr64)) { // and reg64, [reg64]
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x23 } + ModRM(std::any_cast<Asm::Args::Register64>(args[0]).name(), std::any_cast<Asm::Args::Mem64Ptr64>(args[1]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem32Ptr64) && args[1].type() == typeid(Asm::Args::Register32)) { // and [reg64], reg32
+ machine_code = std::vector<uint8_t>{ 0x21 } + ModRM(std::any_cast<Asm::Args::Register32>(args[1]).name(), std::any_cast<Asm::Args::Mem32Ptr64>(args[0]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem64Ptr64) && args[1].type() == typeid(Asm::Args::Register64)) { // and [reg64], reg64
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x21 } + ModRM(std::any_cast<Asm::Args::Register64>(args[1]).name(), std::any_cast<Asm::Args::Mem64Ptr64>(args[0]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Immediate32)) { // and reg64, imm32 (sign-extended)
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x81 } + ModRM("/4", std::any_cast<Asm::Args::Register64>(args[0]).name()) + std::any_cast<Asm::Args::Immediate32>(args[1]).getCode();
+
+ } else {
+ throw std::runtime_error("Unimplemented: and "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Register8>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Register32>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Register64>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate32>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Mem32Ptr64>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Register32>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Mem64Ptr64>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Register64>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate32>("and"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_and>(args);
+ })
+};
+
+}
diff --git a/asm/intel64/and.h b/asm/intel64/and.h
new file mode 100644
index 0000000..f488730
--- /dev/null
+++ b/asm/intel64/and.h
@@ -0,0 +1,31 @@
+// AND
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_and: public Op
+{
+public:
+ Op_and(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/bsf.cpp b/asm/intel64/bsf.cpp
new file mode 100644
index 0000000..974be43
--- /dev/null
+++ b/asm/intel64/bsf.cpp
@@ -0,0 +1,47 @@
+#include "bsf.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_bsf::Op_bsf(const Asm::Args& args)
+{
+ if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Register32)) { // bsf reg32, reg32
+ machine_code = std::vector<uint8_t>{ 0x0F, 0xBC } + ModRM(std::any_cast<Asm::Args::Register32>(args[0]).name(), std::any_cast<Asm::Args::Register32>(args[1]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Register64)) { // bsf reg64, reg64
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x0F, 0xBC } + ModRM(std::any_cast<Asm::Args::Register64>(args[0]).name(), std::any_cast<Asm::Args::Register64>(args[1]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Mem32Ptr64)) { // bsf reg32, [reg64]
+ machine_code = std::vector<uint8_t>{ 0x0F, 0xBC } + ModRM(std::any_cast<Asm::Args::Register32>(args[0]).name(), std::any_cast<Asm::Args::Mem32Ptr64>(args[1]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Mem64Ptr64)) { // bsf reg64, [reg64]
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x0F, 0xBC } + ModRM(std::any_cast<Asm::Args::Register64>(args[0]).name(), std::any_cast<Asm::Args::Mem64Ptr64>(args[1]).reg());
+
+ } else {
+ throw std::runtime_error("Unimplemented: bsf "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Register32>("bsf"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsf>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Register64>("bsf"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsf>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Mem32Ptr64>("bsf"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsf>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Mem64Ptr64>("bsf"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsf>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/bsf.h b/asm/intel64/bsf.h
new file mode 100644
index 0000000..699c093
--- /dev/null
+++ b/asm/intel64/bsf.h
@@ -0,0 +1,31 @@
+// Bit Scan Forward
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_bsf: public Op
+{
+public:
+ Op_bsf(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/bsr.cpp b/asm/intel64/bsr.cpp
new file mode 100644
index 0000000..099c7d2
--- /dev/null
+++ b/asm/intel64/bsr.cpp
@@ -0,0 +1,47 @@
+#include "bsr.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_bsr::Op_bsr(const Asm::Args& args)
+{
+ if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Register32)) { // bsr reg32, reg32
+ machine_code = std::vector<uint8_t>{ 0x0F, 0xBD } + ModRM(std::any_cast<Asm::Args::Register32>(args[0]).name(), std::any_cast<Asm::Args::Register32>(args[1]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Register64)) { // bsr reg64, reg64
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x0F, 0xBD } + ModRM(std::any_cast<Asm::Args::Register64>(args[0]).name(), std::any_cast<Asm::Args::Register64>(args[1]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32) && args[1].type() == typeid(Asm::Args::Mem32Ptr64)) { // bsr reg32, [reg64]
+ machine_code = std::vector<uint8_t>{ 0x0F, 0xBD } + ModRM(std::any_cast<Asm::Args::Register32>(args[0]).name(), std::any_cast<Asm::Args::Mem32Ptr64>(args[1]).reg());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64) && args[1].type() == typeid(Asm::Args::Mem64Ptr64)) { // bsr reg64, [reg64]
+ machine_code = REX("W") + std::vector<uint8_t>{ 0x0F, 0xBD } + ModRM(std::any_cast<Asm::Args::Register64>(args[0]).name(), std::any_cast<Asm::Args::Mem64Ptr64>(args[1]).reg());
+
+ } else {
+ throw std::runtime_error("Unimplemented: bsr "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Register32>("bsr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Register64>("bsr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Mem32Ptr64>("bsr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Mem64Ptr64>("bsr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_bsr>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/bsr.h b/asm/intel64/bsr.h
new file mode 100644
index 0000000..423a6bf
--- /dev/null
+++ b/asm/intel64/bsr.h
@@ -0,0 +1,31 @@
+// Bit Scan Reverse
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_bsr: public Op
+{
+public:
+ Op_bsr(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/encode.cpp b/asm/intel64/encode.cpp
index 4648194..21b6629 100644
--- a/asm/intel64/encode.cpp
+++ b/asm/intel64/encode.cpp
@@ -2,6 +2,7 @@
#include "encode.h"
#include "asm/assembler.h"
+#include "asm/parse.h"
#include "minicc.h"
#include <boost/endian/conversion.hpp>
@@ -123,31 +124,28 @@ void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment)
if (node.get()) {
auto& node_deref = *node.get();
if (typeid(node_deref) == typeid(FlowGraph::UnaryOperation)) {
- // TODO:
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));
+ if (operands.size() != 2)
+ throw std::runtime_error("ICE: Bad number of operands for UnaryOperation: "s + std::to_string(operands.size()));
+
+ if (op.type() == FlowGraph::UnaryOperationType::BitwiseNot) {
+ segment.push_back(makeLoadValue(operands[1], graph));
+ segment.push_back(parseAsm("not eax"));
+ segment.push_back(makeStoreValue(operands[0], graph));
+ } else if (op.type() == FlowGraph::UnaryOperationType::LogicalNot) {
+ segment.push_back(makeLoadValue(operands[1], graph));
+ segment.push_back(parseAsm("bsr eax")); // ZF=1 iff eax=0
+ segment.push_back(parseAsm("lahf")); // ZF in AH bit 6
+ segment.push_back(parseAsm("shr eax, 14")); // ZF in eax bit 0
+ segment.push_back(parseAsm("and eax, 1")); // now, 0 or 1 is in eax, negated because of zero flag
+ segment.push_back(makeStoreValue(operands[0], graph));
+ } else if (op.type() == FlowGraph::UnaryOperationType::Minus) {
+ segment.push_back(makeLoadValue(operands[1], graph));
+ segment.push_back(parseAsm("neg eax"));
+ segment.push_back(makeStoreValue(operands[0], graph));
} else
throw std::runtime_error("ICE: Asm: Unsupported unary operation type: "s + std::to_string(static_cast<int>(op.type())));
@@ -156,6 +154,9 @@ void Asm::toMachineCode(const FlowGraph::Graph& graph, Segment& segment)
auto operands {op.operands()};
+ if (operands.size() != 3)
+ throw std::runtime_error("ICE: Bad number of operands for BinaryOperation: "s + std::to_string(operands.size()));
+
if (op.type() == FlowGraph::BinaryOperationType::Add) {
segment.push_back(makeLoadValue(operands[1], graph));
segment.push_back(makeAddValue(operands[2], graph));
diff --git a/asm/intel64/neg.cpp b/asm/intel64/neg.cpp
new file mode 100644
index 0000000..121a54f
--- /dev/null
+++ b/asm/intel64/neg.cpp
@@ -0,0 +1,59 @@
+#include "neg.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_neg::Op_neg(const Asm::Args& args)
+{
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // neg reg8
+ machine_code = std::vector<uint8_t>{ 0xF6 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // neg reg32
+ machine_code = std::vector<uint8_t>{ 0xF7 } + ModRM("/3", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // neg reg64
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xF7 } + ModRM("/3", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem8Ptr64)) { // neg byte ptr [reg64]
+ machine_code = std::vector<uint8_t>{ 0xF6 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem32Ptr64)) { // neg dword ptr [reg64]
+ machine_code = std::vector<uint8_t>{ 0xF7 } + ModRM("/3", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem64Ptr64)) { // neg qword ptr [reg64]
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xF7 } + ModRM("/3", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else {
+ throw std::runtime_error("Unimplemented: neg "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64>("neg"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_neg>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/neg.h b/asm/intel64/neg.h
new file mode 100644
index 0000000..226b632
--- /dev/null
+++ b/asm/intel64/neg.h
@@ -0,0 +1,31 @@
+// Two's Complement Negation
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_neg: public Op
+{
+public:
+ Op_neg(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/not.cpp b/asm/intel64/not.cpp
new file mode 100644
index 0000000..58604f4
--- /dev/null
+++ b/asm/intel64/not.cpp
@@ -0,0 +1,59 @@
+#include "not.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_not::Op_not(const Asm::Args& args)
+{
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // not reg8
+ machine_code = std::vector<uint8_t>{ 0xF6 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // not reg32
+ machine_code = std::vector<uint8_t>{ 0xF7 } + ModRM("/2", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // not reg64
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xF7 } + ModRM("/2", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem8Ptr64)) { // not byte ptr [reg64]
+ machine_code = std::vector<uint8_t>{ 0xF6 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem32Ptr64)) { // not dword ptr [reg64]
+ machine_code = std::vector<uint8_t>{ 0xF7 } + ModRM("/2", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else if (args[0].type() == typeid(Asm::Args::Mem64Ptr64)) { // not qword ptr [reg64]
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xF7 } + ModRM("/2", std::any_cast<Asm::Args::Register32>(args[0]).name());
+
+ } else {
+ throw std::runtime_error("Unimplemented: not "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64>("not"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_not>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/not.h b/asm/intel64/not.h
new file mode 100644
index 0000000..105daf8
--- /dev/null
+++ b/asm/intel64/not.h
@@ -0,0 +1,31 @@
+// One's Complement Negation
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_not: public Op
+{
+public:
+ Op_not(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/rcl.cpp b/asm/intel64/rcl.cpp
new file mode 100644
index 0000000..038f3d3
--- /dev/null
+++ b/asm/intel64/rcl.cpp
@@ -0,0 +1,61 @@
+#include "rcl.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_rcl::Op_rcl(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rcl reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rcl reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rcl reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rcl reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rcl reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rcl reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/2", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: rcl "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("rcl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcl>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/rcl.h b/asm/intel64/rcl.h
new file mode 100644
index 0000000..f530ff1
--- /dev/null
+++ b/asm/intel64/rcl.h
@@ -0,0 +1,31 @@
+// Rotate Through Carry Left
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_rcl: public Op
+{
+public:
+ Op_rcl(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/rcr.cpp b/asm/intel64/rcr.cpp
new file mode 100644
index 0000000..27b688c
--- /dev/null
+++ b/asm/intel64/rcr.cpp
@@ -0,0 +1,61 @@
+#include "rcr.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_rcr::Op_rcr(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rcr reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rcr reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rcr reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rcr reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rcr reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rcr reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/3", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: rcr "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("rcr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rcr>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/rcr.h b/asm/intel64/rcr.h
new file mode 100644
index 0000000..ab0bf57
--- /dev/null
+++ b/asm/intel64/rcr.h
@@ -0,0 +1,31 @@
+// Rotate Throught Carry Right
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_rcr: public Op
+{
+public:
+ Op_rcr(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/rol.cpp b/asm/intel64/rol.cpp
new file mode 100644
index 0000000..98d69d9
--- /dev/null
+++ b/asm/intel64/rol.cpp
@@ -0,0 +1,61 @@
+#include "rol.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_rol::Op_rol(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rol reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rol reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rol reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // rol reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // rol reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // rol reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/0", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: rol "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("rol"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_rol>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/rol.h b/asm/intel64/rol.h
new file mode 100644
index 0000000..ae1a0b7
--- /dev/null
+++ b/asm/intel64/rol.h
@@ -0,0 +1,31 @@
+// Rotate Left
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_rol: public Op
+{
+public:
+ Op_rol(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/ror.cpp b/asm/intel64/ror.cpp
new file mode 100644
index 0000000..70a7a6b
--- /dev/null
+++ b/asm/intel64/ror.cpp
@@ -0,0 +1,61 @@
+#include "ror.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_ror::Op_ror(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // ror reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // ror reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // ror reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // ror reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // ror reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // ror reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/1", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: ror "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("ror"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ror>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/ror.h b/asm/intel64/ror.h
new file mode 100644
index 0000000..d33c49a
--- /dev/null
+++ b/asm/intel64/ror.h
@@ -0,0 +1,31 @@
+// Rotate Right
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_ror: public Op
+{
+public:
+ Op_ror(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/sal_shl.cpp b/asm/intel64/sal_shl.cpp
new file mode 100644
index 0000000..c822666
--- /dev/null
+++ b/asm/intel64/sal_shl.cpp
@@ -0,0 +1,79 @@
+#include "sal_shl.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_sal::Op_sal(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // sal reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // sal reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // sal reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // sal reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // sal reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // sal reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/4", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: sal(shl) "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("sal"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("shl"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sal>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/sal_shl.h b/asm/intel64/sal_shl.h
new file mode 100644
index 0000000..e7a44b2
--- /dev/null
+++ b/asm/intel64/sal_shl.h
@@ -0,0 +1,31 @@
+// Shift Left
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_sal: public Op
+{
+public:
+ Op_sal(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/sar.cpp b/asm/intel64/sar.cpp
new file mode 100644
index 0000000..fccd738
--- /dev/null
+++ b/asm/intel64/sar.cpp
@@ -0,0 +1,61 @@
+#include "sar.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_sar::Op_sar(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // sar reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // sar reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // sar reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // sar reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // sar reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // sar reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/7", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: sar "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("sar"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_sar>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/sar.h b/asm/intel64/sar.h
new file mode 100644
index 0000000..531532d
--- /dev/null
+++ b/asm/intel64/sar.h
@@ -0,0 +1,31 @@
+// Shift Arithmetic Right
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_sar: public Op
+{
+public:
+ Op_sar(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/shr.cpp b/asm/intel64/shr.cpp
new file mode 100644
index 0000000..01977b0
--- /dev/null
+++ b/asm/intel64/shr.cpp
@@ -0,0 +1,61 @@
+#include "shr.h"
+
+#include "codes.h"
+
+#include <asm/assembler.h>
+#include <asm/operators.h>
+
+using namespace std::string_literals;
+
+Op_shr::Op_shr(const Asm::Args& args)
+{
+ if (args[1].type() == typeid(Asm::Args::Immediate8)) {
+ std::vector<uint8_t> shift_offset{std::any_cast<Asm::Args::Immediate8>(args[1]).getCode()};
+ if (shift_offset == std::vector<uint8_t>{ 0x01 }) { // 1 bit version is shorter
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // shr reg8, 1
+ machine_code = std::vector<uint8_t>{ 0xD0 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // shr reg32, 1
+ machine_code = std::vector<uint8_t>{ 0xD1 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // shr reg64, 1
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xD1 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name());
+ }
+ } else { // general version >= 2 bits shift
+ if (args[0].type() == typeid(Asm::Args::Register8)) { // shr reg8, imm8
+ machine_code = std::vector<uint8_t>{ 0xC0 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register32)) { // shr reg32, imm8
+ machine_code = std::vector<uint8_t>{ 0xC1 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ } else if (args[0].type() == typeid(Asm::Args::Register64)) { // shr reg64, imm8
+ machine_code = REX("W") + std::vector<uint8_t>{ 0xC1 } + ModRM("/5", std::any_cast<Asm::Args::Register8>(args[0]).name()) + shift_offset;
+ }
+ }
+
+ } else {
+ throw std::runtime_error("Unimplemented: shr "s + args[0].type().name() + " "s + args[1].type().name());
+ }
+}
+
+namespace {
+
+bool registered {
+ registerOp(mangleName<Asm::Args::Register8, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register32, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Register64, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem8Ptr64, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem32Ptr64, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ }) &&
+ registerOp(mangleName<Asm::Args::Mem64Ptr64, Asm::Args::Immediate8>("shr"), [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_shr>(args);
+ })
+};
+
+}
+
diff --git a/asm/intel64/shr.h b/asm/intel64/shr.h
new file mode 100644
index 0000000..be724c9
--- /dev/null
+++ b/asm/intel64/shr.h
@@ -0,0 +1,31 @@
+// Shift Right
+
+#pragma once
+
+#include <asm/assembler.h>
+
+class Op_shr: public Op
+{
+public:
+ Op_shr(const Asm::Args& args);
+
+public:
+ std::vector<uint8_t> getCode() override
+ {
+ return machine_code;
+ }
+
+ size_t size() override
+ {
+ return machine_code.size();
+ }
+
+ bool optimize() override ///< returns true if changed
+ {
+ return false;
+ }
+
+protected:
+ std::vector<uint8_t> machine_code;
+};
+
diff --git a/asm/intel64/trivials.cpp b/asm/intel64/trivials.cpp
index eb1bbb8..ef537b6 100644
--- a/asm/intel64/trivials.cpp
+++ b/asm/intel64/trivials.cpp
@@ -2,13 +2,18 @@
#include <asm/assembler.h>
-Op_nop::Op_nop(): OpSimple({ 0x90 }) {}
+Op_lahf::Op_lahf(): OpSimple({ 0x9F }) {} // Load flags to AH
+Op_nop::Op_nop(): OpSimple({ 0x90 }) {} // No operation
Op_ret::Op_ret(): OpSimple({ 0xC3 }) {} // near return; TODO: far return is 0xCB
-Op_syscall::Op_syscall(): OpSimple({ 0x0F, 0x05 }) {}
+Op_syscall::Op_syscall(): OpSimple({ 0x0F, 0x05 }) {} // Syscall
+Op_ud2::Op_ud2(): OpSimple({ 0x0F, 0x0B }) {} // Undefined Instruction, variant 2: with no operands
namespace {
bool registered {
+ registerOp("lahf", [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_lahf>();
+ }) &&
registerOp("nop", [](const Asm::Args& args) -> std::shared_ptr<Op>{
return std::make_shared<Op_nop>();
}) &&
@@ -17,6 +22,9 @@ bool registered {
}) &&
registerOp("syscall", [](const Asm::Args& args) -> std::shared_ptr<Op>{
return std::make_shared<Op_syscall>();
+ }) &&
+ registerOp("ud2", [](const Asm::Args& args) -> std::shared_ptr<Op>{
+ return std::make_shared<Op_ud2>();
})
};
diff --git a/asm/intel64/trivials.h b/asm/intel64/trivials.h
index 898001e..2ec1b53 100644
--- a/asm/intel64/trivials.h
+++ b/asm/intel64/trivials.h
@@ -4,6 +4,9 @@
#include <asm/chunk.h>
+// Copy Flags to AH
+class Op_lahf: public OpSimple { public: Op_lahf(); };
+
// No Operation
class Op_nop: public OpSimple { public: Op_nop(); };
@@ -13,3 +16,5 @@ class Op_ret: public OpSimple { public: Op_ret(); };
// Syscall
class Op_syscall: public OpSimple { public: Op_syscall(); };
+// Undefined Instruction, variant 2: with no operands
+class Op_ud2: public OpSimple { public: Op_ud2(); };
diff --git a/asm/parse.cpp b/asm/parse.cpp
new file mode 100644
index 0000000..350d86e
--- /dev/null
+++ b/asm/parse.cpp
@@ -0,0 +1,8 @@
+#include "parse.h"
+
+#include "asm/assembler.h"
+
+std::shared_ptr<Chunk> parseAsm(const std::string& line)
+{
+ return makeOp("lahf"); // TODO
+}
diff --git a/asm/parse.h b/asm/parse.h
new file mode 100644
index 0000000..1e6a202
--- /dev/null
+++ b/asm/parse.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "asm/chunk.h"
+
+#include <memory>
+#include <string>
+
+std::shared_ptr<Chunk> parseAsm(const std::string& line);
diff --git a/flowgraph/node.h b/flowgraph/node.h
index 6a3ef14..def3c04 100644
--- a/flowgraph/node.h
+++ b/flowgraph/node.h
@@ -117,9 +117,9 @@ namespace FlowGraph {
enum class UnaryOperationType: int
{
- Increment,
- Decrement,
- Negate,
+ LogicalNot,
+ BitwiseNot,
+ Minus,
};
class UnaryOperation: public Node