Work on Frontend

This commit is contained in:
Jack Andersen 2015-10-09 13:55:13 -10:00
parent 32bd32b9dd
commit 96b8c4c8d8
3 changed files with 446 additions and 42 deletions

View File

@ -81,19 +81,7 @@ struct IR
OpSwizzle /**< Vector insertion/extraction/swizzling operation */ OpSwizzle /**< Vector insertion/extraction/swizzling operation */
}; };
enum RegType using RegID = int;
{
RegNone,
RegFloat,
RegVec3,
RegVec4
};
struct RegID
{
RegType m_type = RegNone;
unsigned m_idx = 0;
};
struct Instruction struct Instruction
{ {
@ -101,7 +89,7 @@ struct IR
struct struct
{ {
std::vector<RegID> m_callRegs; std::string m_name;
RegID m_target; RegID m_target;
} m_call; } m_call;
@ -111,16 +99,18 @@ struct IR
RegID m_target; RegID m_target;
} m_loadImm; } m_loadImm;
enum ArithmeticOpType
{
ArithmeticOpNone,
ArithmeticOpAdd,
ArithmeticOpSubtract,
ArithmeticOpMultiply,
ArithmeticOpDivide
};
struct struct
{ {
enum ArithmeticOpType ArithmeticOpType m_op = ArithmeticOpNone;
{
ArithmeticOpNone,
ArithmeticOpAdd,
ArithmeticOpSubtract,
ArithmeticOpMultiply,
ArithmeticOpDivide
} m_op = ArithmeticOpNone;
RegID m_a; RegID m_a;
RegID m_b; RegID m_b;
RegID m_target; RegID m_target;
@ -128,16 +118,15 @@ struct IR
struct struct
{ {
RegID m_source; RegID m_reg;
int m_sourceIdxs[4] = {-1}; int m_idxs[4] = {-1};
RegID m_target; RegID m_target;
int m_targetIdxs[4] = {-1};
} m_swizzle; } m_swizzle;
Instruction(OpType type) : m_op(type) {}
}; };
unsigned m_floatRegCount = 0; int m_regCount = 0;
unsigned m_vec3RegCount = 0;
unsigned m_vec4RegCount = 0;
std::vector<Instruction> m_instructions; std::vector<Instruction> m_instructions;
}; };
@ -164,6 +153,17 @@ class Lexer
/* Final lexed root function (IR comes from this) */ /* Final lexed root function (IR comes from this) */
OperationNode* m_root = nullptr; OperationNode* m_root = nullptr;
/* Helper for relinking operator precedence */
static void ReconnectArithmetic(OperationNode* sn, OperationNode** lastSub, OperationNode** newSub);
/* Recursive IR compile funcs */
static void RecursiveFuncCompile(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target);
static void RecursiveGroupCompile(IR& ir, const Lexer::OperationNode* groupNode, IR::RegID target);
static void EmitVec3(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target);
static void EmitVec4(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target);
static void EmitArithmetic(IR& ir, const Lexer::OperationNode* arithNode, IR::RegID target);
static void EmitVectorSwizzle(IR& ir, const Lexer::OperationNode* swizNode, IR::RegID target);
public: public:
void reset(); void reset();
void consumeAllTokens(Parser& parser); void consumeAllTokens(Parser& parser);

View File

@ -1,11 +1,52 @@
#include "HECL/HECL.hpp" #include "HECL/HECL.hpp"
#include "HECL/Frontend.hpp" #include "HECL/Frontend.hpp"
/* Combined lexer and semantic analysis system */
namespace HECL namespace HECL
{ {
namespace Frontend namespace Frontend
{ {
static IR::Instruction::ArithmeticOpType ArithType(int aChar)
{
switch (aChar)
{
case '+':
return IR::Instruction::ArithmeticOpAdd;
case '-':
return IR::Instruction::ArithmeticOpSubtract;
case '*':
return IR::Instruction::ArithmeticOpMultiply;
case '/':
return IR::Instruction::ArithmeticOpDivide;
default:
return IR::Instruction::ArithmeticOpNone;
}
}
void Lexer::ReconnectArithmetic(OperationNode* sn, OperationNode** lastSub, OperationNode** newSub)
{
sn->m_sub = sn->m_prev;
sn->m_prev = nullptr;
sn->m_sub->m_prev = nullptr;
sn->m_sub->m_next = sn->m_next;
sn->m_next = sn->m_next->m_next;
sn->m_sub->m_next->m_prev = sn->m_sub;
sn->m_sub->m_next->m_next = nullptr;
if (*lastSub)
{
(*lastSub)->m_next = sn;
sn->m_prev = *lastSub;
}
*lastSub = sn;
if (!*newSub)
*newSub = sn;
}
void Lexer::reset() void Lexer::reset()
{ {
m_root = nullptr; m_root = nullptr;
@ -237,29 +278,391 @@ void Lexer::consumeAllTokens(Parser& parser)
} }
} }
/* Organize arithmetic usage into tree-hierarchy */
for (Lexer::OperationNode& n : m_pool)
{
if (n.m_tok.m_type == Parser::TokenEvalGroupStart)
{
Lexer::OperationNode* newSub = nullptr;
Lexer::OperationNode* lastSub = nullptr;
for (Lexer::OperationNode* sn = n.m_sub ; sn ; sn = sn->m_next)
{
if (sn->m_tok.m_type == Parser::TokenArithmeticOp)
{
IR::Instruction::ArithmeticOpType op = ArithType(sn->m_tok.m_tokenInt);
if (op == IR::Instruction::ArithmeticOpMultiply ||
op == IR::Instruction::ArithmeticOpDivide)
ReconnectArithmetic(sn, &lastSub, &newSub);
}
}
for (Lexer::OperationNode* sn = n.m_sub ; sn ; sn = sn->m_next)
{
if (sn->m_tok.m_type == Parser::TokenArithmeticOp)
{
IR::Instruction::ArithmeticOpType op = ArithType(sn->m_tok.m_tokenInt);
if (op == IR::Instruction::ArithmeticOpAdd ||
op == IR::Instruction::ArithmeticOpSubtract)
ReconnectArithmetic(sn, &lastSub, &newSub);
}
}
if (newSub)
n.m_sub = newSub;
}
}
/* Done! */ /* Done! */
m_root = firstNode->m_next; m_root = firstNode->m_next;
} }
void Lexer::EmitVec3(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target)
{
/* Optimization case: if empty call, emit zero imm load */
const Lexer::OperationNode* gn = funcNode->m_sub;
if (!gn)
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
ir.m_instructions.back().m_loadImm.m_immVec = {};
return;
}
/* Optimization case: if all numeric literals, emit vector imm load */
bool opt = true;
const Parser::Token* imms[3];
for (int i=0 ; i<3 ; ++i)
{
if (!gn->m_sub || gn->m_sub->m_tok.m_type != Parser::TokenNumLiteral)
{
opt = false;
break;
}
imms[i] = &gn->m_sub->m_tok;
gn = gn->m_next;
}
if (opt)
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
atVec4f& vec = ir.m_instructions.back().m_loadImm.m_immVec;
vec.vec[0] = imms[0]->m_tokenFloat;
vec.vec[1] = imms[1]->m_tokenFloat;
vec.vec[2] = imms[2]->m_tokenFloat;
vec.vec[3] = 0.0;
return;
}
/* Otherwise treat as normal function */
RecursiveFuncCompile(ir, funcNode, target);
}
void Lexer::EmitVec4(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target)
{
/* Optimization case: if empty call, emit zero imm load */
const Lexer::OperationNode* gn = funcNode->m_sub;
if (!gn)
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
ir.m_instructions.back().m_loadImm.m_immVec = {};
return;
}
/* Optimization case: if all numeric literals, emit vector imm load */
bool opt = true;
const Parser::Token* imms[4];
for (int i=0 ; i<4 ; ++i)
{
if (!gn->m_sub || gn->m_sub->m_tok.m_type != Parser::TokenNumLiteral)
{
opt = false;
break;
}
imms[i] = &gn->m_sub->m_tok;
gn = gn->m_next;
}
if (opt)
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
atVec4f& vec = ir.m_instructions.back().m_loadImm.m_immVec;
vec.vec[0] = imms[0]->m_tokenFloat;
vec.vec[1] = imms[1]->m_tokenFloat;
vec.vec[2] = imms[2]->m_tokenFloat;
vec.vec[3] = imms[3]->m_tokenFloat;
return;
}
/* Otherwise treat as normal function */
RecursiveFuncCompile(ir, funcNode, target);
}
void Lexer::EmitArithmetic(IR& ir, const Lexer::OperationNode* arithNode, IR::RegID target)
{
/* Evaluate operands */
atVec4f* opt[2] = {nullptr};
size_t instCount = ir.m_instructions.size();
const Lexer::OperationNode* on = arithNode->m_sub;
IR::RegID tgt = target;
for (int i=0 ; i<2 ; ++i, ++tgt)
{
const Parser::Token& tok = on->m_tok;
switch (tok.m_type)
{
case Parser::TokenFunctionStart:
if (!tok.m_tokenString.compare("vec3"))
EmitVec3(ir, on, tgt);
else if (!tok.m_tokenString.compare("vec4"))
EmitVec4(ir, on, tgt);
else
RecursiveFuncCompile(ir, on, tgt);
break;
case Parser::TokenEvalGroupStart:
RecursiveGroupCompile(ir, on, tgt);
break;
case Parser::TokenNumLiteral:
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_loadImm.m_target = tgt;
inst.m_loadImm.m_immVec.vec[0] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[1] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[2] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[3] = tok.m_tokenFloat;
break;
}
case Parser::TokenVectorSwizzle:
EmitVectorSwizzle(ir, on, tgt);
break;
default:
LogModule.report(LogVisor::FatalError, "invalid lexer node for IR");
break;
};
if (ir.m_instructions.back().m_op == IR::OpLoadImm)
opt[i] = &ir.m_instructions.back().m_loadImm.m_immVec;
on = on->m_next;
}
/* Optimization case: if both operands imm load, pre-evalulate */
if (opt[0] && opt[1] && (ir.m_instructions.size() - instCount == 2))
{
atVec4f eval;
switch (ArithType(arithNode->m_tok.m_tokenInt))
{
case IR::Instruction::ArithmeticOpAdd:
eval.vec[0] = opt[0]->vec[0] + opt[1]->vec[0];
eval.vec[1] = opt[0]->vec[1] + opt[1]->vec[1];
eval.vec[2] = opt[0]->vec[2] + opt[1]->vec[2];
eval.vec[3] = opt[0]->vec[3] + opt[1]->vec[3];
break;
case IR::Instruction::ArithmeticOpSubtract:
eval.vec[0] = opt[0]->vec[0] - opt[1]->vec[0];
eval.vec[1] = opt[0]->vec[1] - opt[1]->vec[1];
eval.vec[2] = opt[0]->vec[2] - opt[1]->vec[2];
eval.vec[3] = opt[0]->vec[3] - opt[1]->vec[3];
break;
case IR::Instruction::ArithmeticOpMultiply:
eval.vec[0] = opt[0]->vec[0] * opt[1]->vec[0];
eval.vec[1] = opt[0]->vec[1] * opt[1]->vec[1];
eval.vec[2] = opt[0]->vec[2] * opt[1]->vec[2];
eval.vec[3] = opt[0]->vec[3] * opt[1]->vec[3];
break;
case IR::Instruction::ArithmeticOpDivide:
eval.vec[0] = opt[0]->vec[0] / opt[1]->vec[0];
eval.vec[1] = opt[0]->vec[1] / opt[1]->vec[1];
eval.vec[2] = opt[0]->vec[2] / opt[1]->vec[2];
eval.vec[3] = opt[0]->vec[3] / opt[1]->vec[3];
break;
default:
LogModule.report(LogVisor::FatalError, "invalid arithmetic type");
break;
}
ir.m_instructions.pop_back();
ir.m_instructions.pop_back();
ir.m_instructions.emplace_back(IR::OpLoadImm);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_loadImm.m_target = target;
inst.m_loadImm.m_immVec = eval;
}
else
{
ir.m_instructions.emplace_back(IR::OpArithmetic);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_arithmetic.m_target = target;
inst.m_arithmetic.m_a = target;
inst.m_arithmetic.m_b = target + 1;
inst.m_arithmetic.m_op = ArithType(arithNode->m_tok.m_tokenInt);
if (tgt > ir.m_regCount)
ir.m_regCount = tgt;
}
}
static int SwizzleCompIdx(char aChar)
{
switch (aChar)
{
case 'x':
case 'r':
return 0;
case 'y':
case 'g':
return 1;
case 'z':
case 'b':
return 2;
case 'w':
case 'a':
return 3;
default:
LogModule.report(LogVisor::FatalError, "invalid swizzle char %c", aChar);
}
return -1;
}
void Lexer::EmitVectorSwizzle(IR& ir, const Lexer::OperationNode* swizNode, IR::RegID target)
{
const std::string& str = swizNode->m_tok.m_tokenString;
if (str.size() != 1 && str.size() != 3 && str.size() != 4)
LogModule.report(LogVisor::FatalError, "%d component swizzles not supported", int(str.size()));
size_t instCount = ir.m_instructions.size();
const Lexer::OperationNode* on = swizNode->m_sub;
const Parser::Token& tok = on->m_tok;
switch (tok.m_type)
{
case Parser::TokenFunctionStart:
if (!tok.m_tokenString.compare("vec3"))
EmitVec3(ir, on, target);
else if (!tok.m_tokenString.compare("vec4"))
EmitVec4(ir, on, target);
else
RecursiveFuncCompile(ir, on, target);
break;
case Parser::TokenEvalGroupStart:
RecursiveGroupCompile(ir, on, target);
break;
case Parser::TokenNumLiteral:
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_loadImm.m_target = target;
inst.m_loadImm.m_immVec.vec[0] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[1] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[2] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[3] = tok.m_tokenFloat;
break;
}
case Parser::TokenVectorSwizzle:
EmitVectorSwizzle(ir, on, target);
break;
default:
LogModule.report(LogVisor::FatalError, "invalid lexer node for IR");
break;
};
/* Optimization case: if operand imm load, pre-evalulate */
if (ir.m_instructions.back().m_op == IR::OpLoadImm && (ir.m_instructions.size() - instCount == 1))
{
atVec4f* opt = &ir.m_instructions.back().m_loadImm.m_immVec;
atVec4f eval;
switch (str.size())
{
case 1:
eval = {opt->vec[SwizzleCompIdx(str[0])]};
break;
case 3:
eval.vec[0] = opt->vec[SwizzleCompIdx(str[0])];
eval.vec[1] = opt->vec[SwizzleCompIdx(str[1])];
eval.vec[2] = opt->vec[SwizzleCompIdx(str[2])];
eval.vec[3] = 0.0;
break;
case 4:
eval.vec[0] = opt->vec[SwizzleCompIdx(str[0])];
eval.vec[1] = opt->vec[SwizzleCompIdx(str[1])];
eval.vec[2] = opt->vec[SwizzleCompIdx(str[2])];
eval.vec[3] = opt->vec[SwizzleCompIdx(str[3])];
break;
default:
break;
}
ir.m_instructions.pop_back();
ir.m_instructions.emplace_back(IR::OpLoadImm);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_loadImm.m_target = target;
inst.m_loadImm.m_immVec = eval;
}
else
{
ir.m_instructions.emplace_back(IR::OpSwizzle);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_swizzle.m_reg = target;
inst.m_swizzle.m_target = target;
for (int i=0 ; i<str.size() ; ++i)
inst.m_swizzle.m_idxs[i] = SwizzleCompIdx(str[i]);
}
}
void Lexer::RecursiveGroupCompile(IR& ir, const Lexer::OperationNode* groupNode, IR::RegID target)
{
IR::RegID tgt = target;
for (const Lexer::OperationNode* sn = groupNode->m_sub ; sn ; sn = sn->m_next, ++tgt)
{
const Parser::Token& tok = sn->m_tok;
switch (tok.m_type)
{
case Parser::TokenFunctionStart:
if (!tok.m_tokenString.compare("vec3"))
EmitVec3(ir, sn, tgt);
else if (!tok.m_tokenString.compare("vec4"))
EmitVec4(ir, sn, tgt);
else
RecursiveFuncCompile(ir, sn, tgt);
break;
case Parser::TokenEvalGroupStart:
RecursiveGroupCompile(ir, sn, tgt);
break;
case Parser::TokenNumLiteral:
{
ir.m_instructions.emplace_back(IR::OpLoadImm);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_loadImm.m_target = tgt;
inst.m_loadImm.m_immVec.vec[0] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[1] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[2] = tok.m_tokenFloat;
inst.m_loadImm.m_immVec.vec[3] = tok.m_tokenFloat;
break;
}
case Parser::TokenArithmeticOp:
EmitArithmetic(ir, sn, tgt);
break;
case Parser::TokenVectorSwizzle:
EmitVectorSwizzle(ir, sn, tgt);
break;
default:
LogModule.report(LogVisor::FatalError, "invalid lexer node for IR");
break;
};
}
if (tgt > ir.m_regCount)
ir.m_regCount = tgt;
}
void Lexer::RecursiveFuncCompile(IR& ir, const Lexer::OperationNode* funcNode, IR::RegID target)
{
IR::RegID tgt = target;
for (const Lexer::OperationNode* gn = funcNode->m_sub ; gn ; gn = gn->m_next, ++tgt)
RecursiveGroupCompile(ir, gn, tgt);
ir.m_instructions.emplace_back(IR::OpCall);
IR::Instruction& inst = ir.m_instructions.back();
inst.m_call.m_name = funcNode->m_tok.m_tokenString;
inst.m_call.m_target = target;
if (tgt > ir.m_regCount)
ir.m_regCount = tgt;
}
IR Lexer::compileIR() const IR Lexer::compileIR() const
{ {
if (!m_root) if (!m_root)
LogModule.report(LogVisor::FatalError, "unable to compile HECL-IR for invalid source"); LogModule.report(LogVisor::FatalError, "unable to compile HECL-IR for invalid source");
IR ir; IR ir;
RecursiveFuncCompile(ir, m_root, 0);
/* Determine maximum float regs */
for (const Lexer::OperationNode& n : m_pool)
{
if (n.m_tok.m_type == Parser::TokenFunctionStart)
{
for (Lexer::OperationNode* sn = n.m_sub ; sn ; sn = sn->m_next)
{
}
}
}
return ir; return ir;
} }

View File

@ -1,6 +1,7 @@
#include "HECL/HECL.hpp" #include "HECL/HECL.hpp"
#include "HECL/Frontend.hpp" #include "HECL/Frontend.hpp"
#include <math.h>
/* Syntatical token parsing system */
namespace HECL namespace HECL
{ {