##LLVM的IR語言 首先來簡單介紹一下llvm使用的IR(intermediate representation)語言。它有許多相似彙編的指令但又有函數的語法,並且提供了一個強大的類型系統。
下面是一段簡單的IR代碼:java
; ModuleID = 'test' define void @main() { entry: %a = call i64 @add(i64 1, i64 2) %b = alloca i64 store i64 %a, i64* %b ret void } define i64 @add(i64, i64) { entry: %2 = alloca i64 store i64 %0, i64* %2 %3 = alloca i64 store i64 %1, i64* %3 %4 = load i64* %2 %5 = load i64* %3 %6 = add i64 %4, %5 ret i64 %6 }
分號;後面的是註釋
%a,%1等以%開頭的能夠當作是個局部的寄存器或局部變量,全局的以@開頭
call指令是調用一個函數,%a = call i64 @add(i64 1, i64 2)
的意思是調用返回值是64位整型的add函數,傳入的參數是64位的1和64位的2,結果保存到%a上,因此%a的類型就是64位整型
%b = alloca i64
的意思是申請棧上的空間存放64位整型,地址保存到%b上,因此%b的類型是64位整型的指針(i64*)
store i64 %a, i64* %b
就是把%a的值保存到%b指向的內存上
load與store相對應,把地址上的數據取出來和存數據
IR的類型很嚴格,並且每條指令的參數前面都要先聲明類型,看起來十分囉嗦。node
使用llc和lli能夠編譯和運行IR程序。llvm有不少工具能夠優化IR代碼,因此咱們但願把自已的語言翻譯成IR再用llvm來優化。把本身的語言翻譯成IR彷佛不比直接翻譯成彙編簡單,幸運的是llvm已經提供了大量api來生成IR。ios
##幾個基本的LLVM API LLVMContext: 線程上下文,通個getGlobalContext得到
Module: 模塊,能夠當作是變量、函數和類型的集合,通常對應一個文件
Function: 函數
Type: 數據類型如i6四、double、i64*、double*等
Value: 能夠當作是個變量如上面的%a、%1等
BasicBlock: 基本塊,如上面的entry,在IR裏類型是label,能夠當作是指令的集合,但必須以return、br等跳轉類指令結束
IRBuilder: 是一個輔助類,提供便捷的api插入指令express
##設計一個簡單的語言 我深受java的影響,因此這裏也採用類C的語法。首先我要實現兩最基本的功能,變量和函數的相關語法。變量的類型有long和double兩種。函數的語法也相似於java,能夠先使用後定義,不能嵌套,提供多值返回。運算表達式和註釋都相似於C,語句結束用分號。就像下面的例子:api
long global_a=1,global_b=2; double global_c=3.14; /* main function is the entry of the program */ void main(){ global_a = global_a + 1; global_c = global_c + global_b; printL(global_a);println(); //print 2 printD(global_c);println(); //print 5.14 long x = 112/3; printL(x);println(); //print 37 double y; [x,y] = test1(); //x=100 y=3.333 [,y] = test2(); //y=3.333 printL(x);println(); printD(y);println(); } //return two values long,double test1(){ return 100,3.333; } //as test1, but another syntax [long a,double b] test2(){ a = 100,b=3.333; return; }
##用flex和bison作語法分析 lex和yacc的實現,不解釋。。。ide
##變量的處理 函數外聲明的是全局變量,函數內聲明的都是局部變量。用Value *var = new GlobalVariable(module,type,false,GlobalValue::ExternalLinkage,initial);
來建立一個全局的變量,用Value *var = irBuilder.CreateAlloca(type);
來建立一個局部變量。不管是全局的仍是局部的,var的類型都是指針型的,因此要用load和store來進行取值和賦值,例如Value *val = irBuilder.CreateLoad(var)
和irBuilder.CreateStore(val,var)
。函數
##函數的處理 下面的幾步能夠建立一個函數:工具
vector<Type*> argTypes; argTypes.push_back(builder.getInt64Ty()); ArrayRef<Type*> argTypesRef(argTypes); FunctionType *funcType = FunctionType::get(builder.getVoidTy(),argTypesRef,false); Function *func = Function::Create(funcType,Function::ExternalLinkage,"funcA",&module);
函數體就是BasicBlock的集合,能夠用BasicBlock *bb = BasicBlock::Create(context,"label1",func)
在函數體的最後建立一個BasicBlock。把IRBuilder的插入點設置成相應BasicBlock,後面用builder建立的指令都會追加到這個BasicBlock裏了。例如:flex
builder.SetInsertPoint(bb); builder.Create......
llvm提供的函數都是單值返回的,這裏使用Struct類型進行封裝來實現多值返回。返回多值的函數,對應llvm裏返回Struct類型的函數,return a,b;
時就進行組裝,[a,b] = func();
時就進行拆解。
定義一個Struct類型:優化
vector<Type*> types; ArrayRef<Type*> typesRef(types); StructType *structType = StructType::create(context,typesRef);
建立Struct和獲取單個元素:
Value *structVar = builder.CreateAlloca(structType); Value *elementPtr = builder.CreateStructGEP(structVar,i); Value *aVal = builder.CreateLoad(elementPtr); builder.CreateStore(bVal,elementPtr);
##完整的代碼 ####token.l
%{ #include "ast.hpp" #include "parser.hpp" extern "C" int yywrap(){} int charno = 1; void saveLocation(){ yylloc.first_line = yylineno; yylloc.first_column = charno; yylloc.last_line = yylineno; charno += yyleng; yylloc.last_column = charno-1; } %} %option yylineno %x CMNT %% [\t ]* {saveLocation();} \n {charno = 1;} \/\/.*\n {charno = 1;} "/*" {saveLocation(); BEGIN CMNT;} <CMNT>. {saveLocation();} <CMNT>\n {charno = 1;} <CMNT>"*/" {saveLocation(); BEGIN INITIAL;} return {saveLocation(); return RETURN;} [a-zA-Z_][a-zA-Z0-9_]* {saveLocation();return IDENT;} [0-9]+\.[0-9]+ {saveLocation();return DOUBLE;} [0-9]+ {saveLocation();return LONG;} [=\(\)\+\-\*\/;\{\},\[\]] {saveLocation();return yytext[0];} . {saveLocation(); return LEX_ERROR;}
####parser.y
%{ #include <stdio.h> #include "ast.hpp" #include "parser.hpp" extern int yylex(); extern int yylineno,charno,yyleng; extern FILE *yyin; extern char *yytext; void yyerror(const char *msg){ cout<<yylineno<<":"<<(charno-yyleng)<<": error: "<<msg<<endl; if(yyin != NULL){ fclose(yyin); } exit(1); } void setLocation(Node *node,YYLTYPE *loc,YYLTYPE *firstLoc,YYLTYPE *lastLoc){ loc->first_line = firstLoc->first_line; loc->first_column = firstLoc->first_column; loc->last_line = lastLoc->last_line; loc->last_column = lastLoc->last_column; if(node != NULL){ node->firstLine = loc->first_line; node->firstColumn = loc->first_column; node->lastLine = loc->last_line; node->lastColumn = loc->last_column; } } void setLocation(Node *node,YYLTYPE *loc){ loc->first_line = yylineno; loc->first_column = charno; loc->last_line = yylineno; loc->last_column = charno-1; if(node != NULL){ node->firstLine = loc->first_line; node->firstColumn = loc->first_line; node->lastLine = loc->last_line; node->lastColumn = loc->last_column; } } %} %error-verbose %debug %union{ int token; Ident *ident; Program *program; Statement *stmt; Expression *expr; VarInit *varInit; SimpleVarDecl *spvarDecl; SimpleStmtList *spstmtList; CallExpr *callExpr; GlobalStatement *globalStmt; vector<Ident*> *identList; vector<Statement*> *stmtList; vector<Expression*> *exprList; vector<VarInit*> *varInitList; vector<SimpleVarDecl*> *spvarDeclList; vector<GlobalStatement*> *globalStmtList; } %token <token> IDENT RETURN LEX_ERROR DOUBLE LONG %type <program> program %type <ident> ident %type <stmt> stmt simple_stmt var_decl var_assi return_stmt %type <expr> expr %type <varInit> var_init %type <spvarDecl> simple_var_decl %type <spstmtList> simple_stmt_list %type <callExpr> call_expr %type <globalStmt> global_stmt func_decl global_var_decl %type <stmtList> stmt_list %type <identList> ident_list ident_list_allow_null %type <exprList> expr_list %type <varInitList> var_init_list %type <spvarDeclList> simple_var_decl_list %type <globalStmtList> global_stmt_list %left '+' '-' %left '*' '/' %nonassoc UMINUS %start program %% program: global_stmt_list {program=new Program(*$1);$$=program;setLocation($$,&@$,&@1,&@1);} ; global_stmt_list: global_stmt {$$=new vector<GlobalStatement*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |global_stmt_list global_stmt {$1->push_back($2);$$=$1;setLocation(NULL,&@$,&@1,&@2);} ; global_stmt: global_var_decl ';' {$$=$1;setLocation($$,&@$,&@1,&@1);} |func_decl {$$=$1;setLocation($$,&@$,&@1,&@1);} ; global_var_decl: ident var_init_list {$$=new GlobalVarDecl(*$1,*$2);setLocation($$,&@$,&@1,&@2);} ; ident: IDENT {$$=new Ident(*(new string(yytext,yyleng)));setLocation($$,&@$,&@1,&@1);} ; var_init_list: var_init {$$=new vector<VarInit*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |var_init_list ',' var_init {$1->push_back($3);$$=$1;setLocation(NULL,&@$,&@1,&@3);} ; var_init: ident {$$=new VarInit(*$1,NULL);setLocation($$,&@$,&@1,&@1);} |ident '=' expr {$$=new VarInit(*$1,$3);setLocation($$,&@$,&@1,&@3);} ; func_decl: ident ident '(' simple_var_decl_list ')' '{' stmt_list '}' {vector<Ident*> *types = new vector<Ident*>();types->push_back($1); $$=new FuncDecl(*types,*$2,*$4,*$7);setLocation($$,&@$,&@1,&@8);} |ident_list ident '(' simple_var_decl_list ')' '{' stmt_list '}' {$$=new FuncDecl(*$1,*$2,*$4,*$7);setLocation($$,&@$,&@1,&@8);} |'[' simple_var_decl_list ']' ident '(' simple_var_decl_list ')' '{' stmt_list '}' {$$=new FuncDecl2(*$2,*$4,*$6,*$9);setLocation($$,&@$,&@1,&@10);} ; simple_var_decl_list: /*blank*/ {$$=new vector<SimpleVarDecl*>();setLocation(NULL,&@$);} |simple_var_decl {$$=new vector<SimpleVarDecl*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |simple_var_decl_list ',' simple_var_decl {$1->push_back($3);$$=$1;setLocation(NULL,&@$,&@1,&@3);} ; simple_var_decl: ident ident {$$=new SimpleVarDecl(*$1,*$2);setLocation($$,&@$,&@1,&@2);} ; ident_list: ident {$$=new vector<Ident*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |ident_list ',' ident {$1->push_back($3);$$=$1;setLocation(NULL,&@$,&@1,&@3);} ; stmt_list: /*blank*/ {$$=new vector<Statement*>();setLocation(NULL,&@$);} |stmt {$$=new vector<Statement*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |stmt_list stmt {$1->push_back($2);$$=$1;setLocation(NULL,&@$,&@1,&@2);} ; stmt: ';' {$$=new NullStmt();setLocation($$,&@$,&@1,&@1);} |var_decl ';' {$$=$1;setLocation($$,&@$,&@1,&@2);} |return_stmt ';' {$$=$1;setLocation($$,&@$,&@1,&@2);} |simple_stmt_list ';' {$$=$1;setLocation($$,&@$,&@1,&@2);} ; var_decl: ident var_init_list {$$=new VarDecl(*$1,*$2);setLocation($$,&@$,&@1,&@2);} ; return_stmt: RETURN expr_list {$$=new ReturnStmt(*$2);setLocation($$,&@$,&@1,&@2);} ; simple_stmt_list: simple_stmt {$$=new SimpleStmtList();$$->add($1);setLocation($$,&@$,&@1,&@1);} |simple_stmt_list ',' simple_stmt {$1->add($3);$$=$1;setLocation($$,&@$,&@1,&@3);} ; simple_stmt: var_assi {$$=$1;setLocation($$,&@$,&@1,&@1);} |expr {$$=new ExprStmt(*$1);setLocation($$,&@$,&@1,&@1);} ; var_assi: ident '=' expr {$$=new VarAssi(*$1,*$3);setLocation($$,&@$,&@1,&@3);} |'[' ident_list_allow_null ']' '=' call_expr {$$=new MultiVarAssi(*$2,*$5);setLocation($$,&@$,&@1,&@5);} ; ident_list_allow_null: /*blank*/ {$$=new vector<Ident*>();$$->push_back(NULL);setLocation(NULL,&@$);} |ident {$$=new vector<Ident*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |ident_list_allow_null ',' ident {$1->push_back($3);$$=$1;setLocation(NULL,&@$,&@1,&@3);} |ident_list_allow_null ',' {$1->push_back(NULL);$$=$1;setLocation(NULL,&@$,&@1,&@2);} ; expr_list: /*blank*/ {$$=new vector<Expression*>();setLocation(NULL,&@$);} |expr {$$=new vector<Expression*>();$$->push_back($1);setLocation(NULL,&@$,&@1,&@1);} |expr_list ',' expr {$1->push_back($3);$$=$1;setLocation(NULL,&@$,&@1,&@3);} ; expr: expr '+' expr {$$=new BinaryExpr(*$1,'+',*$3);setLocation($$,&@$,&@1,&@3);} |expr '-' expr {$$=new BinaryExpr(*$1,'-',*$3);setLocation($$,&@$,&@1,&@3);} |expr '*' expr {$$=new BinaryExpr(*$1,'*',*$3);setLocation($$,&@$,&@1,&@3);} |expr '/' expr {$$=new BinaryExpr(*$1,'/',*$3);setLocation($$,&@$,&@1,&@3);} |'(' expr ')' {$$=$2;setLocation($$,&@$,&@1,&@3);} |'-' expr %prec UMINUS {$$=new PrefixExpr('-',*$2);setLocation($$,&@$,&@1,&@2);} |ident {$$=new IdentExpr(*$1);setLocation($$,&@$,&@1,&@1);} |LONG {$$=new Long(new string(yytext,yyleng));setLocation($$,&@$,&@1,&@1);} |DOUBLE {$$=new Double(new string(yytext,yyleng));setLocation($$,&@$,&@1,&@1);} |call_expr {$$=$1;setLocation($$,&@$,&@1,&@1);} ; call_expr: ident '(' expr_list ')' {$$=new CallExpr(*$1,*$3);setLocation($$,&@$,&@1,&@4);} ;
####ast.hpp #ifndef AST_HPP #define AST_HPP #include <iostream> #include <string> #include <vector> #include <map> #include <llvm/Value.h> #include <llvm/Module.h> #include <llvm/LLVMContext.h> #include <llvm/Type.h> #include <llvm/DerivedTypes.h> #include <llvm/Function.h> #include <llvm/BasicBlock.h> #include <llvm/Argument.h> #include <llvm/Instructions.h> #include <llvm/IRBuilder.h>
using namespace std; using namespace llvm; class AstFunction; class AstContext; class Node; class Program; class SimpleVarDecl; class VarInit; class Ident; class GlobalStatement; class GlobalVarDecl; class FuncDecl; class FuncDecl2; class Statement; class VarDecl; class VarAssi; class MultiVarAssi; class ExprStmt; class SimpleStmtList; class NullStmt; class ReturnStmt; class Expression; class BinaryExpr; class PrefixExpr; class IdentExpr; class CallExpr; class Long; class Double; extern LLVMContext &context; extern IRBuilder<> builder; extern Module module; extern Function *startFunc; extern string errorMsg; extern Program *program; extern Value* createCast(Value *value,Type *type); extern Constant* getInitial(Type *type); extern void throwError(Node *node); extern void throwWarning(Node *node,string msg); extern string getOperatorName(int op); extern string getTypeName(Type *type); class AstFunction{ public: string name; Function *llvmFunction; Type *returnType; bool isReturnSingle; bool isReturnVoid; vector<Type*> returnTypes; vector<Type*> argTypes; int style; vector<Value*> returnVars; AstFunction(string name,Function *llvmFunction,vector<Type*> &returnTypes,vector<Type*> &argTypes,int style=1) :name(name),llvmFunction(llvmFunction),returnTypes(returnTypes),argTypes(argTypes),style(style){ isReturnSingle = (returnTypes.size() == 1); isReturnVoid = (returnTypes.size() == 0); returnType = llvmFunction->getReturnType(); } }; class AstContext{ AstContext *parent; map<string,Type*> typeTable; map<string,AstFunction*> functionTable; map<string,Value*> varTable; public: AstFunction *currentFunc; AstContext(AstContext *parent=NULL):parent(parent){ if(parent != NULL){ currentFunc = parent->currentFunc; }else{ currentFunc = NULL; } } Type* getType(string name); AstFunction* getFunction(string name); Value* getVar(string name); bool addFunction(string name,AstFunction *astFunction); bool addVar(string name,Value *var); bool addType(string name,Type *type); }; class Node{ public: int firstLine; int firstColumn; int lastLine; int lastColumn; }; class Program : public Node{ public: vector<GlobalStatement*> &stmts; Program(vector<GlobalStatement*> &stmts):stmts(stmts){} void codeGen(AstContext &astContext); }; class Ident : public Node{ public: string &str; Ident(string &str):str(str){} operator string(){return str;} }; class VarInit : public Node{ public: Ident &varName; Expression *expr; VarInit(Ident &varName,Expression *expr):varName(varName),expr(expr){} }; class SimpleVarDecl : public Node{ public: Ident &typeName; Ident &varName; SimpleVarDecl(Ident &typeName,Ident &varName) :typeName(typeName),varName(varName){} }; class GlobalStatement : public Node{ public: virtual void declGen(AstContext &astContext)=0; virtual void codeGen(AstContext &astContext)=0; virtual bool isFuncDecl()=0; }; class GlobalVarDecl : public GlobalStatement{ public: Ident &typeName; vector<VarInit*> &varInitList; GlobalVarDecl(Ident &typeName,vector<VarInit*> &varInitList) :typeName(typeName),varInitList(varInitList){} void codeGen(AstContext &astContext); void declGen(AstContext &astContext); bool isFuncDecl(){return false;} }; class FuncDecl : public GlobalStatement{ public: vector<Ident*> &retTypeNameList; Ident &funcName; vector<SimpleVarDecl*> &argDeclList; vector<Statement*> &stmtList; FuncDecl(vector<Ident*> &retTypeNameList,Ident &funcName, vector<SimpleVarDecl*> &argDeclList,vector<Statement*> &stmtList) :retTypeNameList(retTypeNameList),funcName(funcName), argDeclList(argDeclList),stmtList(stmtList){} void declGen(AstContext &astContext); void codeGen(AstContext &astContext); bool isFuncDecl(){return true;}; }; class FuncDecl2 : public GlobalStatement{ public: vector<SimpleVarDecl*> &retDeclList; Ident &funcName; vector<SimpleVarDecl*> &argDeclList; vector<Statement*> &stmts; FuncDecl2(vector<SimpleVarDecl*> &retDeclList,Ident &funcName, vector<SimpleVarDecl*> &argDeclList,vector<Statement*> &stmts) :retDeclList(retDeclList),funcName(funcName), argDeclList(argDeclList),stmts(stmts){} void declGen(AstContext &astContext); void codeGen(AstContext &astContext); bool isFuncDecl(){return true;} }; class Statement : public Node{ public: virtual void codeGen(AstContext &astContext)=0; }; class VarDecl : public Statement{ public: Ident &typeName; vector<VarInit*> &varInitList; VarDecl(Ident &typeName,vector<VarInit*> &varInitList) :typeName(typeName),varInitList(varInitList){} void codeGen(AstContext &astContext); }; class VarAssi : public Statement{ public: Ident &varName; Expression &expr; VarAssi(Ident &varName,Expression &expr):varName(varName),expr(expr){} void codeGen(AstContext &astContext); }; class MultiVarAssi : public Statement{ public: vector<Ident*> &varNameList; CallExpr &callExpr; MultiVarAssi(vector<Ident*> &varNameList,CallExpr &callExpr) :varNameList(varNameList),callExpr(callExpr){} void codeGen(AstContext &astContext); }; class SimpleStmtList : public Statement{ public: vector<Statement*> stmtList; SimpleStmtList(){} void add(Statement *stmt); void codeGen(AstContext &astContext); }; class ExprStmt : public Statement{ public: Expression &expr; ExprStmt(Expression &expr):expr(expr){} void codeGen(AstContext &astContext); }; class NullStmt : public Statement{ public: NullStmt(){} void codeGen(AstContext &astContext){} }; class ReturnStmt : public Statement{ public: vector<Expression*> &exprList; ReturnStmt(vector<Expression*> &exprList):exprList(exprList){} void codeGen(AstContext &astContext); }; class Expression : public Node{ public: virtual Value* codeGen(AstContext &astContext)=0; }; class BinaryExpr : public Expression{ public: Expression &lexpr; Expression &rexpr; int op; BinaryExpr(Expression &lexpr,int op,Expression &rexpr) :lexpr(lexpr),rexpr(rexpr),op(op){} Value* codeGen(AstContext &astContext); }; class PrefixExpr : public Expression{ public: int op; Expression &expr; PrefixExpr(int op,Expression &expr):op(op),expr(expr){} Value* codeGen(AstContext &astContext); }; class IdentExpr : public Expression{ public: Ident &ident; IdentExpr(Ident &ident):ident(ident){} Value* codeGen(AstContext &astContext); operator string(); }; class CallExpr : public Expression{ public: Ident &funcName; vector<Expression*> &exprList; CallExpr(Ident &funcName,vector<Expression*> &exprList) :funcName(funcName),exprList(exprList){} Value* codeGen(AstContext &astContext); vector<Value*> multiCodeGen(AstContext &astContext); }; class Long : public Expression{ public: string *valStr; Long(string *valStr):valStr(valStr){} Value* codeGen(AstContext &astContext); }; class Double : public Expression{ public: string *valStr; Double(string *valStr):valStr(valStr){} Value* codeGen(AstContext &astContext); }; #endif // AST_HPP
####ast.cpp
#include "ast.hpp" void throwError(Node *node){ cout<<node->firstLine<<":"<<node->firstColumn<<": error: "<<errorMsg<<endl; exit(1); } void throwWarning(Node *node,string msg){ cout<<node->firstLine<<":"<<node->firstColumn<<": warning: "<<msg<<endl; } string getOperatorName(int op){ switch(op){ case '+': return "+"; case '-': return "-"; case '*': return "*"; case '/': return "/"; defalut: return "unknow"; } } string getTypeName(Type *type){ if(type->isDoubleTy()){ return "double"; }else if(type->isIntegerTy(64)){ return "long"; }if(type->isVoidTy()){ return "void"; }else{ return "unknow"; } } Value* createCast(Value *value,Type *type){ Type *valType = value->getType(); if(valType == type){ return value; }else if(type->isDoubleTy() && valType->isDoubleTy()){ return value; }else if(type->isIntegerTy(64) && valType->isIntegerTy(64)){ return value; }else if(type->isDoubleTy() && valType->isIntegerTy(64)){ return builder.CreateSIToFP(value,type); }else if(type->isIntegerTy(64) && valType->isDoubleTy()){ return builder.CreateFPToSI(value,type); }else{ errorMsg = "no viable conversion from '"+getTypeName(valType) +"' to '"+getTypeName(type)+"'"; return NULL; } } Constant* getInitial(Type *type){ if(type->isDoubleTy()){ return ConstantFP::get(builder.getDoubleTy(),0); }else if(type->isIntegerTy(64)){ return builder.getInt64(0); }else{ errorMsg = "no initializer for '"+getTypeName(type)+"'"; return NULL; } } Type* AstContext::getType(string name){ Type *type = typeTable[name]; if(type == NULL && parent != NULL){ type = parent->getType(name); } if(type == NULL){ if(name == "void"){ errorMsg = "variable has incomplete type 'void'"; }else{ errorMsg = "undeclared type '"+name+"'"; } } return type; } AstFunction* AstContext::getFunction(string name) throw(string){ AstFunction *function = functionTable[name]; if(function == NULL && parent != NULL){ return parent->getFunction(name); } if(function == NULL){ errorMsg = "undeclared function '"+name+"'"; } return function; } Value* AstContext::getVar(string name){ Value *var = varTable[name]; if(var == NULL && parent != NULL){ return parent->getVar(name); } if(var == NULL){ errorMsg = "undeclared identifier '"+name+"'"; } return var; } bool AstContext::addFunction(string name, AstFunction *function){ if(functionTable[name] != NULL){ errorMsg = "redefine function named '"+name+"'"; return false; } functionTable[name] = function; return true; } bool AstContext::addVar(string name, Value *value){ if(varTable[name] != NULL){ errorMsg = "redefine variable named '"+name+"'"; return false; } varTable[name] = value; return true; } bool AstContext::addType(string name, Type *type){ if(typeTable[name] != NULL){ errorMsg = "redefine type named '"+name+"'"; return false; } typeTable[name] = type; return true; } void Program::codeGen(AstContext &astContext){ for(unsigned i=0; i<stmts.size(); i++){ GlobalStatement *stmt = stmts[i]; stmt->declGen(astContext); } //create init func FunctionType *initFuncType = FunctionType::get(builder.getVoidTy(),false); Function *initFunc = Function::Create(initFuncType,Function::ExternalLinkage,"main",&module); builder.SetInsertPoint(BasicBlock::Create(context,"entry",initFunc)); for(unsigned i=0;i<stmts.size();i++){ GlobalStatement *stmt = stmts[i]; if(!stmt->isFuncDecl()){ stmt->codeGen(astContext); } } AstFunction *mainFunc = astContext.getFunction("main"); if(mainFunc == NULL){ cout<<errorMsg<<endl; }else{ builder.CreateCall(mainFunc->llvmFunction); builder.CreateRetVoid(); } startFunc = initFunc; for(unsigned i = 0; i < stmts.size(); i++){ GlobalStatement *stmt = stmts[i]; if(stmt->isFuncDecl()){ stmt->codeGen(astContext); } } } void GlobalVarDecl::declGen(AstContext &astContext){ Type *type = astContext.getType(typeName); if(type == NULL){ throwError(&typeName); } Constant *initial = getInitial(type); if(initial == NULL){ throwError(this); } for(unsigned i = 0; i < varInitList.size(); i++){ VarInit *varInit = varInitList[i]; Value *var = new GlobalVariable(module,type,false,GlobalValue::ExternalLinkage,initial); astContext.addVar(varInit->varName,var); } } void GlobalVarDecl::codeGen(AstContext &astContext){ Type *type = astContext.getType(typeName); if(type == NULL){ throwError(&typeName); } for(unsigned i = 0; i < varInitList.size(); i++){ VarInit *varInit = varInitList[i]; if(varInit->expr != NULL){ Value *var = astContext.getVar(varInit->varName); Value *v = varInit->expr->codeGen(astContext); v = createCast(v,type); if(v == NULL){ throwError(varInit->expr); } builder.CreateStore(v,var); } } } void FuncDecl::declGen(AstContext &astContext){ vector<Type*> returnTypes; if(retTypeNameList.size() > 1 || retTypeNameList[0]->str != "void"){ for(unsigned i = 0; i < retTypeNameList.size(); i++){ Type *type = astContext.getType(*retTypeNameList[i]); if(type == NULL){ throwError(retTypeNameList[i]); } returnTypes.push_back(type); } } Type *returnType = NULL; if(returnTypes.size() == 0){ returnType = builder.getVoidTy(); }else if(returnTypes.size() == 1){ returnType = returnTypes[0]; }else{ ArrayRef<Type*> typesArray(returnTypes); returnType = StructType::create(context,typesArray); } vector<Type*> argTypes; for(unsigned i = 0; i < argDeclList.size(); i++){ SimpleVarDecl *argDecl = argDeclList[i]; Type *type = astContext.getType(argDecl->typeName); if(type == NULL){ throwError(&argDecl->typeName); } argTypes.push_back(type); } FunctionType *functionType = NULL; if(argTypes.size() == 0){ functionType = FunctionType::get(returnType,false); }else{ ArrayRef<Type*> argTypeArrayRef(argTypes); functionType = FunctionType::get(returnType,argTypeArrayRef,false); } Function *function = Function::Create(functionType,Function::ExternalLinkage,funcName.str+"_sp",&module); AstFunction *astFunction = new AstFunction(funcName,function,returnTypes,argTypes); if(!astContext.addFunction(funcName,astFunction)){ throwError(&funcName); } } void FuncDecl::codeGen(AstContext &astContext){ AstFunction *astFunction = astContext.getFunction(funcName); Function* function = astFunction->llvmFunction; vector<Type*> &argTypes = astFunction->argTypes; vector<Type*> &returnTypes = astFunction->returnTypes; AstContext newContext(&astContext); builder.SetInsertPoint(BasicBlock::Create(context,"entry",function)); unsigned i = 0; for(Function::arg_iterator ai = function->arg_begin();ai != function->arg_end(); ai++,i++){ SimpleVarDecl *argDecl = argDeclList[i]; Value *alloc = builder.CreateAlloca(argTypes[i]); builder.CreateStore(ai,alloc); if(!newContext.addVar(argDecl->varName,alloc)){ throwError(&argDecl->varName); } } newContext.currentFunc = astFunction; for(i = 0; i < stmtList.size(); i++){ stmtList[i]->codeGen(newContext); } if(astFunction->isReturnVoid){ builder.CreateRetVoid(); }else if(astFunction->isReturnSingle){ Value *retVal = getInitial(astFunction->returnType); if(retVal == NULL){ throwError(retTypeNameList[0]); } builder.CreateRet(retVal); }else{ Value *alloc = builder.CreateAlloca(astFunction->returnType); for(i = 0; i < returnTypes.size(); i++){ Value *element = builder.CreateStructGEP(alloc,i); Value *elemVal = getInitial(returnTypes[i]); if(elemVal == NULL){ throwError(retTypeNameList[i]); } builder.CreateStore(elemVal,element); } builder.CreateRet(builder.CreateLoad(alloc)); } } void FuncDecl2::declGen(AstContext &astContext){ vector<Type*> returnTypes; for(unsigned i = 0; i < retDeclList.size(); i++){ SimpleVarDecl *retDecl = retDeclList[i]; Type *type = astContext.getType(retDecl->typeName); if(type == NULL){ throwError(&retDecl->typeName); } returnTypes.push_back(type); } Type *returnType = NULL; if(returnTypes.size() == 0){ returnType = builder.getVoidTy(); }else if(returnTypes.size() == 1){ returnType = returnTypes[0]; }else{ ArrayRef<Type*> typesArray(returnTypes); returnType = StructType::create(context,typesArray); } vector<Type*> argTypes; for(unsigned i = 0; i < argDeclList.size(); i++){ SimpleVarDecl *argDecl = argDeclList[i]; Type *type = astContext.getType(argDecl->typeName); if(type == NULL){ throwError(&argDecl->typeName); } argTypes.push_back(type); } FunctionType *functionType = NULL; if(argTypes.size() == 0){ functionType = FunctionType::get(returnType,false); }else{ ArrayRef<Type*> argTypeArrayRef(argTypes); functionType = FunctionType::get(returnType,argTypeArrayRef,false); } Function *function = Function::Create(functionType,Function::ExternalLinkage,funcName.str+"_sp",&module); AstFunction *astFunction = new AstFunction(funcName,function,returnTypes,argTypes,2); if(!astContext.addFunction(funcName,astFunction)){ throwError(&funcName); } } void FuncDecl2::codeGen(AstContext &astContext){ AstFunction *astFunction = astContext.getFunction(funcName); Function* function = astFunction->llvmFunction; vector<Type*> &argTypes = astFunction->argTypes; vector<Type*> &retTypes = astFunction->returnTypes; AstContext newContext(&astContext); builder.SetInsertPoint(BasicBlock::Create(context,"entry",function)); unsigned i = 0; for(Function::arg_iterator ai = function->arg_begin();ai != function->arg_end(); ai++,i++){ SimpleVarDecl *argDecl = argDeclList[i]; Value *alloc = builder.CreateAlloca(argTypes[i]); builder.CreateStore(ai,alloc); if(!newContext.addVar(argDecl->varName,alloc)){ throwError(&argDecl->varName); } } vector<Value*> retVarList; for(i = 0; i < retDeclList.size(); i++){ SimpleVarDecl *retDecl = retDeclList[i]; Value *alloc = builder.CreateAlloca(retTypes[i]); Value *initial = getInitial(retTypes[i]); if(initial == NULL){ throwError(&retDecl->typeName); } if(!newContext.addVar(retDecl->varName,alloc)){ throwError(&retDecl->varName); } retVarList.push_back(alloc); } astFunction->returnVars = retVarList; newContext.currentFunc = astFunction; for(i = 0; i < stmts.size(); i++){ stmts[i]->codeGen(newContext); } if(astFunction->isReturnVoid){ builder.CreateRetVoid(); }else if(astFunction->isReturnSingle){ builder.CreateRet(builder.CreateLoad(retVarList[0])); }else{ Value *alloc = builder.CreateAlloca(astFunction->returnType); for(i = 0; i < retVarList.size(); i++){ Value *element = builder.CreateStructGEP(alloc,i); builder.CreateStore(builder.CreateLoad(retVarList[i]),element); } builder.CreateRet(builder.CreateLoad(alloc)); } } void VarDecl::codeGen(AstContext &astContext){ Type *type = astContext.getType(typeName); if(type == NULL){ throwError(&typeName); } for(unsigned i = 0; i < varInitList.size(); i++){ VarInit *varInit = varInitList[i]; Value *var = NULL; Value *v = NULL; if(varInit->expr != NULL){ v = varInit->expr->codeGen(astContext); v = createCast(v,type); if(v == NULL){ throwError(varInit->expr); } }else{ v = getInitial(type); if(v == NULL){ throwError(&typeName); } } var = builder.CreateAlloca(type); builder.CreateStore(v,var); if(!astContext.addVar(varInit->varName,var)){ throwError(&varInit->varName); } } } void VarAssi::codeGen(AstContext &astContext){ Value *var = astContext.getVar(varName); if(var == NULL){ throwError(&varName); } Value *value = expr.codeGen(astContext); PointerType *pt = static_cast<PointerType*>(var->getType()); value = createCast(value,pt->getElementType()); if(value == NULL){ throwError(&expr); } builder.CreateStore(value,var); } void MultiVarAssi::codeGen(AstContext &astContext){ vector<Value*> vars; for(unsigned i=0; i < varNameList.size(); i++){ Ident *varName = varNameList[i]; if(varName == NULL){ vars.push_back(NULL); }else{ Value *var = astContext.getVar(*varName); if(var == NULL){ throwError(varName); } vars.push_back(var); } } vector<Value*> values = callExpr.multiCodeGen(astContext); if(values.size() < vars.size()){ errorMsg = "too few values returned from function '"+callExpr.funcName.str+"'"; throwError(&callExpr); } for(unsigned i=0; i < vars.size(); i++){ if(vars[i] == NULL){ continue; } Value *v = values[i]; PointerType *pt = static_cast<PointerType*>(vars[i]->getType()); v = createCast(v,pt->getElementType()); if(v == NULL){ throwError(&callExpr); } builder.CreateStore(v,vars[i]); } } void SimpleStmtList::codeGen(AstContext &astContext){ for(unsigned i = 0; i < stmtList.size(); i++){ stmtList[i]->codeGen(astContext); } } void SimpleStmtList::add(Statement *stmt){ stmtList.push_back(stmt); } void ExprStmt::codeGen(AstContext &astContext){ expr.codeGen(astContext); } void ReturnStmt::codeGen(AstContext &astContext){ AstFunction *currentFunc = astContext.currentFunc; if(currentFunc->style == 1){ vector<Type*> &returnTypes = currentFunc->returnTypes; if(exprList.size() < returnTypes.size()){ errorMsg = "too few values to return in function '"+currentFunc->name+"'"; throwError(this); }else if(exprList.size() > returnTypes.size()){ errorMsg = "too many values to return in function '"+currentFunc->name+"'"; throwError(this); } vector<Value*> exprListValues; for(unsigned i=0; i < exprList.size(); i++){ Expression *expr = exprList[i]; exprListValues.push_back(expr->codeGen(astContext)); } if(returnTypes.size() == 0){ builder.CreateRetVoid(); }else if(returnTypes.size() == 1){ Value *v = createCast(exprListValues[0],returnTypes[0]); if(v == NULL){ throwError(exprList[0]); } builder.CreateRet(v); }else{ Value *alloc = builder.CreateAlloca(currentFunc->returnType); for(unsigned i=0; i < returnTypes.size(); i++){ Value *element = builder.CreateStructGEP(alloc,i); Value *v = createCast(exprListValues[i],returnTypes[i]); if(v == NULL){ throwError(exprList[i]); } builder.CreateStore(v,element); } builder.CreateRet(builder.CreateLoad(alloc)); } }else{ if(exprList.size() > 0){ errorMsg = "needn't declare any expression behind 'return' in style 2 function"; throwError(exprList[0]); } if(currentFunc->isReturnVoid){ builder.CreateRetVoid(); }else if(currentFunc->isReturnSingle){ Value *v = builder.CreateLoad(currentFunc->returnVars[0]); builder.CreateRet(v); }else{ Value *alloc = builder.CreateAlloca(currentFunc->returnType); for(unsigned i = 0; i < currentFunc->returnVars.size(); i++){ Value *element = builder.CreateStructGEP(alloc,i); Value *v = builder.CreateLoad(currentFunc->returnVars[i]); builder.CreateStore(v,element); } builder.CreateRet(builder.CreateLoad(alloc)); } } BasicBlock *anonyBB = BasicBlock::Create(context,"after_return",currentFunc->llvmFunction); builder.SetInsertPoint(anonyBB); } Value* BinaryExpr::codeGen(AstContext &astContext){ Value *lv = lexpr.codeGen(astContext); Value *rv = rexpr.codeGen(astContext); if( (lv->getType()->isDoubleTy() || lv->getType()->isIntegerTy(64)) && (lv->getType()->isDoubleTy() || lv->getType()->isIntegerTy(64)) ){ if(lv->getType()->isDoubleTy()){ rv = createCast(rv,lv->getType()); if(rv == NULL){ throwError(&rexpr); } }else{ lv = createCast(lv,rv->getType()); if(lv == NULL){ throwError(&lexpr); } } if(lv->getType()->isDoubleTy()){ switch(op){ case '+': return builder.CreateFAdd(lv,rv); case '-': return builder.CreateFSub(lv,rv); case '*': return builder.CreateFMul(lv,rv); case '/': return builder.CreateFDiv(lv,rv); default: ; } }else{ switch(op){ case '+': return builder.CreateAdd(lv,rv); case '-': return builder.CreateSub(lv,rv); case '*': return builder.CreateMul(lv,rv); case '/': return builder.CreateSDiv(lv,rv); default: ; } } } errorMsg = "invalid operands to binary expression ("+getTypeName(lv->getType())+ " "+getOperatorName(op)+" "+getTypeName(rv->getType())+")"; throwError(this); } Value* PrefixExpr::codeGen(AstContext &astContext){ Value *val = expr.codeGen(astContext); if(op == '-'){ if(val->getType()->isDoubleTy()){ return builder.CreateFNeg(val); }else if(val->getType()->isIntegerTy(64)){ return builder.CreateNeg(val); } } errorMsg = "invalid argument type '"+getTypeName(val->getType())+ "' to unary '"+getOperatorName(op)+"'expression"; throwError(this); } Value* IdentExpr::codeGen(AstContext &astContext){ Value *var = astContext.getVar(ident); if(var == NULL){ throwError(this); } return builder.CreateLoad(var); } vector<Value*> CallExpr::multiCodeGen(AstContext &astContext){ AstFunction *myfunc = astContext.getFunction(funcName); if(myfunc == NULL){ throwError(this); } vector<Type*> &argTypes = myfunc->argTypes; vector<Value*> exprListValues; for(unsigned i=0; i < exprList.size(); i++){ Expression *expr = exprList[i]; exprListValues.push_back(expr->codeGen(astContext)); } if(exprListValues.size() < argTypes.size()){ errorMsg = "too few arguments to function '"+funcName.str+"''"; throwError(this); }else if(exprListValues.size() > argTypes.size()){ cout<<"too many arguments to function '"<<funcName.str<<"'"<<endl; } Value *callResult = NULL; if(argTypes.size() == 0){ callResult = builder.CreateCall(myfunc->llvmFunction); }else{ vector<Value*> argValues; for(unsigned i=0; i < argTypes.size(); i++){ Value *v = createCast(exprListValues[i],argTypes[i]); if(v == NULL){ throwError(exprList[i]); } argValues.push_back(v); } ArrayRef<Value*> args(argValues); callResult = builder.CreateCall(myfunc->llvmFunction,args); } vector<Value*> resultValues; vector<Type*> &resultTypes = myfunc->returnTypes; if(myfunc->isReturnVoid){ resultValues.push_back(callResult); }else if(myfunc->isReturnSingle){ resultValues.push_back(callResult); }else{ Value *alloc = builder.CreateAlloca(myfunc->returnType); builder.CreateStore(callResult,alloc); for(unsigned i=0; i < resultTypes.size(); i++){ Value *element = builder.CreateStructGEP(alloc,i); resultValues.push_back(builder.CreateLoad(element)); } } return resultValues; } Value* CallExpr::codeGen(AstContext &astContext){ vector<Value*> resultValues = multiCodeGen(astContext); return resultValues[0]; } Value* Long::codeGen(AstContext &astContext){ return builder.getInt64(atol(valStr->c_str())); } Value* Double::codeGen(AstContext &astContext){ return ConstantFP::get(builder.getDoubleTy(),atof(valStr->c_str())); }
####main.cpp
#include <stdio.h> #include <llvm/ExecutionEngine/ExecutionEngine.h> #include <llvm/ExecutionEngine/GenericValue.h> #include <llvm/ExecutionEngine/JIT.h> #include <llvm/Support/TargetSelect.h> #include <llvm/Support/ToolOutputFile.h> #include <llvm/Support/FormattedStream.h> #include <llvm/Support/Host.h> #include <llvm/Support/TargetRegistry.h> #include <llvm/Target/TargetMachine.h> #include <llvm/PassManager.h> #include <llvm/Analysis/Passes.h> #include <llvm/Transforms/Scalar.h> #include <llvm/CodeGen/CommandFlags.h> #include "ast.hpp" #include "parser.hpp" extern int yyparse(); extern void createSystemFunctions(AstContext &astContext); extern FILE *yyin, *yyout; LLVMContext &context = getGlobalContext(); Module module("test",context); IRBuilder<> builder(context); Function *startFunc = NULL; string errorMsg; Program *program = NULL; int main(int argc,char **argv){ bool runJit = false; bool irOutput = false; bool asmOutput = false; bool objOutput = false; TargetMachine::CodeGenFileType outputFileType = TargetMachine::CGFT_Null; char *outputFileName = NULL; int option; while((option = getopt(argc,argv,"o:scS")) != -1){ switch(option){ case 'o': if(outputFileName != NULL){ cout<<"warning: ignoring '-o "<<optarg<<"' because '-o " <<outputFileName<<"' has set before"<<endl; }else{ outputFileName = optarg; } break; case 's': asmOutput = true; break; case 'c': objOutput = true; break; case 'S': irOutput = true; break; default: ; } } if(irOutput){ if(asmOutput){ cout<<"warning: ignoring '-s' because '-S' has set"<<endl; } if(objOutput){ cout<<"warning: ignoring '-c' because '-S' has set"<<endl; } }else if(asmOutput){ if(objOutput){ cout<<"warning: ignoring '-c' because '-s' has set"<<endl; } outputFileType = TargetMachine::CGFT_AssemblyFile; }else if(objOutput){ outputFileType = TargetMachine::CGFT_ObjectFile; }else{ if(outputFileName != NULL){ cout<<"warning: ignoring '-o "<<outputFileName <<"' because '-s' or '-S' or '-c' has not set"<<endl; } runJit = true; } char *inputFileName = NULL; for(;optind < argc; optind++){ if(inputFileName == NULL){ inputFileName = argv[optind]; }else{ cout<<"warning: ignoring input file "<<argv[optind]<<endl; } } if(inputFileName != NULL){ yyin = fopen(inputFileName,"r"); if(yyin == NULL){ cout<<"can not open file '"<<inputFileName<<"'"<<endl; exit(1); } } if(yyin == NULL){ cout<<"input program>>"<<endl; } yyparse(); if(yyin != NULL){ fclose(yyin); } AstContext astContext; astContext.addType("long",builder.getInt64Ty()); astContext.addType("double",builder.getDoubleTy()); astContext.addType("bool",builder.getInt1Ty()); createSystemFunctions(astContext); program->codeGen(astContext); //module.dump();cout<<endl; InitializeNativeTarget(); InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); if(irOutput){ string opFileName; if(outputFileName == NULL){ if(inputFileName == NULL){ opFileName = "temp.ir"; }else{ opFileName = string(basename(inputFileName)) + ".ir"; } }else{ opFileName = outputFileName; } string errorMsg; tool_output_file outputFile(opFileName.c_str(),errorMsg); if(!errorMsg.empty()){ cout<<errorMsg<<endl; return 1; } outputFile.os()<<module; outputFile.keep(); } if(outputFileType != TargetMachine::CGFT_Null){ Triple triple(sys::getDefaultTargetTriple()); string errorMsg; const Target *target = TargetRegistry::lookupTarget(MArch,triple,errorMsg); if(target == NULL){ cout<<errorMsg<<endl; return 1; } TargetOptions targetOptions; TargetMachine *targetMachine = target->createTargetMachine(triple.getTriple(),MCPU,"",targetOptions); string opFileName; if(outputFileName == NULL){ if(inputFileName == NULL){ if(asmOutput){ opFileName = "temp.s"; }else{ opFileName = "temp.o"; } }else{ if(asmOutput){ opFileName = string(basename(inputFileName)) + ".s"; }else{ opFileName = string(basename(inputFileName)) + ".o"; } } }else{ opFileName = outputFileName; } string errorMsg2; tool_output_file *outputFile = new tool_output_file(opFileName.c_str(),errorMsg2); if(!errorMsg2.empty()){ cout<<errorMsg2<<endl; return 1; } PassManager passManager; passManager.add(new DataLayout(&module)); formatted_raw_ostream fos(outputFile->os()); targetMachine->addPassesToEmitFile(passManager,fos,outputFileType); passManager.run(module); outputFile->keep(); } if(runJit){ string errStr; ExecutionEngine *execEngine = EngineBuilder(&module).setErrorStr(&errStr).setEngineKind(EngineKind::JIT).create(); if(execEngine == NULL){ cout<<"Could not create ExecutionEngine: "<<errStr<<endl; exit(1); } vector<GenericValue> argValues; execEngine->runFunction(startFunc,argValues); } return 0; } void createSystemFunctions(AstContext &astContext){ //insert printf func decl vector<Type*> printfFuncArgTypes; printfFuncArgTypes.push_back(builder.getInt8PtrTy()); ArrayRef<Type*> printfFuncArgTypesRef(printfFuncArgTypes); FunctionType *printfFuncType = FunctionType::get(builder.getInt32Ty(),printfFuncArgTypesRef,true); Constant *printfFunc = module.getOrInsertFunction("printf",printfFuncType); vector<Type*> emptyTypes; //create print long func vector<Type*> printfLongFuncArgTypes; printfLongFuncArgTypes.push_back(builder.getInt64Ty()); ArrayRef<Type*> printfLongFuncArgTypesRef(printfLongFuncArgTypes); FunctionType *printfLongFuncType = FunctionType::get(builder.getVoidTy(),printfLongFuncArgTypesRef,false); Function *printfLongFunc = Function::Create(printfLongFuncType,Function::ExternalLinkage,"printL",&module); builder.SetInsertPoint(BasicBlock::Create(context,"entry",printfLongFunc)); Value *longFormat = builder.CreateGlobalStringPtr("%ld"); builder.CreateCall2(printfFunc,longFormat,printfLongFunc->arg_begin()); builder.CreateRetVoid(); AstFunction *printfL = new AstFunction("printL",printfLongFunc,emptyTypes,printfLongFuncArgTypes); //create print double func vector<Type*> printfDoubleFuncArgTypes; printfDoubleFuncArgTypes.push_back(builder.getDoubleTy()); ArrayRef<Type*> printfDoubleFuncArgTypesRef(printfDoubleFuncArgTypes); FunctionType *printfDoubleFuncType = FunctionType::get(builder.getVoidTy(),printfDoubleFuncArgTypesRef,false); Function *printfDoubleFunc = Function::Create(printfDoubleFuncType,Function::ExternalLinkage,"printD",&module); builder.SetInsertPoint(BasicBlock::Create(context,"entry",printfDoubleFunc)); Value *doubleFormat = builder.CreateGlobalStringPtr("%lf"); builder.CreateCall2(printfFunc,doubleFormat,printfDoubleFunc->arg_begin()); builder.CreateRetVoid(); AstFunction *printfD = new AstFunction("printD",printfDoubleFunc,emptyTypes,printfDoubleFuncArgTypes); //create println func FunctionType *printlnFuncType = FunctionType::get(builder.getVoidTy(),false); Function *printlnFunc = Function::Create(printlnFuncType,Function::ExternalLinkage,"println",&module); builder.SetInsertPoint(BasicBlock::Create(context,"entry",printlnFunc)); Value *lnFormat = builder.CreateGlobalStringPtr("\n"); builder.CreateCall(printfFunc,lnFormat); builder.CreateRetVoid(); AstFunction *println = new AstFunction("println",printlnFunc,emptyTypes,emptyTypes); //astContext.addFunction("printf",cast<Function>(printfFunc)); astContext.addFunction("printL",printfL); astContext.addFunction("printD",printfD); astContext.addFunction("println",println); }
相關的命令
bison -d -o parser.cpp parser.y flex -o token.cpp token.l g++ -o toy main.cpp ast.cpp parser.cpp token.cpp -Iinclude -I. `llvm-config --cxxflags --ldflags --libs core jit native all-targets asmparser`
以上llvm的版本是3.2