forked from DoctorWkt/acwj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcg.c
137 lines (121 loc) · 3.03 KB
/
cg.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "defs.h"
#include "data.h"
#include "decl.h"
// Code generator for x86-64
// Copyright (c) 2019 Warren Toomey, GPL3
// List of available registers
// and their names
static int freereg[4];
static char *reglist[4]= { "%r8", "%r9", "%r10", "%r11" };
// Set all registers as available
void freeall_registers(void)
{
freereg[0]= freereg[1]= freereg[2]= freereg[3]= 1;
}
// Allocate a free register. Return the number of
// the register. Die if no available registers.
static int alloc_register(void)
{
for (int i=0; i<4; i++) {
if (freereg[i]) {
freereg[i]= 0;
return(i);
}
}
fprintf(stderr, "Out of registers!\n");
exit(1);
}
// Return a register to the list of available registers.
// Check to see if it's not already there.
static void free_register(int reg)
{
if (freereg[reg] != 0) {
fprintf(stderr, "Error trying to free register %d\n", reg);
exit(1);
}
freereg[reg]= 1;
}
// Print out the assembly preamble
void cgpreamble()
{
freeall_registers();
fputs(
"\t.text\n"
".LC0:\n"
"\t.string\t\"%d\\n\"\n"
"printint:\n"
"\tpushq\t%rbp\n"
"\tmovq\t%rsp, %rbp\n"
"\tsubq\t$16, %rsp\n"
"\tmovl\t%edi, -4(%rbp)\n"
"\tmovl\t-4(%rbp), %eax\n"
"\tmovl\t%eax, %esi\n"
"\tleaq .LC0(%rip), %rdi\n"
"\tmovl $0, %eax\n"
"\tcall printf@PLT\n"
"\tnop\n"
"\tleave\n"
"\tret\n"
"\n"
"\t.globl\tmain\n"
"\t.type\tmain, @function\n"
"main:\n"
"\tpushq\t%rbp\n"
"\tmovq %rsp, %rbp\n",
Outfile);
}
// Print out the assembly postamble
void cgpostamble()
{
fputs(
"\tmovl $0, %eax\n"
"\tpopq %rbp\n"
"\tret\n",
Outfile);
}
// Load an integer literal value into a register.
// Return the number of the register
int cgload(int value) {
// Get a new register
int r= alloc_register();
// Print out the code to initialise it
fprintf(Outfile, "\tmovq\t$%d, %s\n", value, reglist[r]);
return(r);
}
// Add two registers together and return
// the number of the register with the result
int cgadd(int r1, int r2) {
fprintf(Outfile, "\taddq\t%s, %s\n", reglist[r1], reglist[r2]);
free_register(r1);
return(r2);
}
// Subtract the second register from the first and
// return the number of the register with the result
int cgsub(int r1, int r2) {
fprintf(Outfile, "\tsubq\t%s, %s\n", reglist[r2], reglist[r1]);
free_register(r2);
return(r1);
}
// Multiply two registers together and return
// the number of the register with the result
int cgmul(int r1, int r2) {
fprintf(Outfile, "\timulq\t%s, %s\n", reglist[r1], reglist[r2]);
free_register(r1);
return(r2);
}
// Divide the first register by the second and
// return the number of the register with the result
int cgdiv(int r1, int r2) {
fprintf(Outfile, "\tmovq\t%s,%%rax\n", reglist[r1]);
fprintf(Outfile, "\tcqo\n");
fprintf(Outfile, "\tidivq\t%s\n", reglist[r2]);
fprintf(Outfile, "\tmovq\t%%rax,%s\n", reglist[r1]);
free_register(r2);
return(r1);
}
// Call printint() with the given register
void cgprintint(int r) {
fprintf(Outfile, "\tmovq\t%s, %%rdi\n", reglist[r]);
fprintf(Outfile, "\tcall\tprintint\n");
free_register(r);
}