nicolaswinkler 7 éve
szülő
commit
16681efb0a
5 módosított fájl, 155 hozzáadás és 46 törlés
  1. 109 38
      src/AssemblyGenerator.cpp
  2. 19 3
      src/AssemblyGenerator.h
  3. 18 3
      src/Optimizer.cpp
  4. 3 0
      src/Optimizer.h
  5. 6 2
      src/main.cpp

+ 109 - 38
src/AssemblyGenerator.cpp

@@ -5,6 +5,22 @@ using namespace std;
 
 #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::dataRegister = "r12";
 
@@ -20,37 +36,39 @@ const char* AssemblyGenerator::argumentRegister2 = "rsi";
 AssemblyGenerator::AssemblyGenerator(std::ostream& 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)
 {
-    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)
 {
-    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)
 {
-    return generateOffset("%"s + pointerRegister, "%"s + dataRegister);
+    //return generateOffset("%"s + pointerRegister, "%"s + dataRegister);
+    return "(%"s + pointerRegister + ")";
 }
 
 void AssemblyGenerator::visitBlockInstruction(const BlockInstruction&)
@@ -82,13 +101,13 @@ void AssemblyGenerator::visitUnionBlockInstruction(const UnionBlockInstruction&
 void AssemblyGenerator::visitIOInstruction(const IOInstruction& ioi)
 {
     if (ioi.isRead) {
-        out << "callq getchar" << endl;
-        out << "movb %al, " << ptr() << endl;
+        write("callq ", LabelNames::getchar);
+        write("movb %al, ", ptr());
     }
     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)
 {
     for (const auto [index, value] : sbi.added) {
-        out << "addb $" << int(value) << ", " << index <<
-            ptr() << endl;
+        write("addb $", int(value), ", ", index,
+            ptr());
     }
     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)
 {
-
+    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 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);
-    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
+}

+ 19 - 3
src/AssemblyGenerator.h

@@ -7,11 +7,10 @@
 
 namespace zp
 {
-    class X64AssemblyHolder;
-    class X64TextAssemblyHolder;
-
     class IRVisitor;
 
+    struct LabelNames;
+
     class AssemblyGenerator;
 }
 
@@ -28,6 +27,14 @@ public:
 };
 
 
+struct zp::LabelNames
+{
+    static const char* main;
+    static const char* getchar;
+    static const char* putchar;
+};
+
+
 class zp::AssemblyGenerator :
     public IRVisitor
 {
@@ -48,12 +55,21 @@ public:
     std::string generateOffset(const std::string& offset, const std::string& base);
     std::string ptr(void);
 
+    template<typename... Args>
+    void write(Args... args)
+    {
+        (out << ... << args) << std::endl;
+    }
+
     virtual void visitBlockInstruction(const BlockInstruction&);
     virtual void visitUnionBlockInstruction(const UnionBlockInstruction&);
     virtual void visitIOInstruction(const IOInstruction&);
     virtual void visitSimpleBlockInstruction(const SimpleBlockInstruction&);
     virtual void visitLinearLoopInstruction(const LinearLoopInstruction&);
     virtual void visitLoopInstruction(const LoopInstruction&);
+
+    void compileMult(Index index, Cell factor);
+    int trailingZeroes(unsigned long long x);
 };
 
 

+ 18 - 3
src/Optimizer.cpp

@@ -97,15 +97,30 @@ unique_ptr<BlockInstruction> Optimizer::visitLoop(Loop& loop)
     auto ret = make_unique<LoopInstruction>();
     ret->content.reserve(loop.instructions.size());
     bool noSubLoops = true;
+    Index pointerMoved = 0;
     for (auto& block : loop.instructions) {
         auto v = visit(*block.get());
-        if (!dynamic_cast<SimpleBlockInstruction*>(v.get())) {
+        if (auto sbi = dynamic_cast<SimpleBlockInstruction*>(v.get())) {
+            pointerMoved += sbi->pointerMoved;
+        }
+        else {
             noSubLoops = false;
         }
         ret->content.push_back(std::move(v));
     }
-    if (noSubLoops) {
-        // TODO: apply linear loop optimizations
+
+    if (noSubLoops && pointerMoved == 0 && ret->content.size() == 1) {
+        auto sbi = dynamic_cast<SimpleBlockInstruction*>(ret->content[0].get());
+        auto linear = make_unique<LinearLoopInstruction>();
+        for (const auto [index, value] : sbi->added) {
+            if (index == 0)
+                linear->increment = value;
+            else
+                linear->factors[index] = value;
+        }
+        if (linear->increment == 255) {
+            return linear;
+        }
     }
     return ret;
 }

+ 3 - 0
src/Optimizer.h

@@ -90,6 +90,9 @@ struct zp::SimpleBlockInstruction :
 struct zp::LinearLoopInstruction :
     public BlockInstruction
 {
+    Cell increment;
+    std::map<Index, Cell> factors;
+    inline LinearLoopInstruction(void) : increment{ 0 } {}
     virtual void accept(IRVisitor& v);
 };
 

+ 6 - 2
src/main.cpp

@@ -9,7 +9,6 @@
 using namespace std;
 using zp::Parser;
 using zp::Optimizer;
-using zp::X64TextAssemblyHolder;
 using zp::AssemblyGenerator;
 
 
@@ -28,9 +27,11 @@ int main(int argc, char** argv)
     }
 
     istream* in = &cin;
+    ostream* out = &cout;
 
     if (filename != "") {
         in = new ifstream{filename.c_str(), fstream::in};
+        out = new ofstream{(filename + ".s").c_str(), fstream::out};
     }
 
     Parser parser{ *in };
@@ -47,14 +48,17 @@ int main(int argc, char** argv)
     Optimizer optimizer;
     auto ir = ast->accept(optimizer);
 
-    AssemblyGenerator ag{ cout };
+    AssemblyGenerator ag{ *out };
     ir->accept(ag);
     ag.finish();
 
     if (filename != "") {
         dynamic_cast<ifstream*> (in)->close();
+        dynamic_cast<ofstream*> (out)->close();
         delete in;
+        delete out;
         in = &cin;
+        out = &cout;
     }
 }