Code generator converts the intermediate representation of source code into a form that can be readily executed by the machine. A code generator is expected to generate the correct code. Designing of code generator should be done in such a way so that it can be easily implemented, tested and maintained.
The following issue arises during the code generation phase:
- Input to code generator –
The input to code generator is the intermediate code generated by the front end, along with information in the symbol table that determines the run-time addresses of the data-objects denoted by the names in the intermediate representation. Intermediate codes may be represented mostly in quadruples, triples, indirect triples, Postfix notation, syntax trees, DAG’s, etc. The code generation phase just proceeds on an assumption that the input are free from all of syntactic and state semantic errors, the necessary type checking has taken place and the type-conversion operators have been inserted wherever necessary.
- Target program –
The target program is the output of the code generator. The output may be absolute machine language, relocatable machine language, assembly language.
- Absolute machine language as output has advantages that it can be placed in a fixed memory location and can be immediately executed.
- Relocatable machine language as an output allows subprograms and subroutines to be compiled separately. Relocatable object modules can be linked together and loaded by linking loader. But there is added expense of linking and loading.
- Assembly language as output makes the code generation easier. We can generate symbolic instructions and use macro-facilities of assembler in generating code. And we need an additional assembly step after code generation.
- Memory Management –
Mapping the names in the source program to the addresses of data objects is done by the front end and the code generator. A name in the three address statements refers to the symbol table entry for name. Then from the symbol table entry, a relative address can be determined for the name.
- Instruction selection –
Selecting the best instructions will improve the efficiency of the program. It includes the instructions that should be complete and uniform. Instruction speeds and machine idioms also plays a major role when efficiency is considered. But if we do not care about the efficiency of the target program then instruction selection is straight-forward.
For example, the respective three-address statements would be translated into the latter code sequence as shown below:
P:=Q+R S:=P+T MOV Q, R0 ADD R, R0 MOV R0, P MOV P, R0 ADD T, R0 MOV R0, S
Here the fourth statement is redundant as the value of the P is loaded again in that statement that just has been stored in the previous statement. It leads to an inefficient code sequence. A given intermediate representation can be translated into many code sequences, with significant cost differences between the different implementations. A prior knowledge of instruction cost is needed in order to design good sequences, but accurate cost information is difficult to predict.
- Register allocation issues –
Use of registers make the computations faster in comparison to that of memory, so efficient utilization of registers is important. The use of registers are subdivided into two subproblems:
- During Register allocation – we select only those set of variables that will reside in the registers at each point in the program.
- During a subsequent Register assignment phase, the specific register is picked to access the variable.
As the number of variables increases, the optimal assignment of registers to variables becomes difficult. Mathematically, this problem becomes NP-complete. Certain machine requires register pairs consist of an even and next odd-numbered register. For example
M a, b
These types of multiplicative instruction involve register pairs where the multiplicand is an even register and b, the multiplier is the odd register of the even/odd register pair.
- Evaluation order –
The code generator decides the order in which the instruction will be executed. The order of computations affects the efficiency of the target code. Among many computational orders, some will require only fewer registers to hold the intermediate results. However, picking the best order in the general case is a difficult NP-complete problem.
- Approaches to code generation issues: Code generator must always generate the correct code. It is essential because of the number of special cases that a code generator might face. Some of the design goals of code generator are:
- Easily maintainable
Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.
- Code Optimization in Compiler Design
- Intermediate Code Generation in Compiler Design
- Introduction of Object Code in Compiler Design
- Compiler Design | Detection of a Loop in Three Address Code
- Need for Intermediate Code and Code Optimization
- Flex (Fast Lexical Analyzer Generator )
- Three address code in Compiler
- DFA in LEX code which accepts strings ending with 11
- Frequency Reduction in Code Optimization
- Bootstrapping in Compiler Design
- Why FIRST and FOLLOW in Compiler Design?
- Introduction of Compiler Design
- Lex code to count total number of tokens
- Types of Parsers in Compiler Design
- Semantic Analysis in Compiler Design
- Basic Blocks in Compiler Design
- Labeling Algorithm in Compiler Design
- Loop Optimization in Compiler Design
- Error Handling in Compiler Design
- Runtime Environments in Compiler Design
If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to email@example.com. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.