From 9221bcccb39a53c8cddf338e53d0cfa2201b52dd Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Wed, 26 Aug 2009 16:15:07 -0700 Subject: Preliminary struct and union support. Working features: - struct - union - nested structs - anonymous structs - forward declarations - '.' and '->' - copying structs using '=' Missing features: - passing structs by value - returning structs by value - typedef - sizeof Example: struct v {float x, y, z, w; }; void add(struct v* result, struct v* a, struct v* b) { result->x = a->x + b->x; result->y = a->y + b->y; result->z = a->z + b->z; result->w = a->w + b->w; } Reworked size-of and alignment logic to support structs. Improved encoding of ARM immediate constants. --- libacc/acc.cpp | 480 +++++++++++++++++++++++++++++++++++--------- libacc/tests/data/structs.c | 95 +++++++++ libacc/tests/test.py | 7 + 3 files changed, 487 insertions(+), 95 deletions(-) create mode 100644 libacc/tests/data/structs.c diff --git a/libacc/acc.cpp b/libacc/acc.cpp index a4222e6..0409c10 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -157,9 +157,11 @@ class Compiler : public ErrorSink { struct Type { TypeTag tag; - tokenid_t id; // For function arguments, local vars - int length; // length of array - Type* pHead; + tokenid_t id; // For function arguments, global vars, local vars, struct elements + tokenid_t structTag; // For structs the name of the struct + int length; // length of array, offset of struct element. -1 means struct is forward defined + int alignment; // for structs only + Type* pHead; // For a struct this is the prototype struct. Type* pTail; }; @@ -341,6 +343,9 @@ class Compiler : public ErrorSink { /* Load floating point value from global address. */ virtual void loadFloat(int address, Type* pType) = 0; + /* Add the struct offset in bytes to R0, change the type to pType */ + virtual void addStructOffsetR0(int offset, Type* pType) = 0; + /* Jump to a target, and return the address of the word that * holds the target data, in case it needs to be fixed up later. */ @@ -508,16 +513,6 @@ class Compiler : public ErrorSink { */ virtual size_t sizeOf(Type* type) = 0; - /** - * Stack alignment of this type of data - */ - virtual size_t stackAlignmentOf(Type* pType) = 0; - - /** - * Argument stack argument size of this data type. - */ - virtual size_t stackSizeOf(Type* pType) = 0; - virtual Type* getR0Type() { return mExpressionStack.back().pType; } @@ -675,7 +670,6 @@ class Compiler : public ErrorSink { } return NULL; } - Type* mkpInt; private: @@ -801,6 +795,19 @@ class Compiler : public ErrorSink { } } + + virtual void addStructOffsetR0(int offset, Type* pType) { + if (offset) { + size_t immediate = 0; + if (encode12BitImmediate(offset, &immediate)) { + o4(0xE2800000 | immediate); // add r0, r0, #offset + } else { + error("structure offset out of range: %d", offset); + } + } + setR0Type(pType, ET_LVALUE); + } + virtual int gjmp(int t) { return o4(0xEA000000 | encodeAddress(t)); // b .L33 } @@ -1367,6 +1374,15 @@ class Compiler : public ErrorSink { o4(0xE1C200F0); // strd r0, [r2] #endif break; + case TY_STRUCT: + { + int size = sizeOf(pDestType); + if (size > 0) { + liReg(size, 1); + callRuntime((void*) runtime_structCopy); + } + } + break; default: error("storeR0ToTOS: unimplemented type %d", pDestType->tag); @@ -1407,6 +1423,8 @@ class Compiler : public ErrorSink { case TY_ARRAY: pNewType = pNewType->pTail; break; + case TY_STRUCT: + break; default: error("loadR0FromR0: unimplemented type %d", tag); break; @@ -1417,13 +1435,18 @@ class Compiler : public ErrorSink { virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) { if (ea > -LOCAL && ea < LOCAL) { // Local, fp relative - if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { - error("Offset out of range: %08x", ea); - } + + size_t immediate = 0; + bool inRange = false; if (ea < 0) { - o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea + inRange = encode12BitImmediate(-ea, &immediate); + o4(0xE24B0000 | immediate); // sub r0, fp, #ea } else { - o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea + inRange = encode12BitImmediate(ea, &immediate); + o4(0xE28B0000 | immediate); // add r0, fp, #ea + } + if (! inRange) { + error("Offset out of range: %08x", ea); } } else { // Global, absolute. @@ -1750,9 +1773,16 @@ class Compiler : public ErrorSink { case TY_CHAR: return 1; case TY_SHORT: - return 1; + return 2; case TY_DOUBLE: return 8; + case TY_ARRAY: + return alignmentOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->alignment & 0x7fffffff; + case TY_FUNC: + error("alignment of func not supported"); + return 1; default: return 4; } @@ -1777,37 +1807,14 @@ class Compiler : public ErrorSink { return 4; case TY_ARRAY: return pType->length * sizeOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->length; default: error("Unsupported type %d", pType->tag); return 0; } } - virtual size_t stackAlignmentOf(Type* pType) { - switch(pType->tag) { - case TY_DOUBLE: - return 8; - case TY_ARRAY: - return stackAlignmentOf(pType->pHead); - default: - return 4; - } - } - - virtual size_t stackSizeOf(Type* pType) { - 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; - } - } - private: static FILE* disasmOut; @@ -1986,19 +1993,42 @@ class Compiler : public ErrorSink { void liReg(int t, int reg) { assert(reg >= 0 && reg < 16); int rN = (reg & 0xf) << 12; - if (t >= 0 && t < 255) { - o4((0xE3A00000 + t) | rN); // mov rN, #0 - } else if (t >= -256 && t < 0) { + size_t encodedImmediate; + if (encode12BitImmediate(t, &encodedImmediate)) { + o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0 + } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) { // mvn means move constant ^ ~0 - o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0 + o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0 } else { - o4(0xE51F0000 | rN); // ldr rN, .L3 - o4(0xEA000000); // b .L99 - o4(t); // .L3: .word 0 + o4(0xE51F0000 | rN); // ldr rN, .L3 + o4(0xEA000000); // b .L99 + o4(t); // .L3: .word 0 // .L99: } } + bool encode12BitImmediate(size_t immediate, size_t* pResult) { + for(size_t i = 0; i < 16; i++) { + size_t rotate = i * 2; + size_t mask = rotateRight(0xff, rotate); + if ((immediate | mask) == mask) { + size_t bits8 = rotateLeft(immediate, rotate); + assert(bits8 <= 0xff); + *pResult = (i << 8) | bits8; + return true; + } + } + return false; + } + + size_t rotateRight(size_t n, size_t rotate) { + return (n >> rotate) | (n << (32 - rotate)); + } + + size_t rotateLeft(size_t n, size_t rotate) { + return (n << rotate) | (n >> (32 - rotate)); + } + void callRuntime(void* fn) { o4(0xE59FC000); // ldr r12, .L1 o4(0xEA000000); // b .L99 @@ -2016,6 +2046,10 @@ class Compiler : public ErrorSink { return a % b; } + static void runtime_structCopy(void* src, size_t size, void* dest) { + memcpy(dest, src, size); + } + #ifndef ARM_USE_VFP // Comparison to zero @@ -2212,6 +2246,13 @@ class Compiler : public ErrorSink { } } + virtual void addStructOffsetR0(int offset, Type* pType) { + if (offset) { + oad(0x05, offset); // addl offset, %eax + } + setR0Type(pType, ET_LVALUE); + } + virtual int gjmp(int t) { return psym(0xe9, t); } @@ -2537,6 +2578,26 @@ class Compiler : public ErrorSink { case TY_DOUBLE: o(0x19dd); /* fstpl (%ecx) */ break; + case TY_STRUCT: + { + // TODO: use alignment information to use movsw/movsl instead of movsb + int size = sizeOf(pTargetType); + if (size > 0) { + o(0x9c); // pushf + o(0x57); // pushl %edi + o(0x56); // pushl %esi + o(0xcf89); // movl %ecx, %edi + o(0xc689); // movl %eax, %esi + oad(0xb9, size); // mov #size, %ecx + o(0xfc); // cld + o(0xf3); // rep + o(0xa4); // movsb + o(0x5e); // popl %esi + o(0x5f); // popl %edi + o(0x9d); // popf + } + } + break; default: error("storeR0ToTOS: unsupported type %d", pTargetType->tag); @@ -2571,6 +2632,8 @@ class Compiler : public ErrorSink { case TY_ARRAY: pNewType = pNewType->pTail; break; + case TY_STRUCT: + break; default: error("loadR0FromR0: unsupported type %d", tag); break; @@ -2747,6 +2810,8 @@ class Compiler : public ErrorSink { return 2; case TY_ARRAY: return alignmentOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->alignment & 0x7fffffff; case TY_FUNC: error("alignment of func not supported"); return 1; @@ -2774,30 +2839,14 @@ class Compiler : public ErrorSink { return 4; case TY_ARRAY: return pType->length * sizeOf(pType->pHead); + case TY_STRUCT: + return pType->pHead->length; default: error("Unsupported type %d", pType->tag); return 0; } } - virtual size_t stackAlignmentOf(Type* pType){ - return 4; - } - - virtual size_t stackSizeOf(Type* pType) { - 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; - } - } - private: /** Output 1 to 4 bytes. @@ -2926,6 +2975,11 @@ class Compiler : public ErrorSink { mpBase->loadFloat(address, pType); } + virtual void addStructOffsetR0(int offset, Type* pType) { + fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag); + mpBase->addStructOffsetR0(offset, pType); + } + virtual int gjmp(int t) { int result = mpBase->gjmp(t); fprintf(stderr, "gjmp(%d) = %d\n", t, result); @@ -3073,16 +3127,6 @@ class Compiler : public ErrorSink { return mpBase->sizeOf(pType); } - - virtual size_t stackAlignmentOf(Type* pType) { - return mpBase->stackAlignmentOf(pType); - } - - - virtual size_t stackSizeOf(Type* pType) { - return mpBase->stackSizeOf(pType); - } - virtual Type* getR0Type() { return mpBase->getR0Type(); } @@ -3236,6 +3280,7 @@ class Compiler : public ErrorSink { // Current values for the token char* mpMacroDefinition; VariableInfo* mpVariableInfo; + VariableInfo* mpStructInfo; }; class TokenTable { @@ -3516,6 +3561,7 @@ class Compiler : public ErrorSink { size_t level; VariableInfo* pOldDefinition; Type* pType; + bool isStructTag; }; class SymbolStack { @@ -3547,7 +3593,11 @@ class Compiler : public ErrorSink { while (mStack.size() > mark.mSymbolHead) { VariableInfo* pV = mStack.back(); mStack.pop_back(); - (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition; + if (pV->isStructTag) { + (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition; + } else { + (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition; + } } mpArena->freeToMark(mark.mArenaMark); } @@ -3557,6 +3607,11 @@ class Compiler : public ErrorSink { return pV && pV->level == level(); } + bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) { + VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo; + return pV && pV->level == level(); + } + VariableInfo* add(tokenid_t tok) { Token& token = (*mpTokenTable)[tok]; VariableInfo* pOldV = token.mpVariableInfo; @@ -3571,6 +3626,21 @@ class Compiler : public ErrorSink { return pNewV; } + VariableInfo* addStructTag(tokenid_t tok) { + Token& token = (*mpTokenTable)[tok]; + VariableInfo* pOldS = token.mpStructInfo; + VariableInfo* pNewS = + (VariableInfo*) mpArena->alloc(sizeof(VariableInfo)); + memset(pNewS, 0, sizeof(VariableInfo)); + pNewS->tok = tok; + pNewS->level = level(); + pNewS->isStructTag = true; + pNewS->pOldDefinition = pOldS; + token.mpStructInfo = pNewS; + mStack.push_back(pNewS); + return pNewS; + } + VariableInfo* add(Type* pType) { VariableInfo* pVI = add(pType->id); pVI->pType = pType; @@ -3629,6 +3699,8 @@ class Compiler : public ErrorSink { SymbolStack mGlobals; SymbolStack mLocals; + SymbolStack* mpCurrentSymbolStack; + // Prebuilt types, makes things slightly faster. Type* mkpInt; // int Type* mkpShort; // short @@ -3663,6 +3735,7 @@ class Compiler : public ErrorSink { static const int TOK_NUM_FLOAT = 3; static const int TOK_NUM_DOUBLE = 4; static const int TOK_OP_ASSIGNMENT = 5; + static const int TOK_OP_ARROW = 6; // 3..255 are character and/or operators @@ -4000,6 +4073,9 @@ class Compiler : public ErrorSink { mTokenString.clear(); pdef(ch); inp(); + if (tok == '.' && !isdigit(ch)) { + goto done; + } int base = 10; if (tok == '0') { if (ch == 'x' || ch == 'X') { @@ -4088,6 +4164,9 @@ class Compiler : public ErrorSink { } inp(); next(); + } else if ((tok == '-') & (ch == '>')) { + inp(); + tok = TOK_OP_ARROW; } else { const char* t = operatorChars; int opIndex = 0; @@ -4121,6 +4200,8 @@ class Compiler : public ErrorSink { } } } + + done: ; #if 0 { String buf; @@ -4443,6 +4524,24 @@ class Compiler : public ErrorSink { pGen->genOp(OP_PLUS); doPointer(); skip(']'); + } else if (accept('.')) { + // struct element + pGen->forceR0RVal(); + Type* pStruct = pGen->getR0Type(); + if (pStruct->tag == TY_STRUCT) { + doStructMember(pStruct); + } else { + error("expected a struct value to the left of '.'"); + } + } else if (accept(TOK_OP_ARROW)) { + pGen->forceR0RVal(); + Type* pPtr = pGen->getR0Type(); + if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) { + pGen->loadR0FromR0(); + doStructMember(pPtr->pHead); + } else { + error("Expected a pointer to a struct to the left of '->'"); + } } else if (accept('(')) { /* function call */ Type* pDecl = NULL; @@ -4505,6 +4604,18 @@ class Compiler : public ErrorSink { } } + void doStructMember(Type* pStruct) { + Type* pStructElement = lookupStructMember(pStruct, tok); + if (pStructElement) { + next(); + pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead)); + } else { + String buf; + decodeToken(buf, tok, true); + error("Expected a struct member to the right of '.', got %s", buf.getUnwrapped()); + } + } + void doIncDec(int isInc, int isPost) { // R0 already has the lval checkLVal(); @@ -4714,6 +4825,8 @@ class Compiler : public ErrorSink { } else if (at == TY_FUNC || at == TY_PARAM) { return typeEqual(a->pHead, b->pHead) && typeEqual(a->pTail, b->pTail); + } else if (at == TY_STRUCT) { + return a->pHead == b->pHead; } return true; } @@ -4746,20 +4859,22 @@ class Compiler : public ErrorSink { void decodeTypeImp(String& buffer, Type* pType) { decodeTypeImpPrefix(buffer, pType); + decodeId(buffer, pType->id); + decodeTypeImpPostfix(buffer, pType); + } - String temp; - if (pType->id != 0) { - decodeToken(temp, pType->id, false); + void decodeId(String& buffer, tokenid_t id) { + if (id) { + String temp; + decodeToken(temp, id, false); buffer.append(temp); } - - decodeTypeImpPostfix(buffer, pType); } void decodeTypeImpPrefix(String& buffer, Type* pType) { TypeTag tag = pType->tag; - if (tag >= TY_INT && tag <= TY_DOUBLE) { + if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) { switch (tag) { case TY_INT: buffer.appendCStr("int"); @@ -4779,6 +4894,16 @@ class Compiler : public ErrorSink { case TY_DOUBLE: buffer.appendCStr("double"); break; + case TY_STRUCT: + { + bool isStruct = (pType->pHead->alignment & 0x80000000) != 0; + buffer.appendCStr(isStruct ? "struct" : "union"); + if (pType->pHead && pType->pHead->structTag) { + buffer.append(' '); + decodeId(buffer, pType->pHead->structTag); + } + } + break; default: break; } @@ -4808,6 +4933,8 @@ class Compiler : public ErrorSink { case TY_ARRAY: decodeTypeImpPrefix(buffer, pType->pHead); break; + case TY_STRUCT: + break; case TY_FUNC: decodeTypeImp(buffer, pType->pHead); break; @@ -4839,6 +4966,16 @@ class Compiler : public ErrorSink { buffer.append(temp); } break; + case TY_STRUCT: + if (pType->pHead->length >= 0) { + buffer.appendCStr(" {"); + for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { + decodeTypeImp(buffer, pArg->pHead); + buffer.appendCStr(";"); + } + buffer.append('}'); + } + break; case TY_FUNC: buffer.append('('); for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) { @@ -4874,6 +5011,8 @@ class Compiler : public ErrorSink { pType = mkpFloat; } else if (tok == TOK_DOUBLE) { pType = mkpDouble; + } else if (tok == TOK_STRUCT || tok == TOK_UNION) { + return acceptStruct(); } else { return NULL; } @@ -4881,6 +5020,123 @@ class Compiler : public ErrorSink { return pType; } + Type* acceptStruct() { + assert(tok == TOK_STRUCT || tok == TOK_UNION); + bool isStruct = tok == TOK_STRUCT; + next(); + tokenid_t structTag = acceptSymbol(); + bool isDeclaration = accept('{'); + bool fail = false; + + Type* pStructType = createType(TY_STRUCT, NULL, NULL); + if (structTag) { + Token* pToken = &mTokenTable[structTag]; + VariableInfo* pStructInfo = pToken->mpStructInfo; + bool needToDeclare = !pStructInfo; + if (pStructInfo) { + if (isDeclaration) { + if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) { + if (pStructInfo->pType->pHead->length == -1) { + // we're filling in a forward declaration. + needToDeclare = false; + } else { + error("A struct with the same name is already defined at this level."); + fail = true; + } + } else { + needToDeclare = true; + } + } + if (!fail) { + assert(pStructInfo->isStructTag); + pStructType->pHead = pStructInfo->pType; + pStructType->pTail = pStructType->pHead->pTail; + } + } + + if (needToDeclare) { + // This is a new struct name + pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag); + pStructType = createType(TY_STRUCT, NULL, NULL); + pStructType->structTag = structTag; + pStructType->pHead = pStructType; + if (! isDeclaration) { + // A forward declaration + pStructType->length = -1; + } + pToken->mpStructInfo->pType = pStructType; + } + } else { + // An anonymous struct + pStructType->pHead = pStructType; + } + + if (isDeclaration) { + size_t offset = 0; + size_t structSize = 0; + size_t structAlignment = 0; + Type** pParamHolder = & pStructType->pHead->pTail; + while (tok != '}' && tok != EOF) { + Type* pPrimitiveType = expectPrimitiveType(); + if (pPrimitiveType) { + while (tok != ';' && tok != EOF) { + Type* pItem = acceptDeclaration(pPrimitiveType, true, false); + if (!pItem) { + break; + } + if (lookupStructMember(pStructType, pItem->id)) { + String buf; + decodeToken(buf, pItem->id, false); + error("Duplicate struct member %s", buf.getUnwrapped()); + } + Type* pStructElement = createType(TY_PARAM, pItem, NULL); + size_t alignment = pGen->alignmentOf(pItem); + if (alignment > structAlignment) { + structAlignment = alignment; + } + size_t alignmentMask = alignment - 1; + offset = (offset + alignmentMask) & ~alignmentMask; + pStructElement->length = offset; + size_t size = pGen->sizeOf(pItem); + if (isStruct) { + offset += size; + structSize = offset; + } else { + if (size >= structSize) { + structSize = size; + } + } + *pParamHolder = pStructElement; + pParamHolder = &pStructElement->pTail; + accept(','); + } + skip(';'); + } else { + // Some sort of syntax error, skip token and keep trying + next(); + } + } + if (!fail) { + pStructType->pHead->length = structSize; + pStructType->pHead->alignment = structAlignment | (isStruct << 31); + } + skip('}'); + } + if (fail) { + pStructType = NULL; + } + return pStructType; + } + + Type* lookupStructMember(Type* pStruct, tokenid_t memberId) { + for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) { + if (pStructElement->pHead->id == memberId) { + return pStructElement; + } + } + return NULL; + } + Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) { tokenid_t declName = 0; bool reportFailure = false; @@ -4890,14 +5146,15 @@ class Compiler : public ErrorSink { // Clone the parent type so we can set a unique ID Type* pOldType = pType; pType = createType(pType->tag, pType->pHead, pType->pTail); - + *pType = *pOldType; pType->id = declName; - pType->length = pOldType->length; } else if (nameRequired) { error("Expected a variable name"); } - // fprintf(stderr, "Parsed a declaration: "); - // printType(pType); +#if 0 + fprintf(stderr, "Parsed a declaration: "); + printType(pType); +#endif if (reportFailure) { return NULL; } @@ -4905,7 +5162,8 @@ class Compiler : public ErrorSink { } Type* expectDeclaration(Type* pBaseType) { - Type* pType = acceptDeclaration(pBaseType, true, true); + bool nameRequired = pBaseType->tag != TY_STRUCT; + Type* pType = acceptDeclaration(pBaseType, true, nameRequired); if (! pType) { error("Expected a declaration"); } @@ -4962,6 +5220,7 @@ class Compiler : public ErrorSink { String temp; decodeToken(temp, tok, true); error("Expected name. Got %s", temp.getUnwrapped()); + assert(false); reportFailure = true; } for(;;) { @@ -5069,11 +5328,16 @@ class Compiler : public ErrorSink { if (!pDecl) { break; } + if (!pDecl->id) { + break; + } int variableAddress = 0; addLocalSymbol(pDecl); - size_t alignment = pGen->stackAlignmentOf(pDecl); + size_t alignment = pGen->alignmentOf(pDecl); + assert(alignment > 0); size_t alignmentMask = ~ (alignment - 1); size_t sizeOf = pGen->sizeOf(pDecl); + assert(sizeOf > 0); loc = (loc + alignment - 1) & alignmentMask; size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask; loc = loc + alignedSize; @@ -5123,6 +5387,12 @@ class Compiler : public ErrorSink { } } + void printToken(tokenid_t token) { + String buffer; + decodeToken(buffer, token, true); + fprintf(stderr, "%s\n", buffer.getUnwrapped()); + } + bool checkSymbol(tokenid_t token) { bool result = token >= TOK_SYMBOL; if (!result) { @@ -5143,6 +5413,7 @@ class Compiler : public ErrorSink { } void globalDeclarations() { + mpCurrentSymbolStack = &mGlobals; while (tok != EOF) { Type* pBaseType = expectPrimitiveType(); if (!pBaseType) { @@ -5152,6 +5423,11 @@ class Compiler : public ErrorSink { if (!pDecl) { break; } + if (!pDecl->id) { + skip(';'); + continue; + } + if (! isDefined(pDecl->id)) { addGlobalSymbol(pDecl); } @@ -5198,6 +5474,7 @@ class Compiler : public ErrorSink { error("expected '{'"); } else { mpCurrentArena = &mLocalArena; + mpCurrentSymbolStack = &mLocals; if (name) { /* patch forward references */ pGen->resolveForward((int) name->pForward); @@ -5214,12 +5491,13 @@ class Compiler : public ErrorSink { addLocalSymbol(pArg); } /* read param name and compute offset */ - size_t alignment = pGen->stackAlignmentOf(pArg); + Type* pPassingType = passingType(pArg); + size_t alignment = pGen->alignmentOf(pPassingType); a = (a + alignment - 1) & ~ (alignment-1); if (pArg->id) { VI(pArg->id)->pAddress = (void*) a; } - a = a + pGen->stackSizeOf(pArg); + a = a + pGen->sizeOf(pPassingType); argCount++; } rsym = loc = 0; @@ -5230,16 +5508,28 @@ class Compiler : public ErrorSink { pGen->functionExit(pDecl, a, loc); mLocals.popLevel(); mpCurrentArena = &mGlobalArena; + mpCurrentSymbolStack = &mGlobals; } } } } + Type* passingType(Type* pType) { + switch (pType->tag) { + case TY_CHAR: + case TY_SHORT: + return mkpInt; + default: + return pType; + } + } + char* allocGlobalSpace(size_t alignment, size_t bytes) { size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1); size_t end = base + bytes; if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) { error("Global space exhausted"); + assert(false); return NULL; } char* result = (char*) base; diff --git a/libacc/tests/data/structs.c b/libacc/tests/data/structs.c new file mode 100644 index 0000000..dd81af3 --- /dev/null +++ b/libacc/tests/data/structs.c @@ -0,0 +1,95 @@ +// struct definition and declaration +struct a { + int a; + int b; +} c; + +// Useless, but legal struct declaration +struct { + int x; +}; + +// Useful anonymous struct declaration +struct { + int y; +} anon1, anon2; + +// forward declarations +struct a; +struct b; +struct c; + +struct b {int a; int b; }; + +// struct c {b g; }; // syntax error. + +// struct s {float c,a,b,c;} s; // duplicate struct member + +struct c {struct b g; }; + +// struct a { int w; }; // error + +void testCopying() { + struct a {int a[10]; char c;} a, b; + a.c = 37; + b.c = 38; + b = a; + printf("testCopying: %d == %d\n", a.c, b.c); +} + +void testUnion() { + union u; + union u {float f;int i;} u; + u.f = 1.0f; + printf("testUnion: %g == 0x%08x\n", u.f, u.i); +} + +struct v {float x, y, z, w; }; + +void add(struct v* result, struct v* a, struct v* b) { + result->x = a->x + b->x; + result->y = a->y + b->y; + result->z = a->z + b->z; + result->w = a->w + b->w; +} + +void set(struct v* v, float x, float y, float z, float w) { + v->x = x; + v->y = y; + v->z = z; + v->w = w; +} + +void print(struct v* v) { + printf("(%g, %g, %g, %g)\n", v->x, v->y, v->z, v->w); +} + +void testArgs() { + struct v a, b, c; + set(&a, 1.0f, 2.0f, 3.0f, 4.0f); + set(&b, 5.0f, 6.0f, 7.0f, 8.0f); + add(&c, &a, &b); + printf("testArgs: "); + print(&c); +} + +int main() { + anon1.y = 3; + anon2.y = anon1.y; + + testCopying(); + testUnion(); + testArgs(); + + struct c cc; + cc.g.a = 3; + c.a = 1; + c.b = 3; + struct a {int x, y; } z; + // struct a {int x, y; } z2; + z.x = c.a; + struct a *pA; + pA = &z; + pA->x += 5; + return pA->x; +} diff --git a/libacc/tests/test.py b/libacc/tests/test.py index b8caee0..a8575b1 100644 --- a/libacc/tests/test.py +++ b/libacc/tests/test.py @@ -463,6 +463,13 @@ result: 4 result: 1092616192 ""","""""") + def testStructs(self): + self.compileCheck(["-R", "data/structs.c"], """Executing compiled code: +testCopying: 37 == 37 +testUnion: 1 == 0x3f800000 +testArgs: (6, 8, 10, 12) +result: 6 +""","""""") def main(): checkEnvironment() -- cgit v1.1