Merge change 6322

* changes:
  Start teaching the code generator about types.
This commit is contained in:
Android (Google) Code Review 2009-07-06 18:42:51 -07:00
commit 1816655869

View file

@ -68,6 +68,8 @@ public:
};
class Compiler : public ErrorSink {
struct Type;
class CodeBuf {
char* ind; // Output code pointer
char* pProgramBase;
@ -157,8 +159,7 @@ class Compiler : public ErrorSink {
* architecture.
*
* The code generator implements the following abstract machine:
* R0 - the main accumulator.
* R1 - the secondary accumulator.
* R0 - the accumulator.
* FP - a frame pointer for accessing function arguments and local
* variables.
* SP - a stack pointer for storing intermediate results while evaluating
@ -168,7 +169,7 @@ class Compiler : public ErrorSink {
* stack such that the first argument has the lowest address.
* After the call, the result is in R0. The caller is responsible for
* removing the arguments from the stack.
* The R0 and R1 registers are not saved across function calls. The
* The R0 register is not saved across function calls. The
* FP and SP registers are saved.
*/
@ -232,41 +233,42 @@ class Compiler : public ErrorSink {
*/
virtual int gtst(bool l, int t) = 0;
/* Compare R1 against R0, and store the boolean result in R0.
/* Compare TOS against R0, and store the boolean result in R0.
* Pops TOS.
* op specifies the comparison.
*/
virtual void gcmp(int op) = 0;
/* Perform the arithmetic op specified by op. R1 is the
/* Perform the arithmetic op specified by op. TOS is the
* left argument, R0 is the right argument.
* Pops TOS.
*/
virtual void genOp(int op) = 0;
/* Set R1 to 0.
/* Compare 0 against R0, and store the boolean result in R0.
* op specifies the comparison.
*/
virtual void clearR1() = 0;
virtual void gUnaryCmp(int op) = 0;
/* Perform the arithmetic op specified by op. 0 is the
* left argument, R0 is the right argument.
*/
virtual void genUnaryOp(int op) = 0;
/* Push R0 onto the stack.
*/
virtual void pushR0() = 0;
/* Pop R1 off of the stack.
/* Store R0 to the address stored in TOS.
* The TOS is popped.
* pPointerType is the type of the pointer (of the input R0).
*/
virtual void popR1() = 0;
/* Store R0 to the address stored in R1.
* isInt is true if a whole 4-byte integer value
* should be stored, otherwise a 1-byte character
* value should be stored.
*/
virtual void storeR0ToR1(bool isInt) = 0;
virtual void storeR0ToTOS(Type* pPointerType) = 0;
/* Load R0 from the address stored in R0.
* isInt is true if a whole 4-byte integer value
* should be loaded, otherwise a 1-byte character
* value should be loaded.
* pPointerType is the type of the pointer (of the input R0).
*/
virtual void loadR0FromR0(bool isInt) = 0;
virtual void loadR0FromR0(Type* pPointerType) = 0;
/* Load the absolute address of a variable to R0.
* If ea <= LOCAL, then this is a local variable, or an
@ -362,6 +364,16 @@ class Compiler : public ErrorSink {
*/
virtual int jumpOffset() = 0;
/**
* Stack alignment (in bytes) for this type of data
*/
virtual size_t stackAlignment(Type* type) = 0;
/**
* Array element alignment (in bytes) for this type of data.
*/
virtual size_t sizeOf(Type* type) = 0;
protected:
/*
* Output a byte. Handles all values, 0..ff.
@ -392,6 +404,12 @@ class Compiler : public ErrorSink {
mErrorSink->verror(fmt, ap);
va_end(ap);
}
void assert(bool test) {
if (!test) {
error("code generator assertion failed.");
}
}
private:
CodeBuf* pCodeBuf;
ErrorSink* mErrorSink;
@ -489,6 +507,8 @@ class Compiler : public ErrorSink {
virtual void gcmp(int op) {
LOG_API("gcmp(%d);\n", op);
o4(0xE8BD0002); // ldmfd sp!,{r1}
mStackUse -= 4;
o4(0xE1510000); // cmp r1, r1
switch(op) {
case OP_EQUALS:
@ -523,6 +543,8 @@ class Compiler : public ErrorSink {
virtual void genOp(int op) {
LOG_API("genOp(%d);\n", op);
o4(0xE8BD0002); // ldmfd sp!,{r1}
mStackUse -= 4;
switch(op) {
case OP_MUL:
o4(0x0E0000091); // mul r0,r1,r0
@ -563,9 +585,38 @@ class Compiler : public ErrorSink {
}
}
virtual void clearR1() {
LOG_API("clearR1();\n");
virtual void gUnaryCmp(int op) {
LOG_API("gcmp(%d);\n", op);
o4(0xE3A01000); // mov r1, #0
o4(0xE1510000); // cmp r1, r1
switch(op) {
case OP_NOT_EQUALS:
o4(0x03A00000); // moveq r0,#0
o4(0x13A00001); // movne r0,#1
break;
default:
error("Unknown unary comparison op %d", op);
break;
}
}
virtual void genUnaryOp(int op) {
LOG_API("genOp(%d);\n", op);
switch(op) {
case OP_PLUS:
// Do nothing
break;
case OP_MINUS:
o4(0xE3A01000); // mov r1, #0
o4(0xE0410000); // sub r0,r1,r0
break;
case OP_BIT_NOT:
o4(0xE1E00000); // mvn r0, r0
break;
default:
error("Unknown unary op %d\n", op);
break;
}
}
virtual void pushR0() {
@ -575,28 +626,38 @@ class Compiler : public ErrorSink {
LOG_STACK("pushR0: %d\n", mStackUse);
}
virtual void popR1() {
LOG_API("popR1();\n");
virtual void storeR0ToTOS(Type* pPointerType) {
LOG_API("storeR0ToTOS(%d);\n", isInt);
assert(pPointerType->tag == TY_POINTER);
o4(0xE8BD0002); // ldmfd sp!,{r1}
mStackUse -= 4;
LOG_STACK("popR1: %d\n", mStackUse);
}
virtual void storeR0ToR1(bool isInt) {
LOG_API("storeR0ToR1(%d);\n", isInt);
if (isInt) {
o4(0xE5810000); // str r0, [r1]
} else {
o4(0xE5C10000); // strb r0, [r1]
switch (pPointerType->pHead->tag) {
case TY_INT:
o4(0xE5810000); // str r0, [r1]
break;
case TY_CHAR:
o4(0xE5C10000); // strb r0, [r1]
break;
default:
assert(false);
break;
}
}
virtual void loadR0FromR0(bool isInt) {
LOG_API("loadR0FromR0(%d);\n", isInt);
if (isInt)
o4(0xE5900000); // ldr r0, [r0]
else
o4(0xE5D00000); // ldrb r0, [r0]
virtual void loadR0FromR0(Type* pPointerType) {
LOG_API("loadR0FromR0(%d);\n", pPointerType);
assert(pPointerType->tag == TY_POINTER);
switch (pPointerType->pHead->tag) {
case TY_INT:
o4(0xE5900000); // ldr r0, [r0]
break;
case TY_CHAR:
o4(0xE5D00000); // ldrb r0, [r0]
break;
default:
assert(false);
break;
}
}
virtual void leaR0(int ea) {
@ -834,6 +895,37 @@ class Compiler : public ErrorSink {
return 0;
}
/**
* Stack alignment (in bytes) for this type of data
*/
virtual size_t stackAlignment(Type* pType){
switch(pType->tag) {
case TY_DOUBLE:
return 8;
default:
return 4;
}
}
/**
* Array element alignment (in bytes) for this type of data.
*/
virtual size_t sizeOf(Type* pType){
switch(pType->tag) {
case TY_INT:
return 4;
case TY_CHAR:
return 1;
default:
return 0;
case TY_FLOAT:
return 4;
case TY_DOUBLE:
return 8;
case TY_POINTER:
return 4;
}
}
private:
static FILE* disasmOut;
@ -937,6 +1029,7 @@ class Compiler : public ErrorSink {
virtual void gcmp(int op) {
int t = decodeOp(op);
o(0x59); /* pop %ecx */
o(0xc139); /* cmp %eax,%ecx */
li(0);
o(0x0f); /* setxx %al */
@ -945,32 +1038,60 @@ class Compiler : public ErrorSink {
}
virtual void genOp(int op) {
o(0x59); /* pop %ecx */
o(decodeOp(op));
if (op == OP_MOD)
o(0x92); /* xchg %edx, %eax */
}
virtual void clearR1() {
virtual void gUnaryCmp(int op) {
oad(0xb9, 0); /* movl $0, %ecx */
int t = decodeOp(op);
o(0xc139); /* cmp %eax,%ecx */
li(0);
o(0x0f); /* setxx %al */
o(t + 0x90);
o(0xc0);
}
virtual void genUnaryOp(int op) {
oad(0xb9, 0); /* movl $0, %ecx */
o(decodeOp(op));
}
virtual void pushR0() {
o(0x50); /* push %eax */
}
virtual void popR1() {
virtual void storeR0ToTOS(Type* pPointerType) {
assert(pPointerType->tag == TY_POINTER);
o(0x59); /* pop %ecx */
switch (pPointerType->pHead->tag) {
case TY_INT:
o(0x0189); /* movl %eax/%al, (%ecx) */
break;
case TY_CHAR:
o(0x0188); /* movl %eax/%al, (%ecx) */
break;
default:
assert(false);
break;
}
}
virtual void storeR0ToR1(bool isInt) {
o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
}
virtual void loadR0FromR0(bool isInt) {
if (isInt)
o(0x8b); /* mov (%eax), %eax */
else
o(0xbe0f); /* movsbl (%eax), %eax */
virtual void loadR0FromR0(Type* pPointerType) {
assert(pPointerType->tag == TY_POINTER);
switch (pPointerType->pHead->tag) {
case TY_INT:
o(0x8b); /* mov (%eax), %eax */
break;
case TY_CHAR:
o(0xbe0f); /* movsbl (%eax), %eax */
break;
default:
assert(false);
break;
}
ob(0); /* add zero in code */
}
@ -1055,6 +1176,38 @@ class Compiler : public ErrorSink {
return err;
}
/**
* Stack alignment (in bytes) for this type of data
*/
virtual size_t stackAlignment(Type* pType){
switch(pType->tag) {
case TY_DOUBLE:
return 8;
default:
return 4;
}
}
/**
* Array element alignment (in bytes) for this type of data.
*/
virtual size_t sizeOf(Type* pType){
switch(pType->tag) {
case TY_INT:
return 4;
case TY_CHAR:
return 1;
default:
return 0;
case TY_FLOAT:
return 4;
case TY_DOUBLE:
return 8;
case TY_POINTER:
return 4;
}
}
private:
/** Output 1 to 4 bytes.
@ -1166,9 +1319,15 @@ class Compiler : public ErrorSink {
mpBase->genOp(op);
}
virtual void clearR1() {
fprintf(stderr, "clearR1()\n");
mpBase->clearR1();
virtual void gUnaryCmp(int op) {
fprintf(stderr, "gUnaryCmp(%d)\n", op);
mpBase->gUnaryCmp(op);
}
virtual void genUnaryOp(int op) {
fprintf(stderr, "genUnaryOp(%d)\n", op);
mpBase->genUnaryOp(op);
}
virtual void pushR0() {
@ -1176,19 +1335,14 @@ class Compiler : public ErrorSink {
mpBase->pushR0();
}
virtual void popR1() {
fprintf(stderr, "popR1()\n");
mpBase->popR1();
virtual void storeR0ToTOS(Type* pPointerType) {
fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType);
mpBase->storeR0ToTOS(pPointerType);
}
virtual void storeR0ToR1(bool isInt) {
fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
mpBase->storeR0ToR1(isInt);
}
virtual void loadR0FromR0(bool isInt) {
fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
mpBase->loadR0FromR0(isInt);
virtual void loadR0FromR0(Type* pPointerType) {
fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType);
mpBase->loadR0FromR0(pPointerType);
}
virtual void leaR0(int ea) {
@ -1262,6 +1416,20 @@ class Compiler : public ErrorSink {
fprintf(stderr, "finishCompile() = %d\n", result);
return result;
}
/**
* Stack alignment (in bytes) for this type of data
*/
virtual size_t stackAlignment(Type* pType){
return mpBase->stackAlignment(pType);
}
/**
* Array element alignment (in bytes) for this type of data.
*/
virtual size_t sizeOf(Type* pType){
return mpBase->sizeOf(pType);
}
};
#endif // PROVIDE_TRACE_CODEGEN
@ -1760,8 +1928,6 @@ class Compiler : public ErrorSink {
int oldCh;
};
struct Type;
struct VariableInfo {
void* pAddress;
void* pForward; // For a forward direction, linked list of data to fix up
@ -1876,9 +2042,9 @@ class Compiler : public ErrorSink {
SymbolStack mLocals;
// Prebuilt types, makes things slightly faster.
Type* mkpInt;
Type* mkpChar;
Type* mkpVoid;
Type* mkpInt; // int
Type* mkpChar; // char
Type* mkpVoid; // void
Type* mkpFloat;
Type* mkpDouble;
Type* mkpIntPtr;
@ -2381,11 +2547,10 @@ class Compiler : public ErrorSink {
} else if (c == 2) {
/* -, +, !, ~ */
unary(false);
pGen->clearR1();
if (t == '!')
pGen->gcmp(a);
pGen->gUnaryCmp(a);
else
pGen->genOp(a);
pGen->genUnaryOp(a);
} else if (t == '(') {
expr();
skip(')');
@ -2415,10 +2580,9 @@ class Compiler : public ErrorSink {
if (accept('=')) {
pGen->pushR0();
expr();
pGen->popR1();
pGen->storeR0ToR1(t == TOK_INT);
pGen->storeR0ToTOS(pCast);
} else if (t) {
pGen->loadR0FromR0(t == TOK_INT);
pGen->loadR0FromR0(pCast);
}
// Else we fall through to the function call below, with
// t == 0 to trigger an indirect function call. Hack!
@ -2515,7 +2679,6 @@ class Compiler : public ErrorSink {
} else {
pGen->pushR0();
binaryOp(level);
pGen->popR1();
if ((level == 4) | (level == 5)) {
pGen->gcmp(t);
@ -2958,6 +3121,7 @@ class Compiler : public ErrorSink {
}
int variableAddress = 0;
addLocalSymbol(pDecl);
loc = loc + pGen->sizeOf(pDecl);
loc = loc + 4;
variableAddress = -loc;
VI(pDecl->id)->pAddress = (void*) variableAddress;