|
@@ -5,6 +5,22 @@ using namespace std;
|
|
|
|
|
|
#include <iostream>
|
|
#include <iostream>
|
|
|
|
|
|
|
|
+
|
|
|
|
+#ifdef __APPLE__
|
|
|
|
+const char* LabelNames::main = "_main";
|
|
|
|
+const char* LabelNames::getchar = "_getchar";
|
|
|
|
+const char* LabelNames::putchar = "_putchar";
|
|
|
|
+const char* LabelNames::calloc = "_calloc";
|
|
|
|
+const char* LabelNames::free = "_free";
|
|
|
|
+#else
|
|
|
|
+const char* LabelNames::main = "main";
|
|
|
|
+const char* LabelNames::getchar = "getchar";
|
|
|
|
+const char* LabelNames::putchar = "putchar";
|
|
|
|
+const char* LabelNames::calloc = "calloc";
|
|
|
|
+const char* LabelNames::free = "free";
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+
|
|
const char* AssemblyGenerator::pointerRegister = "rbx";
|
|
const char* AssemblyGenerator::pointerRegister = "rbx";
|
|
const char* AssemblyGenerator::dataRegister = "r12";
|
|
const char* AssemblyGenerator::dataRegister = "r12";
|
|
|
|
|
|
@@ -20,37 +36,39 @@ const char* AssemblyGenerator::argumentRegister2 = "rsi";
|
|
AssemblyGenerator::AssemblyGenerator(std::ostream& out) :
|
|
AssemblyGenerator::AssemblyGenerator(std::ostream& out) :
|
|
out{ out }
|
|
out{ out }
|
|
{
|
|
{
|
|
- out << ".globl main" << endl;
|
|
|
|
- out << "main:" << endl;
|
|
|
|
- out << "subq $40, %rsp" << endl;
|
|
|
|
- out << "movq $131072, %" << argumentRegister1 << endl;
|
|
|
|
- out << "movq $1, %" << argumentRegister2 << endl;
|
|
|
|
- out << "callq calloc" << endl;
|
|
|
|
- out << "addq $65536, %rax" << endl;
|
|
|
|
- out << "movq %rax, %" << dataRegister << endl;
|
|
|
|
- out << "xorq %" << pointerRegister << ", %" << pointerRegister << endl;
|
|
|
|
- out << endl;
|
|
|
|
- out << "# begin of bf-program" << endl;
|
|
|
|
- out << endl;
|
|
|
|
|
|
+ write(".globl ", LabelNames::main);
|
|
|
|
+ write(generateLabel(LabelNames::main));
|
|
|
|
+ write("subq $40, %rsp");
|
|
|
|
+ write("movq $131072, %", argumentRegister1);
|
|
|
|
+ write("movq $1, %", argumentRegister2);
|
|
|
|
+ write("callq ", LabelNames::calloc);
|
|
|
|
+ write("addq $65536, %rax");
|
|
|
|
+ write("movq %rax, %", dataRegister);
|
|
|
|
+ write("xorq %", pointerRegister, ", %", pointerRegister);
|
|
|
|
+ write("movq %", dataRegister, ", %", pointerRegister);
|
|
|
|
+ write();
|
|
|
|
+ write("# begin of bf-program");
|
|
|
|
+ write();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void AssemblyGenerator::finish(void)
|
|
void AssemblyGenerator::finish(void)
|
|
{
|
|
{
|
|
- out << endl;
|
|
|
|
- out << "# end of bf-program" << endl;
|
|
|
|
- out << endl;
|
|
|
|
- out << "movq %" << dataRegister << ", %" << argumentRegister1 << endl;
|
|
|
|
- out << "callq free" << endl;
|
|
|
|
- out << "xorq %rax, %rax" << endl;
|
|
|
|
- out << "addq $40, %rsp" << endl;
|
|
|
|
- out << "retq" << endl;
|
|
|
|
|
|
+ write();
|
|
|
|
+ write("# end of bf-program");
|
|
|
|
+ write();
|
|
|
|
+ write("movq %", dataRegister, ", %", argumentRegister1);
|
|
|
|
+ write("subq $65536, %", argumentRegister1);
|
|
|
|
+ write("callq ", LabelNames::free);
|
|
|
|
+ write("xorq %rax, %rax");
|
|
|
|
+ write("addq $40, %rsp");
|
|
|
|
+ write("retq");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string AssemblyGenerator::generateLabel(void)
|
|
std::string AssemblyGenerator::generateLabel(void)
|
|
{
|
|
{
|
|
- return ".L" + std::to_string(labelcount++);
|
|
|
|
|
|
+ return "L" + std::to_string(labelcount++);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -63,7 +81,8 @@ std::string AssemblyGenerator::generateOffset(const std::string& offset,
|
|
|
|
|
|
std::string AssemblyGenerator::ptr(void)
|
|
std::string AssemblyGenerator::ptr(void)
|
|
{
|
|
{
|
|
- return generateOffset("%"s + pointerRegister, "%"s + dataRegister);
|
|
|
|
|
|
+ //return generateOffset("%"s + pointerRegister, "%"s + dataRegister);
|
|
|
|
+ return "(%"s + pointerRegister + ")";
|
|
}
|
|
}
|
|
|
|
|
|
void AssemblyGenerator::visitBlockInstruction(const BlockInstruction&)
|
|
void AssemblyGenerator::visitBlockInstruction(const BlockInstruction&)
|
|
@@ -82,13 +101,13 @@ void AssemblyGenerator::visitUnionBlockInstruction(const UnionBlockInstruction&
|
|
void AssemblyGenerator::visitIOInstruction(const IOInstruction& ioi)
|
|
void AssemblyGenerator::visitIOInstruction(const IOInstruction& ioi)
|
|
{
|
|
{
|
|
if (ioi.isRead) {
|
|
if (ioi.isRead) {
|
|
- out << "callq getchar" << endl;
|
|
|
|
- out << "movb %al, " << ptr() << endl;
|
|
|
|
|
|
+ write("callq ", LabelNames::getchar);
|
|
|
|
+ write("movb %al, ", ptr());
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- out << "movq " << ptr() << ", %" << argumentRegister1 << endl;
|
|
|
|
- out << "andq $255, %" << argumentRegister1 << endl;
|
|
|
|
- out << "callq putchar" << endl;
|
|
|
|
|
|
+ write("movq ", ptr(), ", %", argumentRegister1);
|
|
|
|
+ write("andq $255, %", argumentRegister1);
|
|
|
|
+ write("callq ", LabelNames::putchar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -96,18 +115,26 @@ void AssemblyGenerator::visitIOInstruction(const IOInstruction& ioi)
|
|
void AssemblyGenerator::visitSimpleBlockInstruction(const SimpleBlockInstruction& sbi)
|
|
void AssemblyGenerator::visitSimpleBlockInstruction(const SimpleBlockInstruction& sbi)
|
|
{
|
|
{
|
|
for (const auto [index, value] : sbi.added) {
|
|
for (const auto [index, value] : sbi.added) {
|
|
- out << "addb $" << int(value) << ", " << index <<
|
|
|
|
- ptr() << endl;
|
|
|
|
|
|
+ write("addb $", int(value), ", ", index,
|
|
|
|
+ ptr());
|
|
}
|
|
}
|
|
if (sbi.pointerMoved != 0)
|
|
if (sbi.pointerMoved != 0)
|
|
- out << "addq $" << sbi.pointerMoved << ", %" << pointerRegister << endl;
|
|
|
|
- //out << "andq $65535, %" << pointerRegister << endl;
|
|
|
|
|
|
+ write("addq $", sbi.pointerMoved, ", %", pointerRegister);
|
|
|
|
+ //write("andq $65535, %", pointerRegister);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void AssemblyGenerator::visitLinearLoopInstruction(const LinearLoopInstruction& lli)
|
|
void AssemblyGenerator::visitLinearLoopInstruction(const LinearLoopInstruction& lli)
|
|
{
|
|
{
|
|
-
|
|
|
|
|
|
+ if (lli.increment == 255) {
|
|
|
|
+ if (!lli.factors.empty())
|
|
|
|
+ write("movzbl ", ptr(), ", %eax");
|
|
|
|
+ for (const auto [index, value] : lli.factors) {
|
|
|
|
+ compileMult(index, value);
|
|
|
|
+ }
|
|
|
|
+ write("movb $0, ", ptr());
|
|
|
|
+ }
|
|
|
|
+ else throw "very fatal error";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -115,11 +142,55 @@ void AssemblyGenerator::visitLoopInstruction(const LoopInstruction& li)
|
|
{
|
|
{
|
|
std::string label1 = generateLabel();
|
|
std::string label1 = generateLabel();
|
|
std::string label2 = generateLabel();
|
|
std::string label2 = generateLabel();
|
|
- out << label1 << ":" << endl;
|
|
|
|
- out << "movb " << ptr() << ", %al" << endl;
|
|
|
|
- out << "testb %al, %al" << endl;
|
|
|
|
- out << "jz " << label2 << endl;
|
|
|
|
|
|
+ write(label1, ":");
|
|
|
|
+ write("movb ", ptr(), ", %al");
|
|
|
|
+ write("testb %al, %al");
|
|
|
|
+ write("jz ", label2);
|
|
visitUnionBlockInstruction(li);
|
|
visitUnionBlockInstruction(li);
|
|
- out << "jmp " << label1 << endl;
|
|
|
|
- out << label2 << ":" << endl;
|
|
|
|
|
|
+ write("jmp ", label1);
|
|
|
|
+ write(label2, ":");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+// doesn't modify the contetn of eax
|
|
|
|
+void AssemblyGenerator::compileMult(Index index, Cell factor)
|
|
|
|
+{
|
|
|
|
+ // don't have to do anything on zero mult
|
|
|
|
+ if (factor == 0) return;
|
|
|
|
+
|
|
|
|
+ // just add
|
|
|
|
+ if (factor == 1) {
|
|
|
|
+ write("addb %al, ", index, ptr());
|
|
|
|
+ }
|
|
|
|
+ else if (factor == 255) {
|
|
|
|
+ write("subb %al, ", index, ptr());
|
|
|
|
+ }
|
|
|
|
+ // check if factor is power of two
|
|
|
|
+ else if ((factor & (factor - 1)) == 0) {
|
|
|
|
+ if (factor <= 8) {
|
|
|
|
+ write("leal (,%eax,", int(factor), "), %ecx");
|
|
|
|
+ write("addb %cl, ", index, ptr());
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ int tz = trailingZeroes(factor);
|
|
|
|
+ write("movl %eax, %ecx");
|
|
|
|
+ write("shl $", tz, ", %ecx");
|
|
|
|
+ write("addb %cl, ", index, ptr());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ write("imull $", int(factor), ", %eax, %ecx");
|
|
|
|
+ write("addb %cl, ", index, ptr());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+int AssemblyGenerator::trailingZeroes(unsigned long long x) {
|
|
|
|
+#if __GNUC__ > 4 && 0
|
|
|
|
+ return __builtin_ctzll(x);
|
|
|
|
+#else
|
|
|
|
+ for (int i = 0; i < 64; i++)
|
|
|
|
+ if (x & (1ULL << i))
|
|
|
|
+ return i;
|
|
|
|
+ return 0;
|
|
|
|
+#endif
|
|
|
|
+}
|