in Jit/lir/parser.cpp [95:321]
std::unique_ptr<Function> Parser::parse(const std::string& code) {
enum {
FUNCTION,
BASIC_BLOCK,
INSTR_OUTPUT,
INSTR_OUTPUT_TYPE,
INSTR_EQUAL,
INSTR_NAME,
INSTR_INPUT,
INSTR_INPUT_TYPE,
INSTR_INPUT_COMMA,
PHI_INPUT_FIRST,
PHI_INPUT_COMMA,
PHI_INPUT_SECOND,
PHI_INPUT_SECOND_TYPE,
PHI_INPUT_PAR,
} state = FUNCTION;
std::unique_ptr<Function> func;
const char* codestr = code.c_str();
const char* cur = codestr;
const char* end = codestr + code.size();
while (cur != end) {
auto token = getNextToken(cur);
auto type = token.type;
while (true) {
if (token.type == kComment) {
// skip comments for now
break;
}
switch (state) {
case FUNCTION: {
// expect a function start
if (type == kNewLine) {
break;
}
expect(type == kFunctionStart, cur, "Expect a function start.");
func = std::make_unique<Function>();
func_ = func.get();
state = BASIC_BLOCK;
break;
}
case BASIC_BLOCK: {
// expect a basic block start
if (type == kNewLine) {
break;
}
expect(type == kBasicBlockStart, cur, "Expect a basic block start.");
int id = token.data;
block_ = func_->allocateBasicBlock();
block_->setId(id);
auto pair = block_index_map_.emplace(id, block_);
expect(pair.second, cur, "Duplicated basic block id.");
setSection(std::string(cur, token.length), block_);
setSuccessorBlocks(std::string(cur, token.length), block_);
state = INSTR_OUTPUT;
break;
}
case INSTR_OUTPUT: {
if (type == kNewLine) {
break;
} else if (type == kBasicBlockStart) {
state = BASIC_BLOCK;
continue;
}
instr_ = block_->allocateInstr(Instruction::kNone, nullptr);
instr_->setId(-1);
auto output = instr_->output();
if (type == kId) {
state = INSTR_NAME;
continue;
} else if (type == kVReg) {
output->setVirtualRegister();
auto pair = output_index_map_.emplace(token.data, instr_);
instr_->setId(token.data);
expect(pair.second, cur, "Duplicated output virtual register.");
} else if (type == kPhyReg) {
output->setPhyRegister(jit::codegen::PhyLocation::parse(
std::string(cur, token.length)));
} else if (type == kStack) {
output->setStackSlot(token.data);
} else if (type == kAddress) {
output->setMemoryAddress(reinterpret_cast<void*>(token.data));
} else if (type == kImmediate) {
output->setConstant(token.data);
} else if (type == kIndirect) {
parseIndirect(output, std::string_view(cur, token.length), cur);
} else {
expect(false, cur);
}
state = INSTR_OUTPUT_TYPE;
break;
}
case INSTR_OUTPUT_TYPE: {
if (type == kEqual) {
state = INSTR_EQUAL;
continue;
}
expect(type == kDataType, cur, "Expect output data type.");
instr_->output()->setDataType(
getOperandDataType(std::string(cur, token.length)));
state = INSTR_EQUAL;
break;
}
case INSTR_EQUAL: {
expect(type == kEqual, cur, "Expect \"=\".");
state = INSTR_NAME;
break;
}
case INSTR_NAME: {
expect(type == kId, cur, "Expect an instruction name.");
instr_->setOpcode(getInstrOpcode(std::string(cur, token.length)));
state = INSTR_INPUT;
break;
}
case INSTR_INPUT: {
if (type == kNewLine) {
state = INSTR_OUTPUT;
break;
}
if (type == kParLeft) {
state = PHI_INPUT_FIRST;
} else {
parseInput(token, cur);
state = INSTR_INPUT_TYPE;
}
break;
}
case INSTR_INPUT_TYPE: {
if (type == kComma || type == kNewLine) {
state = INSTR_INPUT_COMMA;
continue;
}
expect(type == kDataType, cur, "Expect input data type.");
expect(
instr_->getNumInputs() > 0,
cur,
"Expect data type to follow an input.");
OperandBase* input_base =
instr_->getInput(instr_->getNumInputs() - 1);
if (!input_base->isLinked()) {
Operand* input = static_cast<Operand*>(input_base);
auto data_type = getOperandDataType(std::string(cur, token.length));
input->setDataType(data_type);
}
state = INSTR_INPUT_COMMA;
break;
}
case INSTR_INPUT_COMMA: {
// expect commas between inputs
if (type == kNewLine) {
state = INSTR_OUTPUT;
break;
}
expect(type == kComma, cur, "Expect a comma.");
state = INSTR_INPUT;
break;
}
case PHI_INPUT_FIRST: {
// first argument of phi input pairs - basic block id
expect(type == kBasicBlockRef, cur, "Expect a basic block id.");
parseInput(token, cur);
state = PHI_INPUT_COMMA;
break;
}
case PHI_INPUT_COMMA: {
expect(type == kComma, cur, "Expect a comma.");
state = PHI_INPUT_SECOND;
break;
}
case PHI_INPUT_SECOND: {
// second argument of phi input pairs - a variable
parseInput(token, cur);
state = PHI_INPUT_SECOND_TYPE;
break;
}
case PHI_INPUT_SECOND_TYPE: {
if (type == kParRight) {
state = PHI_INPUT_PAR;
continue;
}
expect(type == kDataType, cur, "Expect phi input second data type.");
expect(
instr_->getNumInputs() > 0,
cur,
"Expect data type to follow an input.");
OperandBase* input_base =
instr_->getInput(instr_->getNumInputs() - 1);
if (!input_base->isLinked()) {
Operand* input = static_cast<Operand*>(input_base);
auto data_type = getOperandDataType(std::string(cur, token.length));
input->setDataType(data_type);
}
state = PHI_INPUT_PAR;
break;
}
case PHI_INPUT_PAR: {
// expect a right parenthesis
expect(type == kParRight, cur, "Expect a right parenthesis");
state = INSTR_INPUT_COMMA;
break;
}
}
break;
}
cur += token.length;
// skip whitespaces
while (cur != end && (*cur == ' ' || *cur == '\t')) {
cur++;
}
}
fixOperands();
connectBasicBlocks();
fixUnknownIds();
return func;
}