LLVM platform, in just a few years, changed the direction of many programming languages, but also spawned a large number of features of the emergence of programming language, is worthy of the compiler architecture of the King, also won the 2012 ACM Software System Award-preface
Copyright NOTICE: This article for the West Wind Getaway original article, reproduced please indicate the source westerly world http://blog.csdn.net/xfxyy_sxfancy
function invocation and basic operators
Before we mentioned the definition of a function, how does a well-defined function call it? Today we'll look at the invocation of the function.
Macro form of Function call
Let's read the syntax tree translation of the function call before:
printf("%d\n"y);
Will be translated as:
Node Stringcall String printf String %d\n ID y
The name of this macro is call, which is an indeterminate parameter:
(call 函数名 参数表... )
So we need to scan the parameter table and get all the call parameters.
Basic form of calling macros
Calling a macro is simply a matter of how many parameters can be determined in a continuous loop.
static Value* call_macro(CodeGenContext* context, Node* node) { // 参数一 函数名 // 其余参数 要传入的参数 forNULL; p = p->getNext()) { // 循环获取参数 }}
In addition, we look at the LLVM document, find callinst This instruction, LLVM instructions are derived from instruction, you can find the method is simple:
Create (Value *Func, ArrayRef< Value * > Args, const Twine &NameStr, BasicBlock *InsertAtEnd)
But we found that the value of the transfer is a function object, how to get it? Of course, it is obtained from the symbol table, we will talk about the implementation of the symbol table, this time, as in the previous section, the interface is written first.
// 参数一 函数名 Value*= context->getFunction(node); if==NULL) { <<"找不到函数的定义:"; << node->getStr().<<"\n"; exit(1); }
When a function call is generated, if the function has not been scanned, then the function definition cannot be found at the time of generation, which is why we need to scan multiple times. You can only get the function definitions that follow each function by scanning the syntax tree in sufficient number of times. Although mandatory statements like the C language can be, but I personally do not like this style.
As for the parameter acquisition, it is very simple, but one thing to note is that the parameters are generated recursively, for example:
printf("%d", add(35));
At this point, when we get the parameters, we find that one of the arguments is an expression, then we need to deal with it first:
// 其余参数 要传入的参数 std::vector<Value*> args; for (Node* p = node->getNext(); p != NULL; p = p->getNext()) { // 递归地生成参数 if (v != NULL) args.push_back(v); }
The node class implements the CodeGen method, which functions as a recall of the complete code generation for the current node, facilitating recursive invocation:
Value* Node::codeGen(CodeGenContext* context) { return context->// MacroMake是核心的代码生成接口}
So we generate the code recursively and we can produce a call statement, so don't forget to return it to the previous layer:
Staticvalue* Call_macro (codegencontext* context, node* Node) {//Parameter a function namevalue* func = context->getfunction (node);if(func = = NULL) {errs () <<"The definition of the function could not be found:"; Errs () << node->getstr (). C_STR () <<"\ n";Exit(1); }parameters to pass in///other parameters STD:: vector<Value*>Args for(node* p = node->getnext (); p! = NULL; p = p->getnext ()) {value* v = p->codegen (context);if(v! = NULL) Args.push_back (v); } callinst *call = Callinst::create (func, args,"", Context->getnowblock ());returnCall;}
Simple operator calculation
For computers, subtraction these basic operations are just a few instructions, but there are several things to discuss about the compiler, because all operators have so many:
//Standard binary operators ... First_binary_inst ( 8)Handle_binary_inst ( 8, ADD, Binaryoperator)Handle_binary_inst ( 9, FADD, Binaryoperator)Handle_binary_inst (ten, Sub, Binaryoperator)Handle_binary_inst (One, fsub, Binaryoperator)handle_binary_inst (Mul, Binaryoperator)handle_binary_inst (Fmul, Binaryoperator)handle_binary_inst (UDiv, Binaryoperator)handle_binary_inst (SDiv, Binaryoperator)handle_binary_inst (FDiv, Binaryoperator)handle_binary_inst (urem, Binaryoperator)handle_binary_inst (Srem, Binaryoperator)handle_binary_inst (Frem, Binaryoperator)//Logical operators (integer operands)handle_binary_inst (Shl, Binaryoperator) //Shift Left (logical)handle_binary_inst (lshr, Binaryoperator) //Shift Right (logical)handle_binary_inst (ashr, Binaryoperator) //Shift Right (arithmetic)Handle_binary_inst (all, and, Binaryoperator)Handle_binary_inst (, Or, Binaryoperator)Handle_binary_inst (+, Xor, binaryoperator)
These definitions are hard to find and are not actually written out in the document, but in the header file llvm/IR/Instruction.def
, which is the exclusive part of the macro definition.
These are just numerical operations, not part of the comparison operation.
Of course, this is related to computer architecture, and the operation of floating-point numbers is definitely not the same as integers, and we know that the right shift also counts right shifts and logical right shifts. So inevitably, there will be a lot of different operators.
Creating instructions is simple:
Create (BinaryOps Op, Value *S1, Value *S2, const Twine &Name, BasicBlock *InsertAtEnd)
Two operands, either constant or variable load out value, can also be an expression return value, as long as two value calls GetType, conforming to the rules of operation.
Note that floating-point numbers cannot be directly and integers, and they must first be converted to floating-point.
So here is the simple operator operation, I wrote only the integer operation:
Static Value*Opt2_macro (Codegencontext*Context, Node*node) {STD:: StringOpt=Node -Getstr (); Node*Op1=(node=Node -GetNext ());if(node== NULL)return NULL; Node*Op2=(node=Node -GetNext ());if(node== NULL)return NULL; Instruction:: BinaryopsInStrif(opt== "+") {InStr=Instruction:: Add; Goto Binoper; }if(opt== "-") {InStr=Instruction:: Sub; Goto Binoper; }if(opt== "*") {InStr=Instruction:: Mul; Goto Binoper; }if(opt== "/") {InStr=Instruction:: SDiv; Goto Binoper; }//unknown operator return NULL; Binoper:returnBinaryoperator:: Create(InStr, OP1 -CodeGen (context), OP2 -CodeGen (context),"", context -Getnowblock ());
Attached: document reference and source code
Callinst class Reference
Binaryoperator class Reference
GitHub Source-function calls and basic operators
Copyright NOTICE: This article for the West Wind Getaway original article, reproduced please indicate the source westerly world http://blog.csdn.net/xfxyy_sxfancy
Compiler schema of the King llvm--(8) function call and basic operator