summaryrefslogtreecommitdiffstats
path: root/libacc/acc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libacc/acc.cpp')
-rw-r--r--libacc/acc.cpp211
1 files changed, 175 insertions, 36 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 313bf1c..0a16489 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -139,16 +139,17 @@ class Compiler : public ErrorSink {
TY_VOID, // 3
TY_FLOAT, // 4
TY_DOUBLE, // 5
- TY_POINTER, // 6
- TY_ARRAY, // 7
- TY_STRUCT, // 8
- TY_FUNC, // 9
- TY_PARAM // 10
+ TY_POINTER, // 6
+ TY_ARRAY, // 7
+ TY_STRUCT, // 8
+ TY_FUNC, // 9
+ TY_PARAM // 10
};
struct Type {
TypeTag tag;
- tokenid_t id; // For function arguments (stores length for array)
+ tokenid_t id; // For function arguments, local vars
+ int length; // length of array
Type* pHead;
Type* pTail;
};
@@ -405,7 +406,16 @@ class Compiler : public ErrorSink {
/**
* Convert R0 to the given type.
*/
- virtual void convertR0(Type* pType) = 0;
+
+ void convertR0(Type* pType) {
+ convertR0Imp(pType, false);
+ }
+
+ void castR0(Type* pType) {
+ convertR0Imp(pType, true);
+ }
+
+ virtual void convertR0Imp(Type* pType, bool isCast) = 0;
/* Emit code to adjust the stack for a function call. Return the
* label for the address of the instruction that adjusts the
@@ -622,14 +632,40 @@ class Compiler : public ErrorSink {
return collapseType(getR0Type()->tag);
}
- bool isFloatType(Type* pType) {
+ static bool isFloatType(Type* pType) {
return isFloatTag(pType->tag);
}
- bool isFloatTag(TypeTag tag) {
+ static bool isFloatTag(TypeTag tag) {
return tag == TY_FLOAT || tag == TY_DOUBLE;
}
+ static bool isPointerType(Type* pType) {
+ return isPointerTag(pType->tag);
+ }
+
+ static bool isPointerTag(TypeTag tag) {
+ return tag == TY_POINTER || tag == TY_ARRAY;
+ }
+
+ Type* getPointerArithmeticResultType(Type* a, Type* b) {
+ TypeTag aTag = a->tag;
+ TypeTag bTag = b->tag;
+ if (aTag == TY_POINTER) {
+ return a;
+ }
+ if (bTag == TY_POINTER) {
+ return b;
+ }
+ if (aTag == TY_ARRAY) {
+ return a->pTail;
+ }
+ if (bTag == TY_ARRAY) {
+ return b->pTail;
+ }
+ return NULL;
+ }
+
Type* mkpInt;
private:
@@ -848,8 +884,8 @@ class Compiler : public ErrorSink {
bool isFloatTOS = isFloatTag(tagTOS);
if (!isFloatR0 && !isFloatTOS) {
setupIntPtrArgs();
- bool isPtrR0 = tagR0 == TY_POINTER;
- bool isPtrTOS = tagTOS == TY_POINTER;
+ bool isPtrR0 = isPointerTag(tagR0);
+ bool isPtrTOS = isPointerTag(tagTOS);
if (isPtrR0 || isPtrTOS) {
if (isPtrR0 && isPtrTOS) {
if (op != OP_MINUS) {
@@ -871,7 +907,8 @@ class Compiler : public ErrorSink {
if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
error("Unsupported pointer-scalar operation %d", op);
}
- Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
+ Type* pPtrType = getPointerArithmeticResultType(
+ pR0Type, pTOSType);
int size = sizeOf(pPtrType->pHead);
if (size != 1) {
// TODO: Optimize for power-of-two.
@@ -1131,7 +1168,8 @@ class Compiler : public ErrorSink {
virtual void loadR0FromR0() {
Type* pPointerType = getR0Type();
assert(pPointerType->tag == TY_POINTER);
- switch (pPointerType->pHead->tag) {
+ TypeTag tag = pPointerType->pHead->tag;
+ switch (tag) {
case TY_POINTER:
case TY_INT:
case TY_FLOAT:
@@ -1147,7 +1185,7 @@ class Compiler : public ErrorSink {
o4(0xE1C000D0); // ldrd r0, [r0]
break;
default:
- error("loadR0FromR0: unimplemented type");
+ error("loadR0FromR0: unimplemented type %d", tag);
break;
}
setR0Type(pPointerType->pHead);
@@ -1197,9 +1235,27 @@ class Compiler : public ErrorSink {
return result;
}
- virtual void convertR0(Type* pType){
+ virtual void convertR0Imp(Type* pType, bool isCast){
Type* pR0Type = getR0Type();
- if (bitsSame(pType, pR0Type)) {
+ if (isPointerType(pType) && isPointerType(pR0Type)) {
+ Type* pA = pR0Type;
+ Type* pB = pType;
+ // Array decays to pointer
+ if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
+ pA = pA->pTail;
+ }
+ if (typeEqual(pA, pB)) {
+ return; // OK
+ }
+ if (pB->pHead->tag == TY_VOID) {
+ return; // convert to void* is OK.
+ }
+ if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
+ && isCast) {
+ return; // OK
+ }
+ error("Incompatible pointer or array types");
+ } else if (bitsSame(pType, pR0Type)) {
// do nothing special
} else {
TypeTag r0Tag = collapseType(pR0Type->tag);
@@ -1423,14 +1479,17 @@ class Compiler : public ErrorSink {
return 2;
case TY_CHAR:
return 1;
- default:
- return 0;
case TY_FLOAT:
return 4;
case TY_DOUBLE:
return 8;
case TY_POINTER:
return 4;
+ case TY_ARRAY:
+ return pType->length * sizeOf(pType->pHead);
+ default:
+ error("Unsupported type %d", pType->tag);
+ return 0;
}
}
@@ -1438,6 +1497,8 @@ class Compiler : public ErrorSink {
switch(pType->tag) {
case TY_DOUBLE:
return 8;
+ case TY_ARRAY:
+ return stackAlignmentOf(pType->pHead);
default:
return 4;
}
@@ -1447,6 +1508,11 @@ class Compiler : public ErrorSink {
switch(pType->tag) {
case TY_DOUBLE:
return 8;
+ case TY_ARRAY:
+ return sizeOf(pType);
+ case TY_FUNC:
+ error("stackSizeOf func not supported");
+ return 4;
default:
return 4;
}
@@ -1911,8 +1977,8 @@ class Compiler : public ErrorSink {
bool isFloatR0 = isFloatTag(tagR0);
bool isFloatTOS = isFloatTag(tagTOS);
if (!isFloatR0 && !isFloatTOS) {
- bool isPtrR0 = tagR0 == TY_POINTER;
- bool isPtrTOS = tagTOS == TY_POINTER;
+ bool isPtrR0 = isPointerTag(tagR0);
+ bool isPtrTOS = isPointerTag(tagTOS);
if (isPtrR0 || isPtrTOS) {
if (isPtrR0 && isPtrTOS) {
if (op != OP_MINUS) {
@@ -1936,7 +2002,8 @@ class Compiler : public ErrorSink {
if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
error("Unsupported pointer-scalar operation %d", op);
}
- Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
+ Type* pPtrType = getPointerArithmeticResultType(
+ pR0Type, pTOSType);
o(0x59); /* pop %ecx */
int size = sizeOf(pPtrType->pHead);
if (size != 1) {
@@ -2146,7 +2213,8 @@ class Compiler : public ErrorSink {
virtual void loadR0FromR0() {
Type* pPointerType = getR0Type();
assert(pPointerType->tag == TY_POINTER);
- switch (pPointerType->pHead->tag) {
+ TypeTag tag = pPointerType->pHead->tag;
+ switch (tag) {
case TY_POINTER:
case TY_INT:
o2(0x008b); /* mov (%eax), %eax */
@@ -2166,7 +2234,7 @@ class Compiler : public ErrorSink {
o2(0x00dd); // fldl (%eax)
break;
default:
- error("loadR0FromR0: unsupported type");
+ error("loadR0FromR0: unsupported type %d", tag);
break;
}
setR0Type(pPointerType->pHead);
@@ -2183,14 +2251,32 @@ class Compiler : public ErrorSink {
return getPC() - 4;
}
- virtual void convertR0(Type* pType){
+ virtual void convertR0Imp(Type* pType, bool isCast){
Type* pR0Type = getR0Type();
if (pR0Type == NULL) {
assert(false);
setR0Type(pType);
return;
}
- if (bitsSame(pType, pR0Type)) {
+ if (isPointerType(pType) && isPointerType(pR0Type)) {
+ Type* pA = pR0Type;
+ Type* pB = pType;
+ // Array decays to pointer
+ if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
+ pA = pA->pTail;
+ }
+ if (typeEqual(pA, pB)) {
+ return; // OK
+ }
+ if (pB->pHead->tag == TY_VOID) {
+ return; // convert to void* is OK.
+ }
+ if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
+ && isCast) {
+ return; // OK
+ }
+ error("Incompatible pointer or array types");
+ } else if (bitsSame(pType, pR0Type)) {
// do nothing special
} else if (isFloatType(pType) && isFloatType(pR0Type)) {
// do nothing special, both held in same register on x87.
@@ -2326,6 +2412,11 @@ class Compiler : public ErrorSink {
return 1;
case TY_SHORT:
return 2;
+ case TY_ARRAY:
+ return alignmentOf(pType->pHead);
+ case TY_FUNC:
+ error("alignment of func not supported");
+ return 1;
default:
return 4;
}
@@ -2342,14 +2433,17 @@ class Compiler : public ErrorSink {
return 2;
case TY_CHAR:
return 1;
- default:
- return 0;
case TY_FLOAT:
return 4;
case TY_DOUBLE:
return 8;
case TY_POINTER:
return 4;
+ case TY_ARRAY:
+ return pType->length * sizeOf(pType->pHead);
+ default:
+ error("Unsupported type %d", pType->tag);
+ return 0;
}
}
@@ -2361,6 +2455,11 @@ class Compiler : public ErrorSink {
switch(pType->tag) {
case TY_DOUBLE:
return 8;
+ case TY_ARRAY:
+ return sizeOf(pType);
+ case TY_FUNC:
+ error("stackSizeOf func not supported");
+ return 4;
default:
return 4;
}
@@ -3911,7 +4010,7 @@ class Compiler : public ErrorSink {
skip(')');
unary();
pGen->forceR0RVal();
- pGen->convertR0(pCast);
+ pGen->castR0(pCast);
} else {
commaExpr();
skip(')');
@@ -3959,10 +4058,18 @@ class Compiler : public ErrorSink {
}
}
// load a variable
- Type* pVal = createPtrType(pVI->pType);
+ Type* pVal;
+ ExpressionType et;
+ if (pVI->pType->tag == TY_ARRAY) {
+ pVal = pVI->pType;
+ et = ET_RVALUE;
+ } else {
+ pVal = createPtrType(pVI->pType);
+ et = ET_LVALUE;
+ }
if (n) {
- ExpressionType et = ET_LVALUE;
- if (pVal->pHead->tag == TY_FUNC) {
+ int tag = pVal->pHead->tag;
+ if (tag == TY_FUNC) {
et = ET_RVALUE;
}
pGen->leaR0(n, pVal, et);
@@ -4251,6 +4358,8 @@ class Compiler : public ErrorSink {
}
if (at == TY_POINTER) {
return typeEqual(a->pHead, b->pHead);
+ } else if (at == TY_ARRAY) {
+ return a->length == b->length && typeEqual(a->pHead, b->pHead);
} else if (at == TY_FUNC || at == TY_PARAM) {
return typeEqual(a->pHead, b->pHead)
&& typeEqual(a->pTail, b->pTail);
@@ -4345,6 +4454,9 @@ class Compiler : public ErrorSink {
}
buffer.append('*');
break;
+ case TY_ARRAY:
+ decodeTypeImpPrefix(buffer, pType->pHead);
+ break;
case TY_FUNC:
decodeTypeImp(buffer, pType->pHead);
break;
@@ -4369,6 +4481,13 @@ class Compiler : public ErrorSink {
}
decodeTypeImpPostfix(buffer, pType->pHead);
break;
+ case TY_ARRAY:
+ {
+ String temp;
+ temp.printf("[%d]", pType->length);
+ buffer.append(temp);
+ }
+ break;
case TY_FUNC:
buffer.append('(');
for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
@@ -4418,9 +4537,13 @@ class Compiler : public ErrorSink {
nameRequired, reportFailure);
if (declName) {
// Clone the parent type so we can set a unique ID
+ Type* pOldType = pType;
pType = createType(pType->tag, pType->pHead, pType->pTail);
pType->id = declName;
+ pType->length = pOldType->length;
+ } else if (nameRequired) {
+ error("Expected a variable name");
}
// fprintf(stderr, "Parsed a declaration: ");
// printType(pType);
@@ -4490,11 +4613,27 @@ class Compiler : public ErrorSink {
error("Expected name. Got %s", temp.getUnwrapped());
reportFailure = true;
}
- while (accept('(')) {
- // Function declaration
- Type* pTail = acceptArgs(nameAllowed);
- pType = createType(TY_FUNC, pType, pTail);
- skip(')');
+ for(;;) {
+ if (accept('(')) {
+ // Function declaration
+ Type* pTail = acceptArgs(nameAllowed);
+ pType = createType(TY_FUNC, pType, pTail);
+ skip(')');
+ } if (accept('[')) {
+ if (tok != ']') {
+ if (tok != TOK_NUM || tokc <= 0) {
+ error("Expected positive integer constant");
+ } else {
+ Type* pDecayType = createPtrType(pType);
+ pType = createType(TY_ARRAY, pType, pDecayType);
+ pType->length = tokc;
+ }
+ next();
+ }
+ skip(']');
+ } else {
+ break;
+ }
}
if (pNewHead) {