本文主要是介绍LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
概述
本节将通过一个简单的例子来介绍如何生成llvm IR,以Kaleidoscope IR中的例子为例,我们基于LLVM接口构建一个简单的编译器,实现简单的语句解析并转化为LLVM IR,生成对应的LLVM IR部分,代码如下,文件名为toy.cpp,先给出代码,后面会详细介绍每一步分代码:
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Verifier.h"
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <memory>
#include <string>
#include <vector>using namespace llvm;//===----------------------------------------------------------------------===//
// Lexer
//===----------------------------------------------------------------------===//// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
// of these for known things.
enum Token {tok_eof = -1,// commandstok_def = -2,tok_extern = -3,// primarytok_identifier = -4,tok_number = -5
};static std::string IdentifierStr; // Filled in if tok_identifier
static double NumVal; // Filled in if tok_number/// gettok - Return the next token from standard input.
static int gettok() {static int LastChar = ' ';// Skip any whitespace.while (isspace(LastChar))LastChar = getchar();if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*IdentifierStr = LastChar;while (isalnum((LastChar = getchar())))IdentifierStr += LastChar;if (IdentifierStr == "def")return tok_def;if (IdentifierStr == "extern")return tok_extern;return tok_identifier;}if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+std::string NumStr;do {NumStr += LastChar;LastChar = getchar();} while (isdigit(LastChar) || LastChar == '.');NumVal = strtod(NumStr.c_str(), nullptr);return tok_number;}if (LastChar == '#') {// Comment until end of line.doLastChar = getchar();while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');if (LastChar != EOF)return gettok();}// Check for end of file. Don't eat the EOF.if (LastChar == EOF)return tok_eof;// Otherwise, just return the character as its ascii value.int ThisChar = LastChar;LastChar = getchar();return ThisChar;
}//===----------------------------------------------------------------------===//
// Abstract Syntax Tree (aka Parse Tree)
//===----------------------------------------------------------------------===//namespace {/// ExprAST - Base class for all expression nodes.
class ExprAST {
public:virtual ~ExprAST() = default;virtual Value *codegen() = 0;
};/// NumberExprAST - Expression class for numeric literals like "1.0".
class NumberExprAST : public ExprAST {double Val;public:NumberExprAST(double Val) : Val(Val) {}Value *codegen() override;
};/// VariableExprAST - Expression class for referencing a variable, like "a".
class VariableExprAST : public ExprAST {std::string Name;public:VariableExprAST(const std::string &Name) : Name(Name) {}Value *codegen() override;
};/// BinaryExprAST - Expression class for a binary operator.
class BinaryExprAST : public ExprAST {char Op;std::unique_ptr<ExprAST> LHS, RHS;public:BinaryExprAST(char Op, std::unique_ptr<ExprAST> LHS,std::unique_ptr<ExprAST> RHS): Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}Value *codegen() override;
};/// CallExprAST - Expression class for function calls.
class CallExprAST : public ExprAST {std::string Callee;std::vector<std::unique_ptr<ExprAST>> Args;public:CallExprAST(const std::string &Callee,std::vector<std::unique_ptr<ExprAST>> Args): Callee(Callee), Args(std::move(Args)) {}Value *codegen() override;
};/// PrototypeAST - This class represents the "prototype" for a function,
/// which captures its name, and its argument names (thus implicitly the number
/// of arguments the function takes).
class PrototypeAST {std::string Name;std::vector<std::string> Args;public:PrototypeAST(const std::string &Name, std::vector<std::string> Args): Name(Name), Args(std::move(Args)) {}Function *codegen();const std::string &getName() const { return Name; }
};/// FunctionAST - This class represents a function definition itself.
class FunctionAST {std::unique_ptr<PrototypeAST> Proto;std::unique_ptr<ExprAST> Body;public:FunctionAST(std::unique_ptr<PrototypeAST> Proto,std::unique_ptr<ExprAST> Body): Proto(std::move(Proto)), Body(std::move(Body)) {}Function *codegen();
};} // end anonymous namespace//===----------------------------------------------------------------------===//
// Parser
//===----------------------------------------------------------------------===///// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current
/// token the parser is looking at. getNextToken reads another token from the
/// lexer and updates CurTok with its results.
static int CurTok;
static int getNextToken() { return CurTok = gettok(); }/// BinopPrecedence - This holds the precedence for each binary operator that is
/// defined.
static std::map<char, int> BinopPrecedence;/// GetTokPrecedence - Get the precedence of the pending binary operator token.
static int GetTokPrecedence() {if (!isascii(CurTok))return -1;// Make sure it's a declared binop.int TokPrec = BinopPrecedence[CurTok];if (TokPrec <= 0)return -1;return TokPrec;
}/// LogError* - These are little helper functions for error handling.
std::unique_ptr<ExprAST> LogError(const char *Str) {fprintf(stderr, "Error: %s\n", Str);return nullptr;
}std::unique_ptr<PrototypeAST> LogErrorP(const char *Str) {LogError(Str);return nullptr;
}static std::unique_ptr<ExprAST> ParseExpression();/// numberexpr ::= number
static std::unique_ptr<ExprAST> ParseNumberExpr() {auto Result = std::make_unique<NumberExprAST>(NumVal);getNextToken(); // consume the numberreturn std::move(Result);
}/// parenexpr ::= '(' expression ')'
static std::unique_ptr<ExprAST> ParseParenExpr() {getNextToken(); // eat (.auto V = ParseExpression();if (!V)return nullptr;if (CurTok != ')')return LogError("expected ')'");getNextToken(); // eat ).return V;
}/// identifierexpr
/// ::= identifier
/// ::= identifier '(' expression* ')'
static std::unique_ptr<ExprAST> ParseIdentifierExpr() {std::string IdName = IdentifierStr;getNextToken(); // eat identifier.if (CurTok != '(') // Simple variable ref.return std::make_unique<VariableExprAST>(IdName);// Call.getNextToken(); // eat (std::vector<std::unique_ptr<ExprAST>> Args;if (CurTok != ')') {while (true) {if (auto Arg = ParseExpression())Args.push_back(std::move(Arg));elsereturn nullptr;if (CurTok == ')')break;if (CurTok != ',')return LogError("Expected ')' or ',' in argument list");getNextToken();}}// Eat the ')'.getNextToken();return std::make_unique<CallExprAST>(IdName, std::move(Args));
}/// primary
/// ::= identifierexpr
/// ::= numberexpr
/// ::= parenexpr
static std::unique_ptr<ExprAST> ParsePrimary() {switch (CurTok) {default:return LogError("unknown token when expecting an expression");case tok_identifier:return ParseIdentifierExpr();case tok_number:return ParseNumberExpr();case '(':return ParseParenExpr();}
}/// binoprhs
/// ::= ('+' primary)*
static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,std::unique_ptr<ExprAST> L
这篇关于LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!