diff options
author | Chris Lattner <sabre@nondot.org> | 2010-04-13 17:45:57 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-04-13 17:45:57 +0000 |
commit | eba3e5af56b292f5c96fe50dbbd66bfdefc8d48c (patch) | |
tree | 648d74f17d88a9a7519ca340d73ba5d87df377dd /lib | |
parent | 4357a8291d759f6f9c36d3edeee8476d3eaf0804 (diff) |
move a bunch of ConstStructBuilder methods out of line.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101152 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 542 |
1 files changed, 282 insertions, 260 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index c57cf5b7b6..8d16ed7ad7 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -27,359 +27,381 @@ using namespace clang; using namespace CodeGen; -namespace { +//===----------------------------------------------------------------------===// +// ConstStructBuilder +//===----------------------------------------------------------------------===// + +namespace { class ConstStructBuilder { CodeGenModule &CGM; CodeGenFunction *CGF; bool Packed; - unsigned NextFieldOffsetInBytes; - unsigned LLVMStructAlignment; - std::vector<llvm::Constant *> Elements; - +public: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *ILE); + +private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), LLVMStructAlignment(1) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - uint64_t FieldOffsetInBytes = FieldOffset / 8; + const Expr *InitExpr); - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes - && "Field offset mismatch!"); + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + const Expr *InitExpr); - // Emit the field. - llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); - if (!C) - return false; + void AppendPadding(uint64_t NumBytes); - unsigned FieldAlignment = getAlignment(C); + void AppendTailPadding(uint64_t RecordSize); - // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + void ConvertStructToPacked(); + + bool Build(InitListExpr *ILE); - if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { - assert(!Packed && "Alignment is wrong even with a packed struct!"); + unsigned getAlignment(const llvm::Constant *C) const { + if (Packed) return 1; + return CGM.getTargetData().getABITypeAlignment(C->getType()); + } - // Convert the struct to a packed struct. - ConvertStructToPacked(); - - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + uint64_t getSizeInBytes(const llvm::Constant *C) const { + return CGM.getTargetData().getTypeAllocSize(C->getType()); + } +}; - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { - // We need to append padding. - AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); +bool ConstStructBuilder:: +AppendField(const FieldDecl *Field, uint64_t FieldOffset, const Expr *InitExpr){ + uint64_t FieldOffsetInBytes = FieldOffset / 8; - assert(NextFieldOffsetInBytes == FieldOffsetInBytes && - "Did not add enough padding!"); + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + && "Field offset mismatch!"); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + // Emit the field. + llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); + if (!C) + return false; - // Add the field. - Elements.push_back(C); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); - - if (Packed) - assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); - else - LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); + unsigned FieldAlignment = getAlignment(C); - return true; - } + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); - bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - llvm::ConstantInt *CI = - cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr, - Field->getType(), - CGF)); - // FIXME: Can this ever happen? - if (!CI) - return false; - - if (FieldOffset > NextFieldOffsetInBytes * 8) { - // We need to add padding. - uint64_t NumBytes = - llvm::RoundUpToAlignment(FieldOffset - - NextFieldOffsetInBytes * 8, 8) / 8; + if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + assert(!Packed && "Alignment is wrong even with a packed struct!"); - AppendPadding(NumBytes); - } + // Convert the struct to a packed struct. + ConvertStructToPacked(); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // We need to append padding. + AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); - llvm::APInt FieldValue = CI->getValue(); + assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + "Did not add enough padding!"); - // Promote the size of FieldValue if necessary - // FIXME: This should never occur, but currently it can because initializer - // constants are cast to bool, and because clang is not enforcing bitfield - // width limits. - if (FieldSize > FieldValue.getBitWidth()) - FieldValue.zext(FieldSize); + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - // Truncate the size of FieldValue to the bit field size. - if (FieldSize < FieldValue.getBitWidth()) - FieldValue.trunc(FieldSize); + // Add the field. + Elements.push_back(C); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); + + if (Packed) + assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + else + LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); - if (FieldOffset < NextFieldOffsetInBytes * 8) { - // Either part of the field or the entire field can go into the previous - // byte. - assert(!Elements.empty() && "Elements can't be empty!"); + return true; +} - unsigned BitsInPreviousByte = - NextFieldOffsetInBytes * 8 - FieldOffset; +bool ConstStructBuilder:: + AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + const Expr *InitExpr) { + llvm::ConstantInt *CI = + cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr, + Field->getType(), + CGF)); + // FIXME: Can this ever happen? + if (!CI) + return false; - bool FitsCompletelyInPreviousByte = - BitsInPreviousByte >= FieldValue.getBitWidth(); + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // We need to add padding. + uint64_t NumBytes = + llvm::RoundUpToAlignment(FieldOffset - + NextFieldOffsetInBytes * 8, 8) / 8; - llvm::APInt Tmp = FieldValue; + AppendPadding(NumBytes); + } - if (!FitsCompletelyInPreviousByte) { - unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); - if (CGM.getTargetData().isBigEndian()) { - Tmp = Tmp.lshr(NewFieldWidth); - Tmp.trunc(BitsInPreviousByte); + llvm::APInt FieldValue = CI->getValue(); - // We want the remaining high bits. - FieldValue.trunc(NewFieldWidth); - } else { - Tmp.trunc(BitsInPreviousByte); + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); - // We want the remaining low bits. - FieldValue = FieldValue.lshr(BitsInPreviousByte); - FieldValue.trunc(NewFieldWidth); - } - } + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); - Tmp.zext(8); - if (CGM.getTargetData().isBigEndian()) { - if (FitsCompletelyInPreviousByte) - Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); - } else { - Tmp = Tmp.shl(8 - BitsInPreviousByte); - } + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // Either part of the field or the entire field can go into the previous + // byte. + assert(!Elements.empty() && "Elements can't be empty!"); - // Or in the bits that go into the previous byte. - if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) - Tmp |= Val->getValue(); - else - assert(isa<llvm::UndefValue>(Elements.back())); + unsigned BitsInPreviousByte = + NextFieldOffsetInBytes * 8 - FieldOffset; - Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); + bool FitsCompletelyInPreviousByte = + BitsInPreviousByte >= FieldValue.getBitWidth(); - if (FitsCompletelyInPreviousByte) - return true; - } + llvm::APInt Tmp = FieldValue; - while (FieldValue.getBitWidth() > 8) { - llvm::APInt Tmp; + if (!FitsCompletelyInPreviousByte) { + unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; if (CGM.getTargetData().isBigEndian()) { - // We want the high bits. - Tmp = FieldValue; - Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); - Tmp.trunc(8); + Tmp = Tmp.lshr(NewFieldWidth); + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining high bits. + FieldValue.trunc(NewFieldWidth); } else { - // We want the low bits. - Tmp = FieldValue; - Tmp.trunc(8); + Tmp.trunc(BitsInPreviousByte); - FieldValue = FieldValue.lshr(8); + // We want the remaining low bits. + FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.trunc(NewFieldWidth); } - - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); - NextFieldOffsetInBytes++; - - FieldValue.trunc(FieldValue.getBitWidth() - 8); } - assert(FieldValue.getBitWidth() > 0 && - "Should have at least one bit left!"); - assert(FieldValue.getBitWidth() <= 8 && - "Should not have more than a byte left!"); + Tmp.zext(8); + if (CGM.getTargetData().isBigEndian()) { + if (FitsCompletelyInPreviousByte) + Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); + } else { + Tmp = Tmp.shl(8 - BitsInPreviousByte); + } - if (FieldValue.getBitWidth() < 8) { - if (CGM.getTargetData().isBigEndian()) { - unsigned BitWidth = FieldValue.getBitWidth(); + // Or in the bits that go into the previous byte. + if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa<llvm::UndefValue>(Elements.back())); - FieldValue.zext(8); - FieldValue = FieldValue << (8 - BitWidth); - } else - FieldValue.zext(8); - } + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); - // Append the last element. - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), - FieldValue)); - NextFieldOffsetInBytes++; - return true; + if (FitsCompletelyInPreviousByte) + return true; } - void AppendPadding(uint64_t NumBytes) { - if (!NumBytes) - return; + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + if (CGM.getTargetData().isBigEndian()) { + // We want the high bits. + Tmp = FieldValue; + Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); + Tmp.trunc(8); + } else { + // We want the low bits. + Tmp = FieldValue; + Tmp.trunc(8); - llvm::Constant *C = llvm::Constant::getNullValue(Ty); - Elements.push_back(C); - assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + FieldValue = FieldValue.lshr(8); + } - NextFieldOffsetInBytes += getSizeInBytes(C); + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; + + FieldValue.trunc(FieldValue.getBitWidth() - 8); } - void AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; - AppendPadding(NumPadBytes); + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); } - void ConvertStructToPacked() { - std::vector<llvm::Constant *> PackedElements; - uint64_t ElementOffsetInBytes = 0; + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; +} - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - llvm::Constant *C = Elements[i]; +void ConstStructBuilder::AppendPadding(uint64_t NumBytes) { + if (!NumBytes) + return; - unsigned ElementAlign = - CGM.getTargetData().getABITypeAlignment(C->getType()); - uint64_t AlignedElementOffsetInBytes = - llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { - // We need some padding. - uint64_t NumBytes = - AlignedElementOffsetInBytes - ElementOffsetInBytes; + llvm::Constant *C = llvm::Constant::getNullValue(Ty); + Elements.push_back(C); + assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + NextFieldOffsetInBytes += getSizeInBytes(C); +} - llvm::Constant *Padding = llvm::Constant::getNullValue(Ty); - PackedElements.push_back(Padding); - ElementOffsetInBytes += getSizeInBytes(Padding); - } +void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); - PackedElements.push_back(C); - ElementOffsetInBytes += getSizeInBytes(C); - } + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - assert(ElementOffsetInBytes == NextFieldOffsetInBytes && - "Packing the struct changed its size!"); + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendPadding(NumPadBytes); +} - Elements = PackedElements; - LLVMStructAlignment = 1; - Packed = true; - } - - bool Build(InitListExpr *ILE) { - RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - - unsigned FieldNo = 0; - unsigned ElementNo = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - ElementNo < ILE->getNumInits() && Field != FieldEnd; - ++Field, ++FieldNo) { - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) - continue; +void ConstStructBuilder::ConvertStructToPacked() { + std::vector<llvm::Constant *> PackedElements; + uint64_t ElementOffsetInBytes = 0; - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + llvm::Constant *C = Elements[i]; - if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } else { - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } + unsigned ElementAlign = + CGM.getTargetData().getABITypeAlignment(C->getType()); + uint64_t AlignedElementOffsetInBytes = + llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); - ElementNo++; - } + if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + // We need some padding. + uint64_t NumBytes = + AlignedElementOffsetInBytes - ElementOffsetInBytes; - uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - if (NextFieldOffsetInBytes > LayoutSizeInBytes) { - // If the struct is bigger than the size of the record type, - // we must have a flexible array member at the end. - assert(RD->hasFlexibleArrayMember() && - "Must have flexible array member if struct is bigger than type!"); - - // No tail padding is necessary. - return true; + llvm::Constant *Padding = llvm::Constant::getNullValue(Ty); + PackedElements.push_back(Padding); + ElementOffsetInBytes += getSizeInBytes(Padding); } - uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, - LLVMStructAlignment); + PackedElements.push_back(C); + ElementOffsetInBytes += getSizeInBytes(C); + } - // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInBytes <= LayoutSizeInBytes && - LLVMSizeInBytes > LayoutSizeInBytes) { - assert(!Packed && "Size mismatch!"); - - ConvertStructToPacked(); - assert(NextFieldOffsetInBytes == LayoutSizeInBytes && - "Converting to packed did not help!"); - } + assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + "Packing the struct changed its size!"); - // Append tail padding if necessary. - AppendTailPadding(Layout.getSize()); + Elements = PackedElements; + LLVMStructAlignment = 1; + Packed = true; +} + +bool ConstStructBuilder::Build(InitListExpr *ILE) { + RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + unsigned FieldNo = 0; + unsigned ElementNo = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + ElementNo < ILE->getNumInits() && Field != FieldEnd; + ++Field, ++FieldNo) { + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + if (Field->isBitField()) { + if (!Field->getIdentifier()) + continue; - assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && - "Tail padding mismatch!"); + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), + ILE->getInit(ElementNo))) + return false; + } else { + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), + ILE->getInit(ElementNo))) + return false; + } - return true; + ElementNo++; } - unsigned getAlignment(const llvm::Constant *C) const { - if (Packed) - return 1; - - return CGM.getTargetData().getABITypeAlignment(C->getType()); - } + uint64_t LayoutSizeInBytes = Layout.getSize() / 8; - uint64_t getSizeInBytes(const llvm::Constant *C) const { - return CGM.getTargetData().getTypeAllocSize(C->getType()); + if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + // If the struct is bigger than the size of the record type, + // we must have a flexible array member at the end. + assert(RD->hasFlexibleArrayMember() && + "Must have flexible array member if struct is bigger than type!"); + + // No tail padding is necessary. + return true; } -public: - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, - InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); + uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, + LLVMStructAlignment); - if (!Builder.Build(ILE)) - return 0; + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInBytes <= LayoutSizeInBytes && + LLVMSizeInBytes > LayoutSizeInBytes) { + assert(!Packed && "Size mismatch!"); + + ConvertStructToPacked(); + assert(NextFieldOffsetInBytes == LayoutSizeInBytes && + "Converting to packed did not help!"); + } - llvm::Constant *Result = - llvm::ConstantStruct::get(CGM.getLLVMContext(), - Builder.Elements, Builder.Packed); + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); - assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, - Builder.getAlignment(Result)) == - Builder.getSizeInBytes(Result) && "Size mismatch!"); + assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && + "Tail padding mismatch!"); - return Result; - } -}; + return true; +} + +llvm::Constant *ConstStructBuilder:: + BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + llvm::Constant *Result = + llvm::ConstantStruct::get(CGM.getLLVMContext(), + Builder.Elements, Builder.Packed); + + assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, + Builder.getAlignment(Result)) == + Builder.getSizeInBytes(Result) && "Size mismatch!"); + + return Result; +} + +//===----------------------------------------------------------------------===// +// ConstExprEmitter +//===----------------------------------------------------------------------===// + class ConstExprEmitter : public StmtVisitor<ConstExprEmitter, llvm::Constant*> { CodeGenModule &CGM; |