Skip to content

Commit

Permalink
Command Line control (with defaults for debugging)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reschivon committed Oct 28, 2021
1 parent 06f86df commit a9369d2
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 11 deletions.
Binary file added LinkedOut
Binary file not shown.
33 changes: 33 additions & 0 deletions Out.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.text
.file "MovForth"
.globl main
.p2align 4, 0x90
.type main,@function
main:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset %rbx, -16
movl $12, %ebx
.p2align 4, 0x90
.LBB0_1:
movl $.L__unnamed_1, %edi
xorl %eax, %eax
movl %ebx, %esi
callq printf
decl %ebx
jne .LBB0_1
popq %rbx
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc

.type .L__unnamed_1,@object
.section .rodata.str1.1,"aMS",@progbits,1
.L__unnamed_1:
.asciz "%d\n"
.size .L__unnamed_1, 4


.section ".note.GNU-stack","",@progbits
142 changes: 142 additions & 0 deletions boot2.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@

\ Compilation steps:
\
\ First, this file is interpreted as a typical Forth program. This way,
\ user-defined compiling actions actually do execute during compilation time
\
\ Next, in main.cpp, we instruct the compiler to compile a chosen word in the
\ dictionary ("test" in this case)
\
\ Dependency Tree:
\ Then, the compiler builds a dependency tree for the selected word. The word forms
\ the root node and all of its offspring nodes are determined from its definition.
\ This happens recursively until a primitive word, which has no dependecies, is reached
\
\ As this tree is built, the compiler collapses number data stored in the definition
\ (like the number that proceeds a LITERAL) into the word that owns it
\
\ When all offspring of a certain node have been built, the compiler searches
\ the node/word's definition for BRANCH and BRANCHIF. The compiler uses this
\ information to make a control flow graph. Each word/node has its own control
\ flow graph
\
\ A sequence of words that don't include BRANCH or BRANCHIF
\ is a basic block. This is the same defintion that LLVM uses.
\
\
\ Stack Graph:
\ This compiler compiles forth to LLVM IR. But LLVM uses SSA, which is a register-based
\ format, and Forth is a stack-based. So a stack graph is needed to
\ link the output of one word to the input of another.
\
\ Imagine a sequence of words, each with as many input nodes as it
\ takes elements from the stack and as many output nodes as elements that it pushes to the
\ stack. The stack graph algorithm creates an edge between every pair of input/output
\ nodes and assigns a name to the edge. An edge becomes a register in IR.
\
\ The stack graph is printed out on the console during compilation.
\
\ Registers are named X-Y,
\ where X is the index of the basic block it is consumed in,
\ and Y is an index that is unique to the register within its basic block
\
\
\ Stack Graph with Control Flow
\ The compiler supports not just structured control flow but any CFG
\ that can be represented by BRANCH and BRANCHIF. If two basic blocks
\ merge into the same final BB, they will not push differently named registers,
\ In other words, the registers that cross control flow edges are guaranteed to be the same
\ for all merging basic blocks.

\ (I made a very elegant solution to this here. It piggybacks on the control
\ flow DFS pass so it doesn't need its own pass)


\ BBs that merge together *must* push the same number of
\ stack elements. Making this assumption makes the code much easier to write.




: ['] immediate ' ;

: [,] immediate , ;

: negative -1 * ;

: jump>
literal branch ,
here
0 , ;

: jumpif>
literal branchif ,
here
0 , ;

: >land
dup
here - negative
swap ! ;

: land<
here ;

: <jump
literal branch ,
here - , ;

: <jumpif
literal branchif ,
here - , ;

: if immediate
jumpif> ;

: else immediate
jump>
swap
>land ;

: then immediate
>land ;

: while immediate
land< ;

: repeat immediate
<jump ;

: repeatif immediate
literal literal , \ compile `0 =` into word being defined
0 ,
literal = ,
<jumpif ;

: until0 immediate
literal literal , \ compile `1 -` into word being defined
1 ,
literal - ,

literal dup , \ compile `dup` into word being defined

literal literal , \ compile `0 =` into word being defined
0 ,
literal = ,

<jumpif ;


: main
12 while
dup .
1 - dup
repeatif
drop
;

main

see


21 changes: 17 additions & 4 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@
#include "headers/Generation/IRGenerator.h"
#include "headers/Generation/ObjectGenerator.h"

int main() {
int main(int argc, char* argv[]) {

std::string forth_path = "../boot.fs";

if(argc != 1) { // something passed! A .fs filename?
if(argc != 2) {
std::cout << "Pass only one argument, the path to a Forth file" << std::endl;
return 1;
}
forth_path = std::string(argv[1]);
}

println("Compiling Forth file ", forth_path);
std::string program_name = forth_path.substr(0, forth_path.find_last_of("."));

// Create a plain old interpreter that interprets
// the contents of the Forth file boot.fs
mov::Interpreter interpreter("../boot.fs");
mov::Interpreter interpreter(forth_path);

// Extract the compiled word "main" from the interpreter's
// dictionary. "main" has pointers to each of its definition words,
Expand Down Expand Up @@ -38,12 +51,12 @@ int main() {

ir_generator.exec_module();

mov::ObjectGenerator::generate("../Out.S", *module);
mov::ObjectGenerator::generate("../" + program_name + ".S", *module);

// Link the assembly file provided
// Note: invokes `clang++` command in a new shell instance
// May not work on every system
mov::ObjectGenerator::link("../Out.S", "LinkedOut");
mov::ObjectGenerator::link("../" + program_name + ".S", program_name);

}

10 changes: 4 additions & 6 deletions sources/Generation/IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,11 @@ void IRGenerator::print_module() {
void IRGenerator::exec_module() {
println();
println("==========[Execution]===========");
auto command = "lli ../" + the_module->getName() + ".ll";
auto command2 = command.str();
auto command = "lli ../" + the_module->getName().str() + ".ll";

println("Run command ", command2);
char arr[command2.size() + 1];
strcpy(arr, command2.c_str());
println(exec(arr));
println("Run command ", command);

println(exec(command.c_str()));
}


Expand Down
2 changes: 1 addition & 1 deletion sources/Symbolic/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static void align_register_edge(Block &prev, Block &post) {
}

if(prev.outputs_aligned && !post.inputs_aligned){
print("Gen nodes for post");
println("Gen nodes for post");
indent();
for(Node *thing : prev.outputs) {
println(thing->backward_edge_register.to_string());
Expand Down

0 comments on commit a9369d2

Please sign in to comment.