1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[llvm] support graceful failure of DataLayout parsing

Existing implementation always aborts on syntax errors in a DataLayout
description. While this is meaningful for consuming textual IR modules, it is
inconvenient for users that may need fine-grained control over the layout from,
e.g., command-line options. Propagate errors through the parsing functions and
only abort in the top-level parsing function instead.

Reviewed By: mehdi_amini

Differential Revision: https://reviews.llvm.org/D85650
This commit is contained in:
Alex Zinenko 2020-08-17 13:34:07 +02:00
parent 79d0f5426e
commit 544267f834
2 changed files with 166 additions and 93 deletions

View File

@ -174,19 +174,25 @@ private:
/// well-defined bitwise representation.
SmallVector<unsigned, 8> NonIntegralAddressSpaces;
void setAlignment(AlignTypeEnum align_type, Align abi_align, Align pref_align,
uint32_t bit_width);
/// Attempts to set the alignment of the given type. Returns an error
/// description on failure.
Error 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;
void setPointerAlignment(uint32_t AddrSpace, Align ABIAlign, Align PrefAlign,
uint32_t TypeByteWidth, uint32_t IndexWidth);
/// Attempts to set the alignment of a pointer in the given address space.
/// Returns an error description on failure.
Error 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;
/// Parses a target data specification string. Assert if the string is
/// malformed.
void parseSpecifier(StringRef LayoutDescription);
/// Attempts to parse a target data specification string and reports an error
/// if the string is malformed.
Error parseSpecifier(StringRef Desc);
// Free all internal data structures.
void clear();
@ -229,6 +235,10 @@ public:
/// 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<DataLayout> parse(StringRef LayoutDescription);
/// Layout endianness...
bool isLittleEndian() const { return !BigEndian; }
bool isBigEndian() const { return BigEndian; }

View File

@ -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"
@ -188,57 +189,80 @@ void DataLayout::reset(StringRef Desc) {
// Default alignments
for (const LayoutAlignElem &E : DefaultAlignments) {
setAlignment((AlignTypeEnum)E.AlignType, E.ABIAlign, E.PrefAlign,
E.TypeBitWidth);
if (Error Err = setAlignment((AlignTypeEnum)E.AlignType, E.ABIAlign,
E.PrefAlign, E.TypeBitWidth))
return report_fatal_error(std::move(Err));
}
setPointerAlignment(0, Align(8), Align(8), 8, 8);
if (Error Err = setPointerAlignment(0, Align(8), Align(8), 8, 8))
return report_fatal_error(std::move(Err));
parseSpecifier(Desc);
if (Error Err = parseSpecifier(Desc))
return report_fatal_error(std::move(Err));
}
Expected<DataLayout> DataLayout::parse(StringRef LayoutDescription) {
DataLayout Layout("");
if (Error Err = Layout.parseSpecifier(LayoutDescription))
return std::move(Err);
return Layout;
}
static Error reportError(const Twine &Message) {
return createStringError(inconvertibleErrorCode(), Message);
}
/// Checked version of split, to ensure mandatory subparts.
static std::pair<StringRef, StringRef> split(StringRef Str, char Separator) {
static Error split(StringRef Str, char Separator,
std::pair<StringRef, StringRef> &Split) {
assert(!Str.empty() && "parse error, string can't be empty here");
std::pair<StringRef, StringRef> 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 <typename IntTy> 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 <typename IntTy>
static Error getIntInBytes(StringRef R, IntTy &Result) {
if (Error Err = getInt<IntTy>(R, Result))
return Err;
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 Err = getInt(R, AddrSpace))
return Err;
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 Desc) {
Error DataLayout::parseSpecifier(StringRef Desc) {
StringRepresentation = std::string(Desc);
while (!Desc.empty()) {
// Split at '-'.
std::pair<StringRef, StringRef> Split = split(Desc, '-');
std::pair<StringRef, StringRef> Split;
if (Error Err = split(Desc, '-', Split))
return Err;
Desc = Split.second;
// Split at ':'.
Split = split(Split.first, ':');
if (Error Err = split(Split.first, ':', Split))
return Err;
// Aliases used below.
StringRef &Tok = Split.first; // Current token.
@ -246,11 +270,14 @@ void DataLayout::parseSpecifier(StringRef Desc) {
if (Tok == "ni") {
do {
Split = split(Rest, ':');
if (Error Err = split(Rest, ':', Split))
return Err;
Rest = Split.second;
unsigned AS = getInt(Split.first);
unsigned AS;
if (Error Err = getInt(Split.first, AS))
return Err;
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 +300,36 @@ void DataLayout::parseSpecifier(StringRef Desc) {
break;
case 'p': {
// Address space.
unsigned AddrSpace = Tok.empty() ? 0 : getInt(Tok);
unsigned AddrSpace = 0;
if (!Tok.empty())
if (Error Err = getInt(Tok, AddrSpace))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
unsigned PointerMemSize;
if (Error Err = getIntInBytes(Tok, PointerMemSize))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
unsigned PointerABIAlign;
if (Error Err = getIntInBytes(Tok, PointerABIAlign))
return Err;
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 +338,28 @@ void DataLayout::parseSpecifier(StringRef Desc) {
// Preferred alignment.
unsigned PointerPrefAlign = PointerABIAlign;
if (!Rest.empty()) {
Split = split(Rest, ':');
PointerPrefAlign = inBytes(getInt(Tok));
if (Error Err = split(Rest, ':', Split))
return Err;
if (Error Err = getIntInBytes(Tok, PointerPrefAlign))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
if (Error Err = getIntInBytes(Tok, IndexSize))
return Err;
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 Err = setPointerAlignment(
AddrSpace, assumeAligned(PointerABIAlign),
assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize))
return Err;
break;
}
case 'i':
@ -336,61 +376,75 @@ void DataLayout::parseSpecifier(StringRef Desc) {
}
// Bit size.
unsigned Size = Tok.empty() ? 0 : getInt(Tok);
unsigned Size = 0;
if (!Tok.empty())
if (Error Err = getInt(Tok, Size))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
unsigned ABIAlign;
if (Error Err = getIntInBytes(Tok, ABIAlign))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
if (Error Err = getIntInBytes(Tok, PrefAlign))
return Err;
}
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 Err = setAlignment(AlignType, assumeAligned(ABIAlign),
assumeAligned(PrefAlign), Size))
return Err;
break;
}
case 'n': // Native integer types.
while (true) {
unsigned Width = getInt(Tok);
unsigned Width;
if (Error Err = getInt(Tok, Width))
return Err;
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 Err = split(Rest, ':', Split))
return Err;
}
break;
case 'S': { // Stack natural alignment.
uint64_t Alignment = inBytes(getInt(Tok));
uint64_t Alignment;
if (Error Err = getIntInBytes(Tok, Alignment))
return Err;
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 +457,39 @@ void DataLayout::parseSpecifier(StringRef Desc) {
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 Err = getIntInBytes(Tok, Alignment))
return Err;
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 Err = getAddrSpace(Tok, ProgramAddrSpace))
return Err;
break;
}
case 'A': { // Default stack/alloca address space.
AllocaAddrSpace = getAddrSpace(Tok);
if (Error Err = getAddrSpace(Tok, AllocaAddrSpace))
return Err;
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 +511,12 @@ void DataLayout::parseSpecifier(StringRef Desc) {
}
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 +548,17 @@ DataLayout::findAlignmentLowerBound(AlignTypeEnum AlignType,
});
}
void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align,
Align pref_align, uint32_t bit_width) {
Error DataLayout::setAlignment(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 +572,7 @@ void DataLayout::setAlignment(AlignTypeEnum align_type, Align abi_align,
Alignments.insert(I, LayoutAlignElem::get(align_type, abi_align,
pref_align, bit_width));
}
return Error::success();
}
DataLayout::PointersTy::iterator
@ -521,11 +583,11 @@ DataLayout::findPointerLowerBound(uint32_t AddressSpace) {
});
}
void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign,
Align PrefAlign, uint32_t TypeByteWidth,
uint32_t IndexWidth) {
Error DataLayout::setPointerAlignment(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 +600,7 @@ void DataLayout::setPointerAlignment(uint32_t AddrSpace, Align ABIAlign,
I->TypeByteWidth = TypeByteWidth;
I->IndexWidth = IndexWidth;
}
return Error::success();
}
/// getAlignmentInfo - Return the alignment (either ABI if ABIInfo = true or