diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -174,16 +174,34 @@ /// well-defined bitwise representation. SmallVector NonIntegralAddressSpaces; + /// Attempts to set the alignment of the given type. Returns an error + /// description on failure. + Error trySetAlignment(AlignTypeEnum align_type, Align abi_align, + Align pref_align, uint32_t bit_width); + /// Sets the alignment of the given type. Aborts on error. void setAlignment(AlignTypeEnum align_type, Align abi_align, Align pref_align, uint32_t bit_width); + Align getAlignmentInfo(AlignTypeEnum align_type, uint32_t bit_width, bool ABIAlign, Type *Ty) const; + + /// Attempts to set the alignment of a pointer in the given address space. + /// Returns an error description on failure. + Error trySetPointerAlignment(uint32_t AddrSpace, Align ABIAlign, + Align PrefAlign, uint32_t TypeByteWidth, + uint32_t IndexWidth); + /// Sets the alignment of a pointer in the given address space. Aborts on + /// error. void setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, Align PrefAlign, uint32_t TypeByteWidth, uint32_t IndexWidth); /// Internal helper method that returns requested alignment for type. Align getAlignment(Type *Ty, bool abi_or_pref) const; + /// Attempts to parse a target data specification string and reports an error + /// if the string is malformed. + Error tryParseSpecifier(StringRef Desc); + /// Parses a target data specification string. Assert if the string is /// malformed. void parseSpecifier(StringRef LayoutDescription); @@ -229,6 +247,10 @@ /// Parse a data layout string (with fallback to default values). void reset(StringRef LayoutDescription); + /// Parse a data layout string and return the layout. Return an error + /// description on failure. + static Expected parse(StringRef LayoutDescription); + /// Layout endianness... bool isLittleEndian() const { return !BigEndian; } bool isBigEndian() const { return BigEndian; } diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TypeSize.h" @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -196,49 +198,76 @@ parseSpecifier(Desc); } +Expected DataLayout::parse(StringRef LayoutDescription) { + DataLayout layout(""); + if (Error e = layout.tryParseSpecifier(LayoutDescription)) + return std::move(e); + return layout; +} + +static Error reportError(Twine message) { + // TODO: chose the proper error code! + return createStringError(std::error_code(42, std::generic_category()), + message); +} + /// Checked version of split, to ensure mandatory subparts. -static std::pair split(StringRef Str, char Separator) { +static Error split(StringRef Str, char Separator, + std::pair &Split) { assert(!Str.empty() && "parse error, string can't be empty here"); - std::pair Split = Str.split(Separator); + Split = Str.split(Separator); if (Split.second.empty() && Split.first != Str) - report_fatal_error("Trailing separator in datalayout string"); + return reportError("Trailing separator in datalayout string"); if (!Split.second.empty() && Split.first.empty()) - report_fatal_error("Expected token before separator in datalayout string"); - return Split; + return reportError("Expected token before separator in datalayout string"); + return Error::success(); } /// Get an unsigned integer, including error checks. -static unsigned getInt(StringRef R) { - unsigned Result; +template static Error getInt(StringRef R, IntTy &Result) { bool error = R.getAsInteger(10, Result); (void)error; if (error) - report_fatal_error("not a number, or does not fit in an unsigned int"); - return Result; + return reportError("not a number, or does not fit in an unsigned int"); + return Error::success(); } -/// Convert bits into bytes. Assert if not a byte width multiple. -static unsigned inBytes(unsigned Bits) { - if (Bits % 8) - report_fatal_error("number of bits must be a byte width multiple"); - return Bits / 8; +/// Get an unsigned integer representing the number of bits and convert it into +/// bytes. Error out of not a byte width multiple. +template +static Error getIntInBytes(StringRef R, IntTy &Result) { + if (Error e = getInt(R, Result)) + return e; + if (Result % 8) + return reportError("number of bits must be a byte width multiple"); + Result /= 8; + return Error::success(); } -static unsigned getAddrSpace(StringRef R) { - unsigned AddrSpace = getInt(R); +static Error getAddrSpace(StringRef R, unsigned &AddrSpace) { + if (Error e = getInt(R, AddrSpace)) + return e; if (!isUInt<24>(AddrSpace)) - report_fatal_error("Invalid address space, must be a 24-bit integer"); - return AddrSpace; + return reportError("Invalid address space, must be a 24-bit integer"); + return Error::success(); +} + +void DataLayout::parseSpecifier(StringRef LayoutDescription) { + if (Error err = tryParseSpecifier(LayoutDescription)) + report_fatal_error(std::move(err)); } -void DataLayout::parseSpecifier(StringRef Desc) { +Error DataLayout::tryParseSpecifier(StringRef Desc) { StringRepresentation = std::string(Desc); while (!Desc.empty()) { // Split at '-'. - std::pair Split = split(Desc, '-'); + std::pair Split; + if (Error e = split(Desc, '-', Split)) + return e; Desc = Split.second; // Split at ':'. - Split = split(Split.first, ':'); + if (Error e = split(Split.first, ':', Split)) + return e; // Aliases used below. StringRef &Tok = Split.first; // Current token. @@ -246,11 +275,14 @@ if (Tok == "ni") { do { - Split = split(Rest, ':'); + if (Error e = split(Rest, ':', Split)) + return e; Rest = Split.second; - unsigned AS = getInt(Split.first); + unsigned AS; + if (Error e = getInt(Split.first, AS)) + return e; if (AS == 0) - report_fatal_error("Address space 0 can never be non-integral"); + return reportError("Address space 0 can never be non-integral"); NonIntegralAddressSpaces.push_back(AS); } while (!Rest.empty()); @@ -273,28 +305,36 @@ break; case 'p': { // Address space. - unsigned AddrSpace = Tok.empty() ? 0 : getInt(Tok); + unsigned AddrSpace = 0; + if (!Tok.empty()) + if (Error e = getInt(Tok, AddrSpace)) + return e; if (!isUInt<24>(AddrSpace)) - report_fatal_error("Invalid address space, must be a 24bit integer"); + return reportError("Invalid address space, must be a 24bit integer"); // Size. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing size specification for pointer in datalayout string"); - Split = split(Rest, ':'); - unsigned PointerMemSize = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + unsigned PointerMemSize; + if (Error e = getIntInBytes(Tok, PointerMemSize)) + return e; if (!PointerMemSize) - report_fatal_error("Invalid pointer size of 0 bytes"); + return reportError("Invalid pointer size of 0 bytes"); // ABI alignment. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing alignment specification for pointer in datalayout string"); - Split = split(Rest, ':'); - unsigned PointerABIAlign = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + unsigned PointerABIAlign; + if (Error e = getIntInBytes(Tok, PointerABIAlign)) + return e; if (!isPowerOf2_64(PointerABIAlign)) - report_fatal_error( - "Pointer ABI alignment must be a power of 2"); + return reportError("Pointer ABI alignment must be a power of 2"); // Size of index used in GEP for address calculation. // The parameter is optional. By default it is equal to size of pointer. @@ -303,23 +343,28 @@ // Preferred alignment. unsigned PointerPrefAlign = PointerABIAlign; if (!Rest.empty()) { - Split = split(Rest, ':'); - PointerPrefAlign = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + if (Error e = getIntInBytes(Tok, PointerPrefAlign)) + return e; if (!isPowerOf2_64(PointerPrefAlign)) - report_fatal_error( - "Pointer preferred alignment must be a power of 2"); + return reportError( + "Pointer preferred alignment must be a power of 2"); // Now read the index. It is the second optional parameter here. if (!Rest.empty()) { - Split = split(Rest, ':'); - IndexSize = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + if (Error e = getIntInBytes(Tok, IndexSize)) + return e; if (!IndexSize) - report_fatal_error("Invalid index size of 0 bytes"); + return reportError("Invalid index size of 0 bytes"); } } - setPointerAlignment(AddrSpace, assumeAligned(PointerABIAlign), - assumeAligned(PointerPrefAlign), PointerMemSize, - IndexSize); + if (Error e = trySetPointerAlignment( + AddrSpace, assumeAligned(PointerABIAlign), + assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize)) + return e; break; } case 'i': @@ -336,61 +381,75 @@ } // Bit size. - unsigned Size = Tok.empty() ? 0 : getInt(Tok); + unsigned Size = 0; + if (!Tok.empty()) + if (Error e = getInt(Tok, Size)) + return e; if (AlignType == AGGREGATE_ALIGN && Size != 0) - report_fatal_error( + return reportError( "Sized aggregate specification in datalayout string"); // ABI alignment. if (Rest.empty()) - report_fatal_error( + return reportError( "Missing alignment specification in datalayout string"); - Split = split(Rest, ':'); - const unsigned ABIAlign = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + unsigned ABIAlign; + if (Error e = getIntInBytes(Tok, ABIAlign)) + return e; if (AlignType != AGGREGATE_ALIGN && !ABIAlign) - report_fatal_error( + return reportError( "ABI alignment specification must be >0 for non-aggregate types"); if (!isUInt<16>(ABIAlign)) - report_fatal_error("Invalid ABI alignment, must be a 16bit integer"); + return reportError("Invalid ABI alignment, must be a 16bit integer"); if (ABIAlign != 0 && !isPowerOf2_64(ABIAlign)) - report_fatal_error("Invalid ABI alignment, must be a power of 2"); + return reportError("Invalid ABI alignment, must be a power of 2"); // Preferred alignment. unsigned PrefAlign = ABIAlign; if (!Rest.empty()) { - Split = split(Rest, ':'); - PrefAlign = inBytes(getInt(Tok)); + if (Error e = split(Rest, ':', Split)) + return e; + if (Error e = getIntInBytes(Tok, PrefAlign)) + return e; } if (!isUInt<16>(PrefAlign)) - report_fatal_error( + return reportError( "Invalid preferred alignment, must be a 16bit integer"); if (PrefAlign != 0 && !isPowerOf2_64(PrefAlign)) - report_fatal_error("Invalid preferred alignment, must be a power of 2"); + return reportError("Invalid preferred alignment, must be a power of 2"); - setAlignment(AlignType, assumeAligned(ABIAlign), assumeAligned(PrefAlign), - Size); + if (Error e = trySetAlignment(AlignType, assumeAligned(ABIAlign), + assumeAligned(PrefAlign), Size)) + return e; break; } case 'n': // Native integer types. while (true) { - unsigned Width = getInt(Tok); + unsigned Width; + if (Error e = getInt(Tok, Width)) + return e; if (Width == 0) - report_fatal_error( + return reportError( "Zero width native integer type in datalayout string"); LegalIntWidths.push_back(Width); if (Rest.empty()) break; - Split = split(Rest, ':'); + if (Error e = split(Rest, ':', Split)) + return e; } break; case 'S': { // Stack natural alignment. - uint64_t Alignment = inBytes(getInt(Tok)); + uint64_t Alignment; + if (Error e = getIntInBytes(Tok, Alignment)) + return e; if (Alignment != 0 && !llvm::isPowerOf2_64(Alignment)) - report_fatal_error("Alignment is neither 0 nor a power of 2"); + return reportError("Alignment is neither 0 nor a power of 2"); StackNaturalAlign = MaybeAlign(Alignment); break; } @@ -403,34 +462,39 @@ TheFunctionPtrAlignType = FunctionPtrAlignType::MultipleOfFunctionAlign; break; default: - report_fatal_error("Unknown function pointer alignment type in " + return reportError("Unknown function pointer alignment type in " "datalayout string"); } Tok = Tok.substr(1); - uint64_t Alignment = inBytes(getInt(Tok)); + uint64_t Alignment; + if (Error e = getIntInBytes(Tok, Alignment)) + return e; if (Alignment != 0 && !llvm::isPowerOf2_64(Alignment)) - report_fatal_error("Alignment is neither 0 nor a power of 2"); + return reportError("Alignment is neither 0 nor a power of 2"); FunctionPtrAlign = MaybeAlign(Alignment); break; } case 'P': { // Function address space. - ProgramAddrSpace = getAddrSpace(Tok); + if (Error e = getAddrSpace(Tok, ProgramAddrSpace)) + return e; break; } case 'A': { // Default stack/alloca address space. - AllocaAddrSpace = getAddrSpace(Tok); + if (Error e = getAddrSpace(Tok, AllocaAddrSpace)) + return e; break; } case 'm': if (!Tok.empty()) - report_fatal_error("Unexpected trailing characters after mangling specifier in datalayout string"); + return reportError("Unexpected trailing characters after mangling " + "specifier in datalayout string"); if (Rest.empty()) - report_fatal_error("Expected mangling specifier in datalayout string"); + return reportError("Expected mangling specifier in datalayout string"); if (Rest.size() > 1) - report_fatal_error("Unknown mangling specifier in datalayout string"); + return reportError("Unknown mangling specifier in datalayout string"); switch(Rest[0]) { default: - report_fatal_error("Unknown mangling in datalayout string"); + return reportError("Unknown mangling in datalayout string"); case 'e': ManglingMode = MM_ELF; break; @@ -452,10 +516,12 @@ } break; default: - report_fatal_error("Unknown specifier in datalayout string"); + return reportError("Unknown specifier in datalayout string"); break; } } + + return Error::success(); } DataLayout::DataLayout(const Module *M) { @@ -487,17 +553,17 @@ }); } -void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align, - Align pref_align, uint32_t bit_width) { +Error DataLayout::trySetAlignment(AlignTypeEnum align_type, Align abi_align, + Align pref_align, uint32_t bit_width) { // AlignmentsTy::ABIAlign and AlignmentsTy::PrefAlign were once stored as // uint16_t, it is unclear if there are requirements for alignment to be less // than 2^16 other than storage. In the meantime we leave the restriction as // an assert. See D67400 for context. assert(Log2(abi_align) < 16 && Log2(pref_align) < 16 && "Alignment too big"); if (!isUInt<24>(bit_width)) - report_fatal_error("Invalid bit width, must be a 24bit integer"); + return reportError("Invalid bit width, must be a 24bit integer"); if (pref_align < abi_align) - report_fatal_error( + return reportError( "Preferred alignment cannot be less than the ABI alignment"); AlignmentsTy::iterator I = findAlignmentLowerBound(align_type, bit_width); @@ -511,6 +577,13 @@ Alignments.insert(I, LayoutAlignElem::get(align_type, abi_align, pref_align, bit_width)); } + return Error::success(); +} + +void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align, + Align pref_align, uint32_t bit_width) { + if (Error e = trySetAlignment(align_type, abi_align, pref_align, bit_width)) + report_fatal_error(std::move(e)); } DataLayout::PointersTy::iterator @@ -521,11 +594,12 @@ }); } -void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, - Align PrefAlign, uint32_t TypeByteWidth, - uint32_t IndexWidth) { +Error DataLayout::trySetPointerAlignment(uint32_t AddrSpace, Align ABIAlign, + Align PrefAlign, + uint32_t TypeByteWidth, + uint32_t IndexWidth) { if (PrefAlign < ABIAlign) - report_fatal_error( + return reportError( "Preferred alignment cannot be less than the ABI alignment"); PointersTy::iterator I = findPointerLowerBound(AddrSpace); @@ -538,6 +612,15 @@ I->TypeByteWidth = TypeByteWidth; I->IndexWidth = IndexWidth; } + return Error::success(); +} + +void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, + Align PrefAlign, uint32_t TypeByteWidth, + uint32_t IndexWidth) { + if (Error e = trySetPointerAlignment(AddrSpace, ABIAlign, PrefAlign, + TypeByteWidth, IndexWidth)) + return report_fatal_error(std::move(e)); } /// getAlignmentInfo - Return the alignment (either ABI if ABIInfo = true or