Monstrous commit smh, made a custom ssa intermediate representation to remove some stack ops, glendasay is about 40% faster (and i'm sure the other ones have some improvement too)

This commit is contained in:
cannoli-fruit 2026-07-30 04:54:05 -04:00
commit ca1ee83377
24 changed files with 1018 additions and 176 deletions

View file

@ -34,7 +34,7 @@ targets = {
for f in p:lines() do
base = f:match("([^/]+)%.c$")
obj = "build/"..base..".o"
cc = "cc -c '"..f.."' -o '"..obj.."' "..includes
cc = "cc -c -O3 '"..f.."' -o '"..obj.."' "..includes
e,h,c = execute(cc)
if c ~= 0 and c ~= nil then
print("Compilation Error")

View file

@ -34,7 +34,7 @@ targets = {
for f in p:lines() do
base = f:match("([^/]+)%.c$")
obj = "build/"..base..".o"
cc = "cc -c '"..f.."' -o '"..obj.."' "..includes
cc = "cc -c -ggdb '"..f.."' -o '"..obj.."' "..includes
e,h,c = execute(cc)
if c ~= 0 and c ~= nil then
print("Compilation Error")

1
flagpole/fvm.inc Symbolic link
View file

@ -0,0 +1 @@
../tests/fvm.inc

View file

@ -64,7 +64,7 @@ proc putuint
1 @divisor
while &val &divisor u/ 9 u> do
10 &divisor u* @divisor
&divisor 10 u* @divisor
endwhile
while &divisor 0 u> do
@ -90,7 +90,7 @@ proc puts
dup ld8 :putchar
1 u+
endwhile
pop
drop
endproc
proc newline

View file

@ -0,0 +1,5 @@
proc main
2 @a
3 @b
&a &b u+
endproc

13
flagpole/irtests/cat.fp Normal file
View file

@ -0,0 +1,13 @@
proc putchar
0xCFFFFFFFFFFFFFFD st8
endproc
proc getchar
0xCFFFFFFFFFFFFFFE ld8
endproc
proc main
while 1 do
:getchar :putchar
endwhile
endproc

11
flagpole/irtests/cat1.fp Normal file
View file

@ -0,0 +1,11 @@
proc putchar
0xCFFFFFFFFFFFFFFD st8
endproc
proc getchar
0xCFFFFFFFFFFFFFFE ld8
endproc
proc main
:getchar :putchar
endproc

View file

@ -0,0 +1,10 @@
$inc fvmstd.fp
proc main
1 @divisor
while &divisor 100 u< do
0x31 :putchar
&divisor 10 u* @divisor
endwhile
0x32 :putchar
endproc

View file

@ -0,0 +1,3 @@
proc main
"String" 1 u+
endproc

5
flagpole/irtests/eq.fp Normal file
View file

@ -0,0 +1,5 @@
proc main
1
2 1 u-
==
endproc

6
flagpole/irtests/gt.fp Normal file
View file

@ -0,0 +1,6 @@
proc main
5
if 5 3 u> then
drop 3
endif
endproc

7
flagpole/irtests/hex.fp Normal file
View file

@ -0,0 +1,7 @@
proc putchar
0xCFFFFFFFFFFFFFFD st8
endproc
proc main
0x48 :putchar
endproc

10
flagpole/irtests/loop.fp Normal file
View file

@ -0,0 +1,10 @@
$inc fvmstd.fp
proc main
1 @i
0x30 :putchar
while &i 10 u< do
0x30 :putchar
&i 1 u+ @i
endwhile
endproc

5
flagpole/irtests/num.fp Normal file
View file

@ -0,0 +1,5 @@
$inc fvmstd.fp
proc main
4 :putuint
endproc

View file

@ -0,0 +1,5 @@
$inc fvmstd.fp
proc main
23 :putuint
endproc

3
flagpole/irtests/uadd.fp Normal file
View file

@ -0,0 +1,3 @@
proc main
34 35 u+
endproc

3
flagpole/irtests/usub.fp Normal file
View file

@ -0,0 +1,3 @@
proc main
500 80 u-
endproc

4
flagpole/irtests/var.fp Normal file
View file

@ -0,0 +1,4 @@
proc main
0x40 @a
&a 2 u+
endproc

View file

@ -0,0 +1,14 @@
$inc fvmstd.fp
proc main
2 @a
4 @b
3 @a
8 @c
&b @a
&c @a
&a 0x30 u+ :putchar
&b 0x30 u+ :putchar
&c 0x30 u+ :putchar
endproc

285
flagpole/src/ir.c Normal file
View file

@ -0,0 +1,285 @@
#include "lazy.h"
#include "ir.h"
void IRLoadValue(IRValue v, int reg, IRValue *registers) {
if (v.typ == IRVAL_VIRTUAL) {
for (int i = 1; i < 96; ++i) {
if (registers[i].typ == IRVAL_VIRTUAL && registers[i].val == v.val) {
printf(" Mov64 %d, %d\n", reg, i);
return;
}
}
}
if (v.typ == IRVAL_STACK) {
for (int i = 1; i < 96; ++i) {
if (registers[i].typ == IRVAL_STACK && registers[i].val == v.val) {
printf(" Mov64 %d, %d\n", reg, i);
return;
}
}
}
if (v.typ == IRVAL_MEMORY) {
printf(" MovI64 103, 0x%016lX\n", v.val);
printf(" Ld64 %d, 103\n", reg);
return;
}
if (v.typ == IRVAL_CONSTANT) {
printf(" MovI64 %d, 0x%016lX\n", reg, v.val);
}
}
void IRStoreValue(IRValue v, int reg, int *regalloc, IRValue *registers) {
if (v.typ == IRVAL_VIRTUAL) {
int r = (*regalloc)++;
registers[r] = v;
printf(" Mov64 %d, %d\n", r, reg);
}
if (v.typ == IRVAL_STACK) {
assert(0 && "Don't write directly to the stack pooks <3");
}
if (v.typ == IRVAL_MEMORY) {
printf(" MovI64 123, 0x%016lX\n", v.val);
printf(" St64 %d, 123\n", reg);
return;
}
if (v.typ == IRVAL_CONSTANT) {
// Escape for non returning operations
}
}
void IRComplete(void *statements_v, void *vstack_v) {
Lz_DA(IRStatement) *statements = statements_v;
Lz_DA(IRValue) *vstack = vstack_v;
int regalloc = 1; // Current register for allocating things
// If you manage to hit 95 registers
// You deserve for your compiler to fail
IRValue registers[96];
int deepestStack = 0;
for (int i = 0; i < statements->cnt; ++i) {
if (statements->data[i].arg1.typ == IRVAL_STACK) {
if (statements->data[i].arg1.val > deepestStack) {
deepestStack = statements->data[i].arg1.val;
}
}
if (statements->data[i].arg2.typ == IRVAL_STACK) {
if (statements->data[i].arg2.val > deepestStack) {
deepestStack = statements->data[i].arg2.val;
}
}
}
for (int i = 0; i < deepestStack; ++i) {
int reg = regalloc++;
printf(" popstack %d\n", reg);
registers[reg] = (IRValue) {
.typ = IRVAL_STACK,
.val = i+1
};
}
int count;
lz_da_foreach(IRStatement, s, *statements) {
++count;
printf("; Using ir-operation %d\n", s->op);
switch (s->op) {
case IR_UADD: {
IRLoadValue(s->arg1, 101, registers);
IRLoadValue(s->arg2, 100, registers);
printf(" AddR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_USUB: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" SubR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_UMUL: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" MulR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_UDIV: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" DivR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_UMOD: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" ModR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_AND: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" AndR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_XOR: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" XorR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_OR: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" OrR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_NOT: {
IRLoadValue(s->arg1, 101, registers);
printf(" Not64 101\n");
IRStoreValue(s->dst, 101, &regalloc, registers);
break;
}
case IR_IMUL: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" IMulR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_IDIV: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" IDivR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_IMOD: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" IModR64 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_ST8: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" St8 100, 101\n");
break;
}
case IR_SWAP: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
IRStoreValue(s->arg1, 100, &regalloc, registers);
IRStoreValue(s->arg2, 101, &regalloc, registers);
break;
}
case IR_NOP: {
IRLoadValue(s->arg1, 100, registers);
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_LD8: {
IRLoadValue(s->arg1, 101, registers);
printf(" Ld8 100, 101\n");
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
case IR_EQ: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" Cmp64 100, 101\n");
printf(" JmpIZ eq_%d\n", count);
printf(" MovI64 99, 0\n");
printf(" Jmp cmpdone_%d\n", count);
printf("eq_%d:\n", count);
printf(" MovI64 99, 1\n");
printf("cmpdone_%d:\n",count);
IRStoreValue(s->dst, 99, &regalloc, registers);
break;
}
case IR_ULT: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" Cmp64 100, 101\n");
printf(" JmpIN eq_%d\n", count);
printf(" MovI64 99, 0\n");
printf(" Jmp cmpdone_%d\n", count);
printf("eq_%d:\n", count);
printf(" MovI64 99, 1\n");
printf("cmpdone_%d:\n", count);
IRStoreValue(s->dst, 99, &regalloc, registers);
break;
}
case IR_UGT: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" Cmp64 100, 101\n");
printf(" JmpIP eq_%d\n", count);
printf(" MovI64 99, 0\n");
printf(" Jmp cmpdone_%d\n", count);
printf("eq_%d:\n", count);
printf(" MovI64 99, 1\n");
printf("cmpdone_%d:\n",count);
IRStoreValue(s->dst, 99, &regalloc, registers);
break;
}
case IR_ILT: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" ICmp64 100, 101\n");
printf(" JmpIN eq_%d\n", count);
printf(" MovI64 99, 0\n");
printf(" Jmp cmpdone_%d\n", count);
printf("eq_%d:\n", count);
printf(" MovI64 99, 1\n");
printf("cmpdone_%d:\n",count);
IRStoreValue(s->dst, 99, &regalloc, registers);
break;
}
case IR_IGT: {
IRLoadValue(s->arg2, 100, registers);
IRLoadValue(s->arg1, 101, registers);
printf(" ICmp64 100, 101\n");
printf(" JmpIP eq_%d\n", count);
printf(" MovI64 99, 0\n");
printf(" Jmp cmpdone_%d\n", count);
printf("eq_%d:\n", count);
printf(" MovI64 99, 1\n");
printf("cmpdone_%d:\n",count);
IRStoreValue(s->dst, 99, &regalloc, registers);
break;
}
case IR_STR: {
IRStoreValue(s->dst, 100, &regalloc, registers);
break;
}
}
}
lz_da_foreach(IRValue, v, *vstack) {
if (v->typ == IRVAL_CONSTANT) {
printf(" MovI64 123, 0x%016lX\n", v->val);
printf(" pushstack 123\n");
continue;
}
for (int i = 0; i < 96; ++i) {
if (registers[i].typ == v->typ && registers[i].val == v->val) {
printf(" pushstack %d\n",i);
break;
}
}
}
vstack->cnt = 0;
statements->cnt = 0;
}

51
flagpole/src/ir.h Normal file
View file

@ -0,0 +1,51 @@
typedef enum {
IRVAL_VIRTUAL,
IRVAL_STACK,
IRVAL_MEMORY,
IRVAL_ARG,
IRVAL_CONSTANT
} IRValKind;
typedef struct {
IRValKind typ;
uint64_t val;
} IRValue;
typedef enum {
IR_NOP,
IR_SWAP,
IR_UADD,
IR_USUB,
IR_UMUL,
IR_UDIV,
IR_UMOD,
IR_IADD,
IR_ISUB,
IR_IMUL,
IR_IDIV,
IR_IMOD,
IR_UGT,
IR_ULT,
IR_IGT,
IR_ILT,
IR_EQ,
IR_NOT,
IR_AND,
IR_OR,
IR_XOR,
IR_LD8,
IR_LD64,
IR_ST8,
IR_ST64,
IR_STR,
} IROperation;
typedef struct {
IRValue dst;
IROperation op;
IRValue arg1;
IRValue arg2;
} IRStatement;
void IRComplete(void *statements_v, void *vstack_v);

View file

@ -5,6 +5,7 @@
#include "lazy.h"
#include "token.h"
#include "var.h"
#include "ir.h"
bool is_int_literal(Lz_SB *sb) {
for (int i = 0; i < sb->cnt; ++i) {
@ -78,6 +79,24 @@ void commentStack(void *stack) {
printf("\n");
}
static inline uint64_t lz_sb_readhex(Lz_SB *sb) {
Lz_SB clone = *sb;
clone.data += 2;
clone.cnt -= 2;
uint64_t val = 0;
lz_da_foreach(char, c, clone) {
val *= 0x10;
if (*c >= '0' && *c <= '9') {
val += *c - '0';
} else if (*c >= 'A' && *c <= 'F') {
val += *c - 'A' + 10;
} else if (*c >= 'a' && *c <= 'f') {
val += *c - 'a' + 10;
}
}
return val;
}
static inline bool isKW(Lz_SB *sb) {
return
SBeq(sb, "proc")
@ -117,6 +136,28 @@ static inline bool isKW(Lz_SB *sb) {
;
}
#define IR_GET_2_ARGS \
IRValue x1, x2; \
if (irVStack.cnt >= 2) { \
x1 = lz_da_pop(irVStack); \
x2 = lz_da_pop(irVStack); \
} else if (irVStack.cnt == 1) { \
x1 = lz_da_pop(irVStack); \
x2 = (IRValue) { \
.typ = IRVAL_STACK, \
.val = ++vstackUnderflows \
}; \
} else if (irVStack.cnt == 0) { \
x1 = (IRValue) { \
.typ = IRVAL_STACK, \
.val = ++vstackUnderflows \
}; \
x2 = (IRValue) { \
.typ = IRVAL_STACK, \
.val = ++vstackUnderflows \
}; \
}
int main(uint argc, char **argv) {
int opt;
Lz_DA(FILE *) inpfiles = {};
@ -152,24 +193,28 @@ int main(uint argc, char **argv) {
Lz_DA(int) labelStack = {0};
uint64_t allocHead = 0x7000000000000000;
char funcName[128];
Lz_DA(Variable) vars;
Lz_DA(Variable) vars = {0};
char newchar;
Lz_DA(IRStatement) irStatements = {0};
Lz_DA(IRValue) irVStack = {0};
int irVCount = 0;
int vstackUnderflows = 0;
printf("include 'fvm.inc'\n");
printf("define STACK_START 0x6000000000000000\n");
printf("define STACK_SP 125\n");
printf("define STACK_INC 126\n");
printf("org 0x4000000000000000\n");
printf(" MovI64 STACK_SP, STACK_START\n");
printf(" MovI64 STACK_INC, 8\n");
printf(" Call __fp_user_main\n");
printf(" Halt\n");
printf("macro pushstack reg\n");
printf(" MovI64 124, 8\n");
printf(" SubR64 STACK_SP, 124\n");
printf(" SubR64 STACK_SP, STACK_INC\n");
printf(" St64 reg, STACK_SP\n");
printf("end macro\n\n");
printf("macro popstack reg\n");
printf(" MovI64 124, 8\n");
printf(" Ld64 reg, STACK_SP\n");
printf(" AddR64 STACK_SP, 124\n");
printf(" AddR64 STACK_SP, STACK_INC\n");
printf("end macro\n\n");
// Genuinely idk why goto is possessing me today
compileStart:
@ -182,32 +227,32 @@ compileStart:
if (tokenAccumulator.cnt == 0) continue;
if (is_int_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_INTLIT;
goto codegen;
goto codegenIR;
} else if (is_float_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_FLOATLIT;
goto codegen;
goto codegenIR;
} else if (is_double_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_DOUBLELIT;
goto codegen;
goto codegenIR;
} else if (is_hex_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_HEXLIT;
goto codegen;
goto codegenIR;
} else if (is_bin_literal(&tokenAccumulator)) {
currTokenKind = TOKEN_BINLIT;
goto codegen;
goto codegenIR;
} else {
currTokenKind = TOKEN_IDENTIFIER;
if (isKW(&tokenAccumulator)) {
currTokenKind = TOKEN_KEYWORD;
}
goto codegen;
goto codegenIR;
}
}
if (newchar == '"') {
if (isQuote) {
currTokenKind = TOKEN_STRINGLIT;
isQuote = false;
goto codegen;
goto codegenIR;
} else {
if (tokenAccumulator.cnt != 0) {
fprintf(stderr, "error %d\n", __LINE__);
@ -220,7 +265,8 @@ compileStart:
}
lz_da_append(tokenAccumulator, newchar);
continue;
codegen:
// Names suck but this also generates some asm for blocks
codegenIR:
//printf("I must gen code i am now Amista Azozin\n");
//fprintf(stderr,"Token type: %d\n", currTokenKind);
//fprintf(stderr,"Tok: "LZ_STR_FMT"\n", LZ_STR_PRINTF(tokenAccumulator));
@ -232,6 +278,8 @@ codegen:
break;
}
if (SBeq(&tokenAccumulator, "endproc")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
printf(" Ret\n");
printf("\n\n");
if (labelStack.cnt != 0) {
@ -243,53 +291,113 @@ codegen:
break;
}
if (SBeq(&tokenAccumulator, "return")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
printf(" Ret\n");
break;
}
if (SBeq(&tokenAccumulator, "ld8")) {
printf(" popstack 101\n");
printf(" Ld8 102, 101\n");
printf(" pushstack 102\n");
IRValue x1;
if (irVStack.cnt >= 1) {
x1 = lz_da_pop(irVStack);
} else if (irVStack.cnt == 0) {
x1 = (IRValue) {
.typ = IRVAL_STACK,
.val = 1
};
}
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_LD8,
.arg1 = x1
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "st8")) {
printf(" popstack 101\n");
printf(" popstack 102\n");
printf(" St8 102, 101\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_CONSTANT,
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_ST8,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "dup")) {
if (irVStack.cnt != 0) {
IRValue v = lz_da_pop(irVStack);
lz_da_append(irVStack, v);
lz_da_append(irVStack, v);
} else {
printf(" popstack 106\n");
printf(" pushstack 106\n");
printf(" pushstack 106\n");
}
break;
}
if (SBeq(&tokenAccumulator, "swap")) {
printf(" popstack 118\n");
printf(" popstack 119\n");
printf(" pushstack 118\n");
printf(" pushstack 119\n");
IRValue x1, x2;
if (irVStack.cnt >= 2) {
x1 = lz_da_pop(irVStack);
x2 = lz_da_pop(irVStack);
} else if (irVStack.cnt == 1) {
x1 = lz_da_pop(irVStack);
x2 = (IRValue) {
.typ = IRVAL_STACK,
.val = ++vstackUnderflows
};
} else if (irVStack.cnt == 0) {
x1 = (IRValue) {
.typ = IRVAL_STACK,
.val = ++vstackUnderflows
};
x2 = (IRValue) {
.typ = IRVAL_STACK,
.val = ++vstackUnderflows
};
}
lz_da_append(irVStack, x1);
lz_da_append(irVStack, x2);
break;
}
if (SBeq(&tokenAccumulator, "drop")) {
if (irVStack.cnt != 0)
lz_da_pop(irVStack);
else
printf(" popstack 118\n");
break;
}
if (SBeq(&tokenAccumulator, "while")) {
IRComplete(&irStatements, &irVStack);
lz_da_append(labelStack, counter);
commentStack(&labelStack);
printf("__whilehead_%d:\n", counter);
break;
}
if (SBeq(&tokenAccumulator, "do")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
int lbl = lz_da_pop(labelStack);
lz_da_append(labelStack, lbl);
// TODO: Change flag setting to IR's job
printf(" popstack 108\n");
printf(" RSetF 108\n");
printf(" JmpIE __whiletail_%d\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "endwhile")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
int lbl = lz_da_pop(labelStack);
commentStack(&labelStack);
printf(" Jmp __whilehead_%d\n", lbl);
@ -302,6 +410,8 @@ codegen:
break;
}
if (SBeq(&tokenAccumulator, "then")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
commentStack(&labelStack);
int lbl = lz_da_pop(labelStack);
lz_da_append(labelStack, lbl);
@ -312,177 +422,322 @@ codegen:
}
if (SBeq(&tokenAccumulator, "endif")) {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
commentStack(&labelStack);
int lbl = lz_da_pop(labelStack);
printf("__iftail_%d:\n", lbl);
break;
}
if (SBeq(&tokenAccumulator, "==")) {
// Hacked like crazy...
printf(" popstack 110\n");
printf(" popstack 111\n");
printf(" Cmp64 110, 111\n");
printf(" JmpIZ __Eq%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneEqCheck%d\n", counter);
printf("__Eq%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneEqCheck%d:\n", counter);
printf(" pushstack 112\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_EQ,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "not")) {
printf(" popstack 96\n");
printf(" Not64 96\n");
printf(" pushstack 96\n");
IRValue x1;
if (irVStack.cnt >= 1) {
x1 = lz_da_pop(irVStack);
} else if (irVStack.cnt == 0) {
x1 = (IRValue) {
.typ = IRVAL_STACK,
.val = 1
};
}
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_NOT,
.arg1 = x1
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "band")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" AndR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_AND,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "bor")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" OrR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_OR,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "xor")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" xorR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_XOR,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u+")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" AddR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UADD,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u-")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" SubR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_USUB,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u*")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" MulR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UMUL,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u/")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" DivR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UDIV,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u%")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" ModR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UMOD,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u>")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" Cmp64 98, 97\n");
printf(" JmpIP __Cmp%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneCmp%d\n", counter);
printf("__Cmp%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneCmp%d:\n", counter);
printf(" pushstack 112\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UGT,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "u<")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" Cmp64 98, 97\n");
printf(" JmpIN __Cmp%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneCmp%d\n", counter);
printf("__Cmp%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneCmp%d:\n", counter);
printf(" pushstack 112\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_ULT,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i+")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" AddR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_UADD,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i-")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" SubR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_USUB,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i*")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" IMulR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_IMUL,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i/")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" IDivR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_IDIV,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i%")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" IModR64 98, 97\n");
printf(" pushstack 98\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_IMOD,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i>")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" ICmp64 98, 97\n");
printf(" JmpIP __Cmp%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneCmp%d\n", counter);
printf("__Cmp%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneCmp%d:\n", counter);
printf(" pushstack 112\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_ILT,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "i<")) {
printf(" popstack 97\n");
printf(" popstack 98\n");
printf(" ICmp64 98, 97\n");
printf(" JmpIN __Cmp%d\n", counter);
printf(" MovI64 112, 0\n");
printf(" Jmp __DoneCmp%d\n", counter);
printf("__Cmp%d:\n", counter);
printf(" MovI64 112, 1\n");
printf("__DoneCmp%d:\n", counter);
printf(" pushstack 112\n");
break;
}
if (SBeq(&tokenAccumulator, "pop")) {
printf(" popstack 113\n");
IR_GET_2_ARGS
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_IGT,
.arg1 = x1,
.arg2 = x2
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
}
if (SBeq(&tokenAccumulator, "$inc")) {
@ -511,6 +766,11 @@ codegen:
printf("__fp_user_"LZ_STR_FMT":\n",
LZ_STR_PRINTF(tokenAccumulator));
isProc = false;
IRValue arg = (IRValue) {
.typ = IRVAL_ARG,
.val = 0
};
if (tokenAccumulator.cnt < 127) {
memcpy(funcName, tokenAccumulator.data, tokenAccumulator.cnt);
funcName[tokenAccumulator.cnt] = 0;
@ -521,6 +781,8 @@ codegen:
break;
}
if (tokenAccumulator.data[0] == ':') {
IRComplete(&irStatements, &irVStack);
vstackUnderflows = 0;
printf(" Call __fp_user_"LZ_STR_FMT"\n",
tokenAccumulator.cnt-1,
tokenAccumulator.data+1);
@ -553,10 +815,26 @@ codegen:
lz_da_append(vars, v);
allocHead += 8;
}
printf(" popstack 120\n");
printf(" ; %s:%s\n", funcName, varName);
printf(" MovI64 121, 0x%16lX\n", addr);
printf(" St64 120, 121\n");
IRValue x1;
if (irVStack.cnt >= 1) {
x1 = lz_da_pop(irVStack);
} else if (irVStack.cnt == 0) {
x1 = (IRValue) {
.typ = IRVAL_STACK,
.val = ++vstackUnderflows
};
}
IRValue dstReg = (IRValue) {
.typ = IRVAL_MEMORY,
.val = addr
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_NOP,
.arg1 = x1
};
lz_da_append(irStatements, s);
break;
}
if (tokenAccumulator.data[0] == '&') {
@ -581,9 +859,23 @@ codegen:
varName, funcName);
exit(1);
}
printf(" MovI64 121, 0x%16lX\n", addr);
printf(" Ld64 120, 121\n");
printf(" pushstack 120\n");
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
IRValue x1 = (IRValue) {
.typ = IRVAL_MEMORY,
.val = addr
};
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_NOP,
.arg1 = x1
};
lz_da_append(irStatements, s);
lz_da_append(irVStack, dstReg);
break;
}
// Iirc there's not a general thing for identifiers so just fail?
@ -592,25 +884,58 @@ codegen:
exit(0);
}
case TOKEN_INTLIT: {
printf(" MovI64 103, "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
printf(" pushstack 103\n");
uint64_t x = lz_sb_atoll(&tokenAccumulator);
IRValue v = (IRValue) {
.typ = IRVAL_CONSTANT,
.val = x
};
lz_da_append(irVStack, v);
break;
}
case TOKEN_HEXLIT: {
printf(" MovI64 103, "LZ_STR_FMT"\n",
LZ_STR_PRINTF(tokenAccumulator));
printf(" pushstack 103\n");
uint64_t x = lz_sb_readhex(&tokenAccumulator);
IRValue v = (IRValue) {
.typ = IRVAL_CONSTANT,
.val = x
};
lz_da_append(irVStack, v);
break;
}
case TOKEN_STRINGLIT: {
IRValue dstReg = (IRValue) {
.typ = IRVAL_VIRTUAL,
.val = ++irVCount
};
// This is a bad way of doing strings tbh
printf(" Jmp endstring%d\n", counter);
printf("string%d db \""LZ_STR_FMT"\", 0\n",
counter,
LZ_STR_PRINTF(tokenAccumulator));
printf("endstring%d:\n", counter);
printf(" MovI64 100, string%d\n", counter);
printf(" pushstack 100\n", counter);
IRStatement s = (IRStatement) {
.dst = dstReg,
.op = IR_NOP,
.arg1 = IR_STR
};
lz_da_append(irVStack, dstReg);
lz_da_append(irStatements, s);
break;
//IRComplete(&irStatements, &irVStack);
//vstackUnderflows = 0;
//printf(" Jmp endstring%d\n", counter);
//printf("string%d db \""LZ_STR_FMT"\", 0\n",
// counter,
// LZ_STR_PRINTF(tokenAccumulator));
//printf("endstring%d:\n", counter);
//printf(" MovI64 100, string%d\n", counter);
//printf(" pushstack 100\n", counter);
// IRValue v = (IRValue) {
// .typ = IRVAL_STACK,
// .val = 1
// };
// lz_da_append(irVStack, v);
break;
}
default: {

14
flagpole/tests/fibloop.fp Normal file
View file

@ -0,0 +1,14 @@
$inc fvmstd.fp
proc main
92 @N
0 @a
1 @b
while &N 0 u> do
&a &b u+ @c
&b @a
&c @b
&N 1 u- @N
endwhile
&b :putuint :newline
endproc

View file

@ -5,9 +5,11 @@
#include <assert.h>
#define LAZY_IMPL
#include "lazy.h"
#include <time.h>
#define PAGE_SIZE 4096
#define DEBUG false
//#define DEBUG
//#define TIME
// MMIO is defined between 0xC000000000000000 and 0xD000000000000000
// Some of that is still normal memory though
#define UART_TX 0xCFFFFFFFFFFFFFFD
@ -122,27 +124,47 @@ int main(int argc, char **argv) {
bool positiveFlag = false;
bool negativeFlag = false;
bool parityFlag = false;
#ifdef TIME
Lz_HM(unsigned char, uint) instrTimes;
Lz_HM(unsigned char, uint) instrCounts;
lz_hm_init(instrTimes);
lz_hm_init(instrCounts);
#endif
while (1) {
unsigned char inst = memory_get8(xPc);
if (DEBUG) printf("INST: %02X\n", inst);
if (DEBUG) printf("IP: %16lX\n", xPc);
#ifdef DEBUG
printf("INST: %02X\n", inst);
printf("IP: %16lX\n", xPc);
#endif
size_t inpflag = (inst & 0xE0) >> 5;
size_t inpcnt = flag_bytecnt[inpflag];
if (DEBUG) printf("Cnt: %zu\n", inpcnt);
#ifdef DEBUG
printf("Cnt: %zu\n", inpcnt);
#endif
unsigned char inputs[9];
for (size_t i = 0; i < inpcnt; ++i) {
inputs[i] = memory_get8(xPc+i+1);
if (DEBUG) {
#ifdef DEBUG
printf("X%d: 0x%8X\n", i, inputs[i]);
#endif
}
#ifdef TIME
if (lz_hm_exists(instrCounts, inst)) {
uint x = lz_hm_get(instrCounts, inst);
lz_hm_remove(instrCounts, inst);
lz_hm_add(instrCounts, inst, x+1);
} else {
lz_hm_add(instrCounts, inst, 1);
}
clock_t startTime = clock();
#endif
xPc += 1;
xPc += inpcnt;
switch (inst) {
case 0x00: { // Halt
printf("\nHALT\n");
exit(0);
goto halt;
break;
}
case 0xE9: { // MovI64
@ -156,13 +178,13 @@ int main(int argc, char **argv) {
unsigned char x7 = inputs[7];
unsigned char x8 = inputs[8];
uint64_t val =
((uint64_t)x1 << 56) +
((uint64_t)x2 << 48) +
((uint64_t)x3 << 40) +
((uint64_t)x4 << 32) +
((uint64_t)x5 << 24) +
((uint64_t)x6 << 16) +
((uint64_t)x7 << 8) +
((uint64_t)x1 << 56) |
((uint64_t)x2 << 48) |
((uint64_t)x3 << 40) |
((uint64_t)x4 << 32) |
((uint64_t)x5 << 24) |
((uint64_t)x6 << 16) |
((uint64_t)x7 << 8) |
((uint64_t)x8 << 0);
registers[reg] = val;
registers[0] = 0;
@ -183,11 +205,11 @@ int main(int argc, char **argv) {
case 0x93: { // Ld8
unsigned char dst = inputs[0];
unsigned char addr = inputs[1];
if (DEBUG) {
#ifdef DEBUG
printf("Ld8\n");
printf("Dst val: %8X\n", registers[dst]);
printf("Addr val: %8X\n", registers[addr]);
}
#endif
registers[dst] = memory_get8(registers[addr]);
break;
}
@ -324,7 +346,9 @@ int main(int argc, char **argv) {
case 0xC1: { // JmpIZ
unsigned char addr = inputs[0];
if (zeroFlag) {
if (DEBUG) printf("Jump!\n");
#ifdef DEBUG
printf("Jump!\n");
#endif
xPc = registers[addr];
}
break;
@ -332,7 +356,9 @@ int main(int argc, char **argv) {
case 0xC3: { // JmpIP
unsigned char addr = inputs[0];
if (positiveFlag) {
if (DEBUG) printf("Jump!\n");
#ifdef DEBUG
printf("Jump!\n");
#endif
xPc = registers[addr];
}
break;
@ -340,7 +366,9 @@ int main(int argc, char **argv) {
case 0xC2: { // JmpIN
unsigned char addr = inputs[0];
if (negativeFlag) {
if (DEBUG) printf("Jump!\n");
#ifdef DEBUG
printf("Jump!\n");
#endif
xPc = registers[addr];
}
break;
@ -348,7 +376,9 @@ int main(int argc, char **argv) {
case 0xC8: { // JmpIE
unsigned char addr = inputs[0];
if (!parityFlag) {
if (DEBUG) printf("Jump!\n");
#ifdef DEBUG
printf("Jump!\n");
#endif
xPc = registers[addr];
}
break;
@ -377,7 +407,39 @@ int main(int argc, char **argv) {
exit(1);
}
}
#ifdef TIME
clock_t endTime = clock();
clock_t diff = endTime - startTime ;
uint usec = diff * 1000000 / CLOCKS_PER_SEC;
if (lz_hm_exists(instrTimes, inst)) {
uint x = lz_hm_get(instrTimes, inst);
lz_hm_remove(instrTimes, inst);
lz_hm_add(instrTimes, inst, x+usec);
} else {
lz_hm_add(instrTimes, inst, usec);
}
#endif
}
halt:
#ifdef TIME
// TODO: Fix this shit
for (int i = 0; i < instrTimes.cap; ++i) {
if (instrTimes.exists[i]) {
printf("Instr: %2x used %dus\n",
instrTimes.keys[i],
instrTimes.vals[i]);
}
}
for (int i = 0; i < instrCounts.cap; ++i) {
if (instrCounts.exists[i]) {
printf("Instr: %2x used %d times\n",
instrCounts.keys[i],
instrCounts.vals[i]);
}
}
#endif
return 0;
}