Code Generation (Compiler)

In computing, code generation is part of the process chain of a compiler and converts intermediate representation of source code into a form (e.g., machine code) that can be readily executed by the target system.

11/10 Warm-up Problem: Define using our shorthand, code(term1 → term2 STAR factor)

- code(term2)
+ push($3)
+ code(factor)
+ pop($5)
+ mult $5, $3
+ mflo $3

lvalue

No better solutions for lvalues.

Generating Code for Print Statement

WLP4 rule: statement → PRINTLN LPAREN expr RPAREN SEMI

Code reuse A compiler mixes the code it outputs with code from runtime environment.

MERL for linking purposes. gcc is only a compiler drivers.

Using print

.import print in prologue to use it. Think of it as a label. Just like any other procedure, call print using the jalr instruction which overwrites register 31.

code(println(expr);) = 
push($1)
+ code(expr)
+ add $1, $3, $0
+ push($31)
+ lis $5 + .word print
+ jalr $5 + pop($31)
+ pop($1)

Control-Flow Statements

Convention: Store 1 inside $11 (For true and false purposes) Now prologue is even longer…

; Prologue
.import print
lis $4
.word 4
lis $10
.word print
list $11
.word 1
sub $29, $30, $4
; end Prologue and begin body
; space for variables
; translated WLP4 code
; end body and begin epilogue
add $30, $29, $4
jr $31

If Statements

Rule: statement → IF (test) (stmts1) ELSE (stmts2) Use labels

11/15 Lecture 18 Warm up Problem Informally how would we generate code for a switch statement?

code(switch (expr){…})

int wain(int *a, int b){
int *c = NULL;
int ret = 0;
c = new int[b];
 
if(c < a){
ret = a - c;
}else{
ret = c - a;
}
return ret;
}

Code generation:

;Prologue
 
; code(c = new int[b])
; code(new int[b])
; code(b)
lw $3, -4($29)
add $1, $3, $0
lis $5
.word new
jalr $5
bne $3, $0, 2
add $3, $11, $0
sw $3, -8($29)
; code(if(T){S1} else {S2})
; code(c - a)
; code(c)
lw $3, -8($29)
; push($3)
sw $3, -4($30)
sub $30, $30, $4 //decrement stack pointer
; code(g)
lw $3, 0($29)
; pop($5)
add $30, $30, $4
lw $5, -4($30)
sltu $3, $5, $3
; if(T) {S1} else {S2}
; code(T)
beq $3, $0, else1
	; code(ret = a -c)
		; code(a - c)
			;code(a)
				lw $3, 0($29)
			;push($3)
				sw $3, -4($30)
				sub $30, $40, $4
			; code(c)
				lw $3, -8($29)
			; pop($5)
				add $30, $30, $4
				lw $5, -4($30)
			sub $3, $5, $3
			div $3, $4
			mflo $3
		sw $3, -12($29)
		beq $0, $0, endIf1
else1:
	; code(ret = c - a)
	lw $3, -8($29)
	sw $3, -4($30)
	sub $30, $30, $4
	lw $3, $3, 0($29)
	add $30, $30, $4
	lw $5, -4($30)
	sub $3, $5, $3
	div $3, $4
	mflo $3
	sw $3, -12($29) 
endIf1:
 
;code(ret)
lw $3, -12($29) 
 
;epilogue

Could optimize when we sw what’s in 29) and lw from -12(3. Print which production rule we are in when debugging.

Procedures

Warm up Problem

11/17/22 Given that NULL is 1 in WLP4, how can we using only WLP4 code cheat and get a pointer to 0 anyways?

int *a = NULL;
int *b = NULL;
int c = 0;
b = 8c;
b = b-(b-a)-1;
*b = 0 + ...;

saving registers and restoring

beq $0, $0, wain
 
Fadd:
;int add(int a, int b){
sub $29, $30, $4 //getting $29
; int c = 0;
; code (int c = 0)
	lis $3
	.word 0
	sw $3, -4($30)
	sub $30, $30, $4
;push registers
; c = a * b;
;code(c = a * b)
	; code (a)
		lw $3, 8($29)
	;push($3)
		sw $3, -4($30)
		sub $30, $30, $4
	;code(b)
		lw $3, 4($29)
	;pop($5)
		add $30, $30, $4
		lw $5, -4($30)
	add $3, $5, $3
sw $3, 0($29)
 
;return c;
;code(c)
	lw $3, 0($29)
;)
;retor registers 
add $30, $29, $4
jr $31
}
 
wain:
;int wain(int a, intb){
sub $29, $30, $4
;prologue: init $4, $10, $11; call init; savge arguments
;	return add(a, b);
; code(add(a,b))
	; push ($29), push($31)
	sw $29, -4($30)
	sub $30, $30, $4
	sw $31, -4($30)
	sub $30, $30, $4
	; code (expr1 -> a)
	lw $3, 0($29)
	; push ($3)
	sw $3, ;04($30)
	sub $30, $30, $4
	;code(expr2 -> b)
	lw $3, -4($29)
	; push($3)
	sw $3, -4($30)
	sub $30, $30, $4
	;...
	lis $5
	.word Fadd
	jalr $5
	; pop arguments
	add $30, $30, $4
	add $30, $30, $4
	;pop($31)
	add $30, $30, $4
	lw $31, -4($30)
	;pop($29)
	add $30, $30, $4
	lw $29, -4($30)
;}
;epilogue unchanged...
jr $31