From: Eli Friedman Date: Fri, 30 May 2008 10:24:46 +0000 (+0000) Subject: Some additions to constant initializer generation code. Adds X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a823400df727968fda4b2df23abab0d8ecff7a75;p=clang Some additions to constant initializer generation code. Adds bit-field initialization; ugly code, X86-only, but it works, at least for basic stuff. Separates/adds union initialization; currently disabled, though, because the struct/array code needs modifications to support elements of the wrong type. Fixes PR2381 and PR2309 with the bit-field initialization. And NetHack compiles and appears to work with a few tweaks (to work around the lack of transparent_union support, and clang being a bit strict about conflicting declarations). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@51763 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index c61d71acad..ca7a580ef7 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -18,6 +18,7 @@ #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/Support/Compiler.h" +#include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -73,9 +74,10 @@ public: return Visit(DAE->getExpr()); } - llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, - const llvm::ArrayType *AType) { + llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { std::vector Elts; + const llvm::ArrayType *AType = + cast(ConvertType(ILE->getType())); unsigned NumInitElements = ILE->getNumInits(); // FIXME: Check for wide strings if (NumInitElements > 0 && isa(ILE->getInit(0)) && @@ -92,7 +94,6 @@ public: unsigned i = 0; for (; i < NumInitableElts; ++i) { llvm::Constant *C = Visit(ILE->getInit(i)); - assert (C && "Failed to create initializer expression"); Elts.push_back(C); } @@ -103,9 +104,56 @@ public: return llvm::ConstantArray::get(AType, Elts); } - llvm::Constant *EmitStructInitialization(InitListExpr *ILE, - const llvm::StructType *SType) { - + void InsertBitfieldIntoStruct(std::vector& Elts, + FieldDecl* Field, Expr* E) { + // Calculate the value to insert + llvm::Constant *C = Visit(E); + llvm::ConstantInt *CI = dyn_cast(C); + if (!CI) { + CGM.WarnUnsupported(E, "bitfield initialization"); + return; + } + llvm::APInt V = CI->getValue(); + + // Calculate information about the relevant field + const llvm::Type* Ty = CI->getType(); + unsigned size = CGM.getTypes().getTargetData().getTypeStoreSizeInBits(Ty); + unsigned fieldOffset = CGM.getTypes().getLLVMFieldNo(Field) * size; + CodeGenTypes::BitFieldInfo bitFieldInfo = + CGM.getTypes().getBitFieldInfo(Field); + fieldOffset += bitFieldInfo.Begin; + + // Find where to start the insertion + // FIXME: This is O(n^2) in the number of bit-fields! + // FIXME: This won't work if the struct isn't completely packed! + unsigned offset = 0, i = 0; + while (offset < (fieldOffset & -8)) + offset += CGM.getTypes().getTargetData().getTypeStoreSizeInBits(Elts[i++]->getType()); + + // Insert the bits into the struct + // FIXME: This algorthm is only correct on X86! + // FIXME: THis algorthm assumes bit-fields only have byte-size elements! + unsigned bitsToInsert = bitFieldInfo.Size; + unsigned curBits = std::min(8 - (fieldOffset & 7), bitsToInsert); + unsigned byte = V.getLoBits(curBits).getZExtValue() << (fieldOffset & 7); + do { + llvm::Constant* byteC = llvm::ConstantInt::get(llvm::Type::Int8Ty, byte); + Elts[i] = llvm::ConstantExpr::getOr(Elts[i], byteC); + ++i; + V = V.lshr(curBits); + bitsToInsert -= curBits; + + if (!bitsToInsert) + break; + + curBits = bitsToInsert > 8 ? 8 : bitsToInsert; + byte = V.getLoBits(curBits).getZExtValue(); + } while (true); + } + + llvm::Constant *EmitStructInitialization(InitListExpr *ILE) { + const llvm::StructType *SType = + cast(ConvertType(ILE->getType())); RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); std::vector Elts; @@ -124,13 +172,11 @@ public: if (!curField->getIdentifier()) continue; - llvm::Constant *C = Visit(ILE->getInit(EltNo)); - assert (C && "Failed to create initializer expression"); - if (curField->isBitField()) { - CGM.WarnUnsupported(ILE->getInit(EltNo), "bitfield initialization"); + InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(EltNo)); } else { - Elts[CGM.getTypes().getLLVMFieldNo(curField)] = C; + Elts[CGM.getTypes().getLLVMFieldNo(curField)] = + Visit(ILE->getInit(EltNo)); } EltNo++; } @@ -138,20 +184,75 @@ public: return llvm::ConstantStruct::get(SType, Elts); } - llvm::Constant *EmitVectorInitialization(InitListExpr *ILE, - const llvm::VectorType *VType) { + llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) { + // FIXME: Need to make this work correctly for unions in structs/arrays + CGM.WarnUnsupported(ILE, "bitfield initialization"); + return llvm::UndefValue::get(CGM.getTypes().ConvertType(ILE->getType())); + + // Following is a partial implementation; it doesn't work correctly + // because the parent struct/arrays don't adapt their type yet, though + RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl(); + const llvm::Type *Ty = ConvertType(ILE->getType()); + + // Find the field decl we're initializing, if any + int FieldNo = 0; // Field no in RecordDecl + FieldDecl* curField; + do { + curField = RD->getMember(FieldNo); + FieldNo++; + } while (!curField->getIdentifier() && FieldNo < RD->getNumMembers()); + + if (ILE->getNumInits() == 0 || !curField->getIdentifier()) + return llvm::Constant::getNullValue(Ty); + + if (curField->isBitField()) { + // Create a dummy struct for bit-field insertion + unsigned NumElts = CGM.getTargetData().getABITypeSize(Ty) / 8; + llvm::Constant* NV = llvm::Constant::getNullValue(llvm::Type::Int8Ty); + std::vector Elts(NumElts, NV); + + InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(0)); + const llvm::ArrayType *RetTy = + llvm::ArrayType::get(NV->getType(), NumElts); + return llvm::ConstantArray::get(RetTy, Elts); + } + + llvm::Constant *C = Visit(ILE->getInit(0)); + // Build a struct with the union sub-element as the first member, + // and padded to the appropriate size + std::vector Elts; + std::vector Types; + Elts.push_back(C); + Types.push_back(C->getType()); + unsigned CurSize = CGM.getTargetData().getTypeStoreSize(C->getType()); + unsigned TotalSize = CGM.getTargetData().getTypeStoreSize(Ty); + while (CurSize < TotalSize) { + Elts.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty)); + Types.push_back(llvm::Type::Int8Ty); + CurSize++; + } + + // This always generates a packed struct + // FIXME: Try to generate an unpacked struct when we can + llvm::StructType* STy = llvm::StructType::get(Types, true); + return llvm::ConstantStruct::get(STy, Elts); + } + + llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) { + const llvm::VectorType *VType = + cast(ConvertType(ILE->getType())); std::vector Elts; unsigned NumInitElements = ILE->getNumInits(); unsigned NumElements = VType->getNumElements(); + // FIXME: Handle case in assertion correctly assert (NumInitElements == NumElements && "Unsufficient vector init elelments"); // Copy initializer elements. unsigned i = 0; for (; i < NumElements; ++i) { llvm::Constant *C = Visit(ILE->getInit(i)); - assert (C && "Failed to create initializer expression"); Elts.push_back(C); } @@ -159,24 +260,27 @@ public: } llvm::Constant *VisitInitListExpr(InitListExpr *ILE) { - const llvm::CompositeType *CType = - dyn_cast(ConvertType(ILE->getType())); - - if (!CType) { - // We have a scalar in braces. Just use the first element. + if (ILE->getType()->isScalarType()) { + // We have a scalar in braces. Just use the first element. + if (ILE->getNumInits() > 0) return Visit(ILE->getInit(0)); + + const llvm::Type* RetTy = CGM.getTypes().ConvertType(ILE->getType()); + return llvm::Constant::getNullValue(RetTy); } - - if (const llvm::ArrayType *AType = dyn_cast(CType)) - return EmitArrayInitialization(ILE, AType); - if (const llvm::StructType *SType = dyn_cast(CType)) - return EmitStructInitialization(ILE, SType); + if (ILE->getType()->isArrayType()) + return EmitArrayInitialization(ILE); + + if (ILE->getType()->isStructureType()) + return EmitStructInitialization(ILE); + + if (ILE->getType()->isUnionType()) + return EmitUnionInitialization(ILE); + + if (ILE->getType()->isVectorType()) + return EmitVectorInitialization(ILE); - if (const llvm::VectorType *VType = dyn_cast(CType)) - return EmitVectorInitialization(ILE, VType); - - // Make sure we have an array at this point assert(0 && "Unable to handle InitListExpr"); // Get rid of control reaches end of void function warning. // Not reached.