Grow stack automatically
This commit is contained in:
146
source/elna/ir.d
146
source/elna/ir.d
@ -15,34 +15,35 @@ struct ASTMapping
|
||||
alias Node = .Node;
|
||||
alias Definition = .Definition;
|
||||
alias VariableDeclaration = .VariableDeclaration;
|
||||
alias Statement = Array!(.Statement);
|
||||
alias BangStatement = .Expression;
|
||||
alias Statement = .Operand;
|
||||
alias BangStatement = .Operand;
|
||||
alias Block = .Definition;
|
||||
alias Expression = .Expression;
|
||||
alias Expression = .Operand;
|
||||
alias Number = .Number;
|
||||
alias Variable = .Variable;
|
||||
alias BinaryExpression = .BinaryExpression;
|
||||
alias Variable = .Number;
|
||||
alias BinaryExpression = .Variable;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* IR visitor.
|
||||
*/
|
||||
extern(C++)
|
||||
interface IRVisitor
|
||||
{
|
||||
abstract void visit(Node) @nogc;
|
||||
abstract void visit(Definition) @nogc;
|
||||
abstract void visit(Expression) @nogc;
|
||||
abstract void visit(Statement) @nogc;
|
||||
abstract void visit(Operand) @nogc;
|
||||
abstract void visit(BinaryExpression) @nogc;
|
||||
abstract void visit(Variable) @nogc;
|
||||
abstract void visit(VariableDeclaration) @nogc;
|
||||
abstract void visit(Number) @nogc;
|
||||
abstract void visit(BinaryExpression) @nogc;
|
||||
}
|
||||
|
||||
/**
|
||||
* AST node.
|
||||
*/
|
||||
extern(C++)
|
||||
abstract class Node
|
||||
{
|
||||
abstract void accept(IRVisitor) @nogc;
|
||||
@ -51,11 +52,13 @@ abstract class Node
|
||||
/**
|
||||
* Definition.
|
||||
*/
|
||||
extern(C++)
|
||||
class Definition : Node
|
||||
{
|
||||
char[] identifier;
|
||||
Array!Statement statements;
|
||||
Array!BinaryExpression statements;
|
||||
Array!VariableDeclaration variableDeclarations;
|
||||
Operand result;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc
|
||||
{
|
||||
@ -63,17 +66,13 @@ class Definition : Node
|
||||
}
|
||||
}
|
||||
|
||||
class Statement : Node
|
||||
extern(C++)
|
||||
abstract class Statement : Node
|
||||
{
|
||||
BinaryExpression expression;
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc
|
||||
{
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Expression : Node
|
||||
extern(C++)
|
||||
abstract class Operand : Node
|
||||
{
|
||||
override void accept(IRVisitor visitor) @nogc
|
||||
{
|
||||
@ -81,7 +80,8 @@ abstract class Expression : Node
|
||||
}
|
||||
}
|
||||
|
||||
class Number : Expression
|
||||
extern(C++)
|
||||
class Number : Operand
|
||||
{
|
||||
int value;
|
||||
|
||||
@ -91,7 +91,8 @@ class Number : Expression
|
||||
}
|
||||
}
|
||||
|
||||
class Variable : Expression
|
||||
extern(C++)
|
||||
class Variable : Operand
|
||||
{
|
||||
size_t counter;
|
||||
|
||||
@ -101,6 +102,7 @@ class Variable : Expression
|
||||
}
|
||||
}
|
||||
|
||||
extern(C++)
|
||||
class VariableDeclaration : Node
|
||||
{
|
||||
String identifier;
|
||||
@ -111,12 +113,13 @@ class VariableDeclaration : Node
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryExpression : Node
|
||||
extern(C++)
|
||||
class BinaryExpression : Statement
|
||||
{
|
||||
Expression lhs, rhs;
|
||||
Operand lhs, rhs;
|
||||
BinaryOperator operator;
|
||||
|
||||
this(Expression lhs, Expression rhs, BinaryOperator operator)
|
||||
this(Operand lhs, Operand rhs, BinaryOperator operator)
|
||||
@nogc
|
||||
{
|
||||
this.lhs = lhs;
|
||||
@ -130,9 +133,26 @@ class BinaryExpression : Node
|
||||
}
|
||||
}
|
||||
|
||||
extern(C++)
|
||||
class BangExpression : Statement
|
||||
{
|
||||
Operand operand;
|
||||
|
||||
this(Operand operand)
|
||||
{
|
||||
this.operand = operand;
|
||||
}
|
||||
|
||||
override void accept(IRVisitor visitor) @nogc
|
||||
{
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
{
|
||||
private HashTable!(String, int) constants;
|
||||
private Array!BinaryExpression statements;
|
||||
|
||||
ASTMapping.Node visit(parser.Node node) @nogc
|
||||
{
|
||||
@ -151,7 +171,7 @@ final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
|
||||
ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
return statement.expression.accept(this);
|
||||
}
|
||||
|
||||
ASTMapping.Block visit(parser.Block block) @nogc
|
||||
@ -159,7 +179,9 @@ final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
auto target = defaultAllocator.make!Definition;
|
||||
this.constants = transformConstants(block.definitions);
|
||||
|
||||
target.statements = block.statement.accept(this);
|
||||
target.result = block.statement.accept(this);
|
||||
target.statements = this.statements;
|
||||
|
||||
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
|
||||
|
||||
return target;
|
||||
@ -167,41 +189,45 @@ final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
|
||||
ASTMapping.Expression visit(parser.Expression expression) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
if ((cast(parser.Number) expression) !is null)
|
||||
{
|
||||
return (cast(parser.Number) expression).accept(this);
|
||||
}
|
||||
if ((cast(parser.Variable) expression) !is null)
|
||||
{
|
||||
return (cast(parser.Variable) expression).accept(this);
|
||||
}
|
||||
else if ((cast(parser.BinaryExpression) expression) !is null)
|
||||
{
|
||||
return (cast(parser.BinaryExpression) expression).accept(this);
|
||||
}
|
||||
assert(false, "Invalid expression type");
|
||||
}
|
||||
|
||||
ASTMapping.Number visit(parser.Number number) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = number.value;
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
|
||||
ASTMapping.Variable visit(parser.Variable variable) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = this.constants[variable.identifier];
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
|
||||
ASTMapping.BinaryExpression visit(parser.BinaryExpression) @nogc
|
||||
{
|
||||
assert(false, "Not implemented");
|
||||
}
|
||||
|
||||
private Number transformNumber(parser.Number number) @nogc
|
||||
{
|
||||
return defaultAllocator.make!Number(number.value);
|
||||
}
|
||||
|
||||
private Variable binaryExpression(parser.BinaryExpression binaryExpression,
|
||||
ref Array!Statement statements) @nogc
|
||||
ASTMapping.BinaryExpression visit(parser.BinaryExpression binaryExpression) @nogc
|
||||
{
|
||||
auto target = defaultAllocator.make!BinaryExpression(
|
||||
expression(binaryExpression.lhs, statements),
|
||||
expression(binaryExpression.rhs, statements),
|
||||
binaryExpression.lhs.accept(this),
|
||||
binaryExpression.rhs.accept(this),
|
||||
binaryExpression.operator
|
||||
);
|
||||
|
||||
auto newStatement = defaultAllocator.make!Statement;
|
||||
newStatement.expression = target;
|
||||
statements.insertBack(newStatement);
|
||||
statements.insertBack(target);
|
||||
|
||||
auto newVariable = defaultAllocator.make!Variable;
|
||||
newVariable.counter = statements.length;
|
||||
@ -209,38 +235,18 @@ final class TransformVisitor : parser.ParserVisitor!ASTMapping
|
||||
return newVariable;
|
||||
}
|
||||
|
||||
private Expression expression(parser.Expression expression,
|
||||
ref Array!Statement statements) @nogc
|
||||
private Number transformNumber(parser.Number number) @nogc
|
||||
{
|
||||
if ((cast(parser.Number) expression) !is null)
|
||||
{
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = (cast(parser.Number) expression).value;
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
if ((cast(parser.Variable) expression) !is null)
|
||||
{
|
||||
auto numberExpression = defaultAllocator.make!Number;
|
||||
numberExpression.value = this.constants[(cast(parser.Variable) expression).identifier];
|
||||
|
||||
return numberExpression;
|
||||
}
|
||||
else if ((cast(parser.BinaryExpression) expression) !is null)
|
||||
{
|
||||
return binaryExpression(cast(parser.BinaryExpression) expression, statements);
|
||||
}
|
||||
return null;
|
||||
return defaultAllocator.make!Number(number.value);
|
||||
}
|
||||
|
||||
override Array!Statement visit(parser.Statement statement) @nogc
|
||||
override Operand visit(parser.Statement statement) @nogc
|
||||
{
|
||||
typeof(return) statements;
|
||||
if ((cast(parser.BangStatement) statement) !is null)
|
||||
{
|
||||
expression((cast(parser.BangStatement) statement).expression, statements);
|
||||
return (cast(parser.BangStatement) statement).accept(this);
|
||||
}
|
||||
return statements;
|
||||
assert(false, "Invalid statement type");
|
||||
}
|
||||
|
||||
private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
|
||||
|
@ -8,6 +8,7 @@ import std.range;
|
||||
import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
|
||||
extern(C++)
|
||||
struct Token
|
||||
{
|
||||
enum Type
|
||||
@ -71,7 +72,7 @@ struct Token
|
||||
}
|
||||
|
||||
@property auto value(Type type)() @nogc nothrow pure @trusted
|
||||
in (ofType(type))
|
||||
in (ofType(type), "Expected type: " ~ type.stringof)
|
||||
{
|
||||
static if (type == Type.number)
|
||||
{
|
||||
@ -99,14 +100,17 @@ struct Token
|
||||
/**
|
||||
* Range over the source text that keeps track of the current position.
|
||||
*/
|
||||
extern(C++)
|
||||
struct Source
|
||||
{
|
||||
char[] buffer;
|
||||
char* buffer_;
|
||||
size_t length_;
|
||||
Position position;
|
||||
|
||||
this(char[] buffer) @nogc nothrow pure @safe
|
||||
this(char* buffer, const size_t length) @nogc nothrow pure
|
||||
{
|
||||
this.buffer = buffer;
|
||||
this.buffer_ = buffer;
|
||||
this.length_ = length;
|
||||
}
|
||||
|
||||
@disable this();
|
||||
@ -116,54 +120,50 @@ struct Source
|
||||
return this.length == 0;
|
||||
}
|
||||
|
||||
char front() @nogc nothrow pure @safe
|
||||
char front() @nogc nothrow pure
|
||||
in (!empty)
|
||||
{
|
||||
return this.buffer[0];
|
||||
return this.buffer_[0];
|
||||
}
|
||||
|
||||
void popFront() @nogc nothrow pure @safe
|
||||
void popFront() @nogc nothrow pure
|
||||
in (!empty)
|
||||
{
|
||||
this.buffer = buffer[1 .. $];
|
||||
++this.buffer_;
|
||||
--this.length_;
|
||||
++this.position.column;
|
||||
}
|
||||
|
||||
void breakLine() @nogc nothrow pure @safe
|
||||
void breakLine() @nogc nothrow pure
|
||||
in (!empty)
|
||||
{
|
||||
this.buffer = buffer[1 .. $];
|
||||
++this.buffer_;
|
||||
--this.length_;
|
||||
++this.position.line;
|
||||
this.position.column = 1;
|
||||
}
|
||||
|
||||
@property size_t length() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.buffer.length;
|
||||
return this.length_;
|
||||
}
|
||||
|
||||
char opIndex(size_t index) @nogc nothrow pure @safe
|
||||
char opIndex(size_t index) @nogc nothrow pure
|
||||
in (index < length)
|
||||
{
|
||||
return this.buffer[index];
|
||||
return this.buffer_[index];
|
||||
}
|
||||
|
||||
char[] opSlice(size_t i, size_t j) @nogc nothrow pure @safe
|
||||
in
|
||||
char* buffer() @nogc nothrow pure
|
||||
{
|
||||
assert(i <= j);
|
||||
assert(j <= length);
|
||||
}
|
||||
do
|
||||
{
|
||||
return this.buffer[i .. j];
|
||||
return this.buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
Result!(Array!Token) lex(char[] buffer) @nogc
|
||||
{
|
||||
Array!Token tokens;
|
||||
auto source = Source(buffer);
|
||||
auto source = Source(buffer.ptr, buffer.length);
|
||||
|
||||
while (!source.empty)
|
||||
{
|
||||
@ -218,17 +218,17 @@ Result!(Array!Token) lex(char[] buffer) @nogc
|
||||
{
|
||||
++i;
|
||||
}
|
||||
if (source[0 .. i] == "const")
|
||||
if (source.buffer[0 .. i] == "const")
|
||||
{
|
||||
tokens.insertBack(Token(Token.Type.let, source.position));
|
||||
}
|
||||
else if (source[0 .. i] == "var")
|
||||
else if (source.buffer[0 .. i] == "var")
|
||||
{
|
||||
tokens.insertBack(Token(Token.Type.var, source.position));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto identifier = String(source[0 .. i]);
|
||||
auto identifier = String(source.buffer[0 .. i]);
|
||||
tokens.insertBack(Token(Token.Type.identifier, identifier, source.position));
|
||||
}
|
||||
source.popFrontN(i);
|
||||
|
@ -1,5 +1,6 @@
|
||||
module elna.riscv;
|
||||
|
||||
import core.stdc.stdlib;
|
||||
import elna.extended;
|
||||
import elna.ir;
|
||||
import elna.result;
|
||||
@ -7,7 +8,6 @@ import std.algorithm;
|
||||
import std.typecons;
|
||||
import tanya.container.array;
|
||||
import tanya.container.string;
|
||||
import tanya.memory.allocator;
|
||||
|
||||
enum XRegister : ubyte
|
||||
{
|
||||
@ -140,14 +140,14 @@ struct Instruction
|
||||
return this;
|
||||
}
|
||||
|
||||
ref Instruction s(uint imm1, Funct3 funct3, XRegister rs1, XRegister rs2, uint imm2 = 0)
|
||||
ref Instruction s(uint imm1, Funct3 funct3, XRegister rs1, XRegister rs2)
|
||||
return scope @nogc
|
||||
{
|
||||
this.instruction |= (imm1 << 7)
|
||||
this.instruction |= ((imm1 & 0b11111) << 7)
|
||||
| (funct3 << 12)
|
||||
| (rs1 << 15)
|
||||
| (rs2 << 20)
|
||||
| (imm2 << 25);
|
||||
| ((imm1 & 0b111111100000) << 20);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -178,6 +178,7 @@ struct Instruction
|
||||
}
|
||||
}
|
||||
|
||||
extern(C++)
|
||||
class RiscVVisitor : IRVisitor
|
||||
{
|
||||
Array!Instruction instructions;
|
||||
@ -191,22 +192,24 @@ class RiscVVisitor : IRVisitor
|
||||
|
||||
override void visit(Definition definition) @nogc
|
||||
{
|
||||
const uint stackSize = cast(uint) (definition.statements.length * 4 + 12);
|
||||
|
||||
// Prologue.
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.opImm)
|
||||
.i(XRegister.sp, Funct3.addi, XRegister.sp, cast(uint) -32)
|
||||
.i(XRegister.sp, Funct3.addi, XRegister.sp, -stackSize)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.store)
|
||||
.s(28, Funct3.sw, XRegister.sp, XRegister.s0)
|
||||
.s(stackSize - 4, Funct3.sw, XRegister.sp, XRegister.s0)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.store)
|
||||
.s(24, Funct3.sw, XRegister.sp, XRegister.ra)
|
||||
.s(stackSize - 8, Funct3.sw, XRegister.sp, XRegister.ra)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.opImm)
|
||||
.i(XRegister.s0, Funct3.addi, XRegister.sp, 32)
|
||||
.i(XRegister.s0, Funct3.addi, XRegister.sp, stackSize)
|
||||
);
|
||||
|
||||
foreach (statement; definition.statements[])
|
||||
@ -217,6 +220,10 @@ class RiscVVisitor : IRVisitor
|
||||
{
|
||||
variableDeclaration.accept(this);
|
||||
}
|
||||
this.registerInUse = true;
|
||||
definition.result.accept(this);
|
||||
this.registerInUse = false;
|
||||
|
||||
// Print the result.
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.opImm)
|
||||
@ -247,15 +254,15 @@ class RiscVVisitor : IRVisitor
|
||||
// Epilogue.
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.load)
|
||||
.i(XRegister.s0, Funct3.lw, XRegister.sp, 28)
|
||||
.i(XRegister.s0, Funct3.lw, XRegister.sp, stackSize - 4)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.load)
|
||||
.i(XRegister.ra, Funct3.lw, XRegister.sp, 24)
|
||||
.i(XRegister.ra, Funct3.lw, XRegister.sp, stackSize - 8)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.opImm)
|
||||
.i(XRegister.sp, Funct3.addi, XRegister.sp, 32)
|
||||
.i(XRegister.sp, Funct3.addi, XRegister.sp, stackSize)
|
||||
);
|
||||
this.instructions.insertBack(
|
||||
Instruction(BaseOpcode.jalr)
|
||||
@ -263,13 +270,16 @@ class RiscVVisitor : IRVisitor
|
||||
);
|
||||
}
|
||||
|
||||
override void visit(Expression) @nogc
|
||||
override void visit(Operand operand) @nogc
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(Statement statement) @nogc
|
||||
{
|
||||
statement.expression.accept(this);
|
||||
if ((cast(Variable) operand) !is null)
|
||||
{
|
||||
return (cast(Variable) operand).accept(this);
|
||||
}
|
||||
if ((cast(Number) operand) !is null)
|
||||
{
|
||||
return (cast(Number) operand).accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(Variable variable) @nogc
|
||||
@ -334,10 +344,12 @@ Symbol writeNext(Definition ast) @nogc
|
||||
{
|
||||
Array!Instruction instructions;
|
||||
Array!Reference references;
|
||||
auto visitor = defaultAllocator.make!RiscVVisitor;
|
||||
auto visitor = cast(RiscVVisitor) malloc(__traits(classInstanceSize, RiscVVisitor));
|
||||
(cast(void*) visitor)[0 .. __traits(classInstanceSize, RiscVVisitor)] = __traits(initSymbol, RiscVVisitor)[];
|
||||
scope (exit)
|
||||
{
|
||||
defaultAllocator.dispose(visitor);
|
||||
visitor.__xdtor();
|
||||
free(cast(void*) visitor);
|
||||
}
|
||||
visitor.visit(ast);
|
||||
|
||||
|
Reference in New Issue
Block a user