Vendor import of llvm-project branch release/11.x
llvmorg-11.0.0-rc2-91-g6e042866c30.
This commit is contained in:
parent
bdc6feb28f
commit
e588341d48
@ -60,6 +60,7 @@
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/TypeSize.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@ -1297,6 +1298,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// Returns a vla type where known sizes are replaced with [*].
|
||||
QualType getVariableArrayDecayedType(QualType Ty) const;
|
||||
|
||||
// Convenience struct to return information about a builtin vector type.
|
||||
struct BuiltinVectorTypeInfo {
|
||||
QualType ElementType;
|
||||
llvm::ElementCount EC;
|
||||
unsigned NumVectors;
|
||||
BuiltinVectorTypeInfo(QualType ElementType, llvm::ElementCount EC,
|
||||
unsigned NumVectors)
|
||||
: ElementType(ElementType), EC(EC), NumVectors(NumVectors) {}
|
||||
};
|
||||
|
||||
/// Returns the element type, element count and number of vectors
|
||||
/// (in case of tuple) for a builtin vector type.
|
||||
BuiltinVectorTypeInfo
|
||||
getBuiltinVectorTypeInfo(const BuiltinType *VecTy) const;
|
||||
|
||||
/// Return the unique reference to a scalable vector type of the specified
|
||||
/// element type and scalable number of elements.
|
||||
///
|
||||
|
@ -6021,9 +6021,8 @@ def err_func_def_incomplete_result : Error<
|
||||
def err_atomic_specifier_bad_type
|
||||
: Error<"_Atomic cannot be applied to "
|
||||
"%select{incomplete |array |function |reference |atomic |qualified "
|
||||
"|sizeless ||integer |integer }0type "
|
||||
"%1 %select{|||||||which is not trivially copyable|with less than "
|
||||
"1 byte of precision|with a non power of 2 precision}0">;
|
||||
"|sizeless ||integer }0type "
|
||||
"%1 %select{|||||||which is not trivially copyable|}0">;
|
||||
|
||||
// Expressions.
|
||||
def ext_sizeof_alignof_function_type : Extension<
|
||||
@ -7941,6 +7940,8 @@ def err_atomic_exclusive_builtin_pointer_size : Error<
|
||||
" 1,2,4 or 8 byte type (%0 invalid)">;
|
||||
def err_atomic_builtin_ext_int_size : Error<
|
||||
"Atomic memory operand must have a power-of-two size">;
|
||||
def err_atomic_builtin_ext_int_prohibit : Error<
|
||||
"argument to atomic builtin of type '_ExtInt' is not supported">;
|
||||
def err_atomic_op_needs_atomic : Error<
|
||||
"address argument to atomic operation must be a pointer to _Atomic "
|
||||
"type (%0 invalid)">;
|
||||
|
@ -3634,6 +3634,119 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
|
||||
return QualType(newType, 0);
|
||||
}
|
||||
|
||||
ASTContext::BuiltinVectorTypeInfo
|
||||
ASTContext::getBuiltinVectorTypeInfo(const BuiltinType *Ty) const {
|
||||
#define SVE_INT_ELTTY(BITS, ELTS, SIGNED, NUMVECTORS) \
|
||||
{getIntTypeForBitwidth(BITS, SIGNED), llvm::ElementCount(ELTS, true), \
|
||||
NUMVECTORS};
|
||||
|
||||
#define SVE_ELTTY(ELTTY, ELTS, NUMVECTORS) \
|
||||
{ELTTY, llvm::ElementCount(ELTS, true), NUMVECTORS};
|
||||
|
||||
switch (Ty->getKind()) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported builtin vector type");
|
||||
case BuiltinType::SveInt8:
|
||||
return SVE_INT_ELTTY(8, 16, true, 1);
|
||||
case BuiltinType::SveUint8:
|
||||
return SVE_INT_ELTTY(8, 16, false, 1);
|
||||
case BuiltinType::SveInt8x2:
|
||||
return SVE_INT_ELTTY(8, 16, true, 2);
|
||||
case BuiltinType::SveUint8x2:
|
||||
return SVE_INT_ELTTY(8, 16, false, 2);
|
||||
case BuiltinType::SveInt8x3:
|
||||
return SVE_INT_ELTTY(8, 16, true, 3);
|
||||
case BuiltinType::SveUint8x3:
|
||||
return SVE_INT_ELTTY(8, 16, false, 3);
|
||||
case BuiltinType::SveInt8x4:
|
||||
return SVE_INT_ELTTY(8, 16, true, 4);
|
||||
case BuiltinType::SveUint8x4:
|
||||
return SVE_INT_ELTTY(8, 16, false, 4);
|
||||
case BuiltinType::SveInt16:
|
||||
return SVE_INT_ELTTY(16, 8, true, 1);
|
||||
case BuiltinType::SveUint16:
|
||||
return SVE_INT_ELTTY(16, 8, false, 1);
|
||||
case BuiltinType::SveInt16x2:
|
||||
return SVE_INT_ELTTY(16, 8, true, 2);
|
||||
case BuiltinType::SveUint16x2:
|
||||
return SVE_INT_ELTTY(16, 8, false, 2);
|
||||
case BuiltinType::SveInt16x3:
|
||||
return SVE_INT_ELTTY(16, 8, true, 3);
|
||||
case BuiltinType::SveUint16x3:
|
||||
return SVE_INT_ELTTY(16, 8, false, 3);
|
||||
case BuiltinType::SveInt16x4:
|
||||
return SVE_INT_ELTTY(16, 8, true, 4);
|
||||
case BuiltinType::SveUint16x4:
|
||||
return SVE_INT_ELTTY(16, 8, false, 4);
|
||||
case BuiltinType::SveInt32:
|
||||
return SVE_INT_ELTTY(32, 4, true, 1);
|
||||
case BuiltinType::SveUint32:
|
||||
return SVE_INT_ELTTY(32, 4, false, 1);
|
||||
case BuiltinType::SveInt32x2:
|
||||
return SVE_INT_ELTTY(32, 4, true, 2);
|
||||
case BuiltinType::SveUint32x2:
|
||||
return SVE_INT_ELTTY(32, 4, false, 2);
|
||||
case BuiltinType::SveInt32x3:
|
||||
return SVE_INT_ELTTY(32, 4, true, 3);
|
||||
case BuiltinType::SveUint32x3:
|
||||
return SVE_INT_ELTTY(32, 4, false, 3);
|
||||
case BuiltinType::SveInt32x4:
|
||||
return SVE_INT_ELTTY(32, 4, true, 4);
|
||||
case BuiltinType::SveUint32x4:
|
||||
return SVE_INT_ELTTY(32, 4, false, 4);
|
||||
case BuiltinType::SveInt64:
|
||||
return SVE_INT_ELTTY(64, 2, true, 1);
|
||||
case BuiltinType::SveUint64:
|
||||
return SVE_INT_ELTTY(64, 2, false, 1);
|
||||
case BuiltinType::SveInt64x2:
|
||||
return SVE_INT_ELTTY(64, 2, true, 2);
|
||||
case BuiltinType::SveUint64x2:
|
||||
return SVE_INT_ELTTY(64, 2, false, 2);
|
||||
case BuiltinType::SveInt64x3:
|
||||
return SVE_INT_ELTTY(64, 2, true, 3);
|
||||
case BuiltinType::SveUint64x3:
|
||||
return SVE_INT_ELTTY(64, 2, false, 3);
|
||||
case BuiltinType::SveInt64x4:
|
||||
return SVE_INT_ELTTY(64, 2, true, 4);
|
||||
case BuiltinType::SveUint64x4:
|
||||
return SVE_INT_ELTTY(64, 2, false, 4);
|
||||
case BuiltinType::SveBool:
|
||||
return SVE_ELTTY(BoolTy, 16, 1);
|
||||
case BuiltinType::SveFloat16:
|
||||
return SVE_ELTTY(HalfTy, 8, 1);
|
||||
case BuiltinType::SveFloat16x2:
|
||||
return SVE_ELTTY(HalfTy, 8, 2);
|
||||
case BuiltinType::SveFloat16x3:
|
||||
return SVE_ELTTY(HalfTy, 8, 3);
|
||||
case BuiltinType::SveFloat16x4:
|
||||
return SVE_ELTTY(HalfTy, 8, 4);
|
||||
case BuiltinType::SveFloat32:
|
||||
return SVE_ELTTY(FloatTy, 4, 1);
|
||||
case BuiltinType::SveFloat32x2:
|
||||
return SVE_ELTTY(FloatTy, 4, 2);
|
||||
case BuiltinType::SveFloat32x3:
|
||||
return SVE_ELTTY(FloatTy, 4, 3);
|
||||
case BuiltinType::SveFloat32x4:
|
||||
return SVE_ELTTY(FloatTy, 4, 4);
|
||||
case BuiltinType::SveFloat64:
|
||||
return SVE_ELTTY(DoubleTy, 2, 1);
|
||||
case BuiltinType::SveFloat64x2:
|
||||
return SVE_ELTTY(DoubleTy, 2, 2);
|
||||
case BuiltinType::SveFloat64x3:
|
||||
return SVE_ELTTY(DoubleTy, 2, 3);
|
||||
case BuiltinType::SveFloat64x4:
|
||||
return SVE_ELTTY(DoubleTy, 2, 4);
|
||||
case BuiltinType::SveBFloat16:
|
||||
return SVE_ELTTY(BFloat16Ty, 8, 1);
|
||||
case BuiltinType::SveBFloat16x2:
|
||||
return SVE_ELTTY(BFloat16Ty, 8, 2);
|
||||
case BuiltinType::SveBFloat16x3:
|
||||
return SVE_ELTTY(BFloat16Ty, 8, 3);
|
||||
case BuiltinType::SveBFloat16x4:
|
||||
return SVE_ELTTY(BFloat16Ty, 8, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/// getScalableVectorType - Return the unique reference to a scalable vector
|
||||
/// type of the specified element type and size. VectorType must be a built-in
|
||||
/// type.
|
||||
|
@ -1487,6 +1487,13 @@ static bool shouldBeHidden(NamedDecl *D) {
|
||||
if (FD->isFunctionTemplateSpecialization())
|
||||
return true;
|
||||
|
||||
// Hide destructors that are invalid. There should always be one destructor,
|
||||
// but if it is an invalid decl, another one is created. We need to hide the
|
||||
// invalid one from places that expect exactly one destructor, like the
|
||||
// serialization code.
|
||||
if (isa<CXXDestructorDecl>(D) && D->isInvalidDecl())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3248,7 +3248,7 @@ static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
|
||||
case BuiltinType::Double:
|
||||
return "Float64";
|
||||
case BuiltinType::BFloat16:
|
||||
return "BFloat16";
|
||||
return "Bfloat16";
|
||||
default:
|
||||
llvm_unreachable("Unexpected vector element base type");
|
||||
}
|
||||
|
@ -409,8 +409,6 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
|
||||
return new SolarisTargetInfo<SparcV8TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::NetBSD:
|
||||
return new NetBSDTargetInfo<SparcV8TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::OpenBSD:
|
||||
return new OpenBSDTargetInfo<SparcV8TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::RTEMS:
|
||||
return new RTEMSTargetInfo<SparcV8TargetInfo>(Triple, Opts);
|
||||
default:
|
||||
@ -424,8 +422,6 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
|
||||
return new LinuxTargetInfo<SparcV8elTargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::NetBSD:
|
||||
return new NetBSDTargetInfo<SparcV8elTargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::OpenBSD:
|
||||
return new OpenBSDTargetInfo<SparcV8elTargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::RTEMS:
|
||||
return new RTEMSTargetInfo<SparcV8elTargetInfo>(Triple, Opts);
|
||||
default:
|
||||
|
@ -719,23 +719,39 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
|
||||
case BuiltinType::Id: \
|
||||
return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty);
|
||||
#include "clang/Basic/OpenCLExtensionTypes.def"
|
||||
// TODO: real support for SVE types requires more infrastructure
|
||||
// to be added first. The types have a variable length and are
|
||||
// represented in debug info as types whose length depends on a
|
||||
// target-specific pseudo register.
|
||||
#define SVE_TYPE(Name, Id, SingletonId) \
|
||||
case BuiltinType::Id:
|
||||
#include "clang/Basic/AArch64SVEACLETypes.def"
|
||||
{
|
||||
unsigned DiagID = CGM.getDiags().getCustomDiagID(
|
||||
DiagnosticsEngine::Error,
|
||||
"cannot yet generate debug info for SVE type '%0'");
|
||||
auto Name = BT->getName(CGM.getContext().getPrintingPolicy());
|
||||
CGM.getDiags().Report(DiagID) << Name;
|
||||
// Return something safe.
|
||||
return CreateType(cast<const BuiltinType>(CGM.getContext().IntTy));
|
||||
}
|
||||
|
||||
#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
|
||||
#include "clang/Basic/AArch64SVEACLETypes.def"
|
||||
{
|
||||
ASTContext::BuiltinVectorTypeInfo Info =
|
||||
CGM.getContext().getBuiltinVectorTypeInfo(BT);
|
||||
unsigned NumElemsPerVG = (Info.EC.Min * Info.NumVectors) / 2;
|
||||
|
||||
// Debuggers can't extract 1bit from a vector, so will display a
|
||||
// bitpattern for svbool_t instead.
|
||||
if (Info.ElementType == CGM.getContext().BoolTy) {
|
||||
NumElemsPerVG /= 8;
|
||||
Info.ElementType = CGM.getContext().UnsignedCharTy;
|
||||
}
|
||||
|
||||
auto *LowerBound =
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned(
|
||||
llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0));
|
||||
SmallVector<int64_t, 9> Expr(
|
||||
{llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx,
|
||||
/* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul,
|
||||
llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus});
|
||||
auto *UpperBound = DBuilder.createExpression(Expr);
|
||||
|
||||
llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange(
|
||||
/*count*/ nullptr, LowerBound, UpperBound, /*stride*/ nullptr);
|
||||
llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
|
||||
llvm::DIType *ElemTy =
|
||||
getOrCreateType(Info.ElementType, TheCU->getFile());
|
||||
auto Align = getTypeAlignIfRequired(BT, CGM.getContext());
|
||||
return DBuilder.createVectorType(/*Size*/ 0, Align, ElemTy,
|
||||
SubscriptArray);
|
||||
}
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Char_U:
|
||||
Encoding = llvm::dwarf::DW_ATE_unsigned_char;
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "llvm/ADT/SetOperations.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
@ -1064,23 +1063,6 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
|
||||
StringRef Separator)
|
||||
: CGM(CGM), FirstSeparator(FirstSeparator), Separator(Separator),
|
||||
OMPBuilder(CGM.getModule()), OffloadEntriesInfoManager(CGM) {
|
||||
ASTContext &C = CGM.getContext();
|
||||
RecordDecl *RD = C.buildImplicitRecord("ident_t");
|
||||
QualType KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
|
||||
RD->startDefinition();
|
||||
// reserved_1
|
||||
addFieldToRecordDecl(C, RD, KmpInt32Ty);
|
||||
// flags
|
||||
addFieldToRecordDecl(C, RD, KmpInt32Ty);
|
||||
// reserved_2
|
||||
addFieldToRecordDecl(C, RD, KmpInt32Ty);
|
||||
// reserved_3
|
||||
addFieldToRecordDecl(C, RD, KmpInt32Ty);
|
||||
// psource
|
||||
addFieldToRecordDecl(C, RD, C.VoidPtrTy);
|
||||
RD->completeDefinition();
|
||||
IdentQTy = C.getRecordType(RD);
|
||||
IdentTy = CGM.getTypes().ConvertRecordDeclType(RD);
|
||||
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
|
||||
|
||||
// Initialize Types used in OpenMPIRBuilder from OMPKinds.def
|
||||
@ -1397,39 +1379,6 @@ createConstantGlobalStructAndAddToParent(CodeGenModule &CGM, QualType Ty,
|
||||
Fields.finishAndAddTo(Parent);
|
||||
}
|
||||
|
||||
Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) {
|
||||
CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);
|
||||
unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
|
||||
FlagsTy FlagsKey(Flags, Reserved2Flags);
|
||||
llvm::Value *Entry = OpenMPDefaultLocMap.lookup(FlagsKey);
|
||||
if (!Entry) {
|
||||
if (!DefaultOpenMPPSource) {
|
||||
// Initialize default location for psource field of ident_t structure of
|
||||
// all ident_t objects. Format is ";file;function;line;column;;".
|
||||
// Taken from
|
||||
// https://github.com/llvm/llvm-project/blob/master/openmp/runtime/src/kmp_str.cpp
|
||||
DefaultOpenMPPSource =
|
||||
CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;").getPointer();
|
||||
DefaultOpenMPPSource =
|
||||
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
|
||||
}
|
||||
|
||||
llvm::Constant *Data[] = {
|
||||
llvm::ConstantInt::getNullValue(CGM.Int32Ty),
|
||||
llvm::ConstantInt::get(CGM.Int32Ty, Flags),
|
||||
llvm::ConstantInt::get(CGM.Int32Ty, Reserved2Flags),
|
||||
llvm::ConstantInt::getNullValue(CGM.Int32Ty), DefaultOpenMPPSource};
|
||||
llvm::GlobalValue *DefaultOpenMPLocation =
|
||||
createGlobalStruct(CGM, IdentQTy, isDefaultLocationConstant(), Data, "",
|
||||
llvm::GlobalValue::PrivateLinkage);
|
||||
DefaultOpenMPLocation->setUnnamedAddr(
|
||||
llvm::GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
OpenMPDefaultLocMap[FlagsKey] = Entry = DefaultOpenMPLocation;
|
||||
}
|
||||
return Address(Entry, Align);
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::setLocThreadIdInsertPt(CodeGenFunction &CGF,
|
||||
bool AtCurrentPoint) {
|
||||
auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
|
||||
@ -1458,62 +1407,24 @@ void CGOpenMPRuntime::clearLocThreadIdInsertPt(CodeGenFunction &CGF) {
|
||||
llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF,
|
||||
SourceLocation Loc,
|
||||
unsigned Flags) {
|
||||
Flags |= OMP_IDENT_KMPC;
|
||||
// If no debug info is generated - return global default location.
|
||||
llvm::Constant *SrcLocStr;
|
||||
if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo ||
|
||||
Loc.isInvalid())
|
||||
return getOrCreateDefaultLocation(Flags).getPointer();
|
||||
|
||||
assert(CGF.CurFn && "No function in current CodeGenFunction.");
|
||||
|
||||
CharUnits Align = CGM.getContext().getTypeAlignInChars(IdentQTy);
|
||||
Address LocValue = Address::invalid();
|
||||
auto I = OpenMPLocThreadIDMap.find(CGF.CurFn);
|
||||
if (I != OpenMPLocThreadIDMap.end())
|
||||
LocValue = Address(I->second.DebugLoc, Align);
|
||||
|
||||
// OpenMPLocThreadIDMap may have null DebugLoc and non-null ThreadID, if
|
||||
// GetOpenMPThreadID was called before this routine.
|
||||
if (!LocValue.isValid()) {
|
||||
// Generate "ident_t .kmpc_loc.addr;"
|
||||
Address AI = CGF.CreateMemTemp(IdentQTy, ".kmpc_loc.addr");
|
||||
auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
|
||||
Elem.second.DebugLoc = AI.getPointer();
|
||||
LocValue = AI;
|
||||
|
||||
if (!Elem.second.ServiceInsertPt)
|
||||
setLocThreadIdInsertPt(CGF);
|
||||
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
|
||||
CGF.Builder.SetInsertPoint(Elem.second.ServiceInsertPt);
|
||||
CGF.Builder.CreateMemCpy(LocValue, getOrCreateDefaultLocation(Flags),
|
||||
CGF.getTypeSize(IdentQTy));
|
||||
}
|
||||
|
||||
// char **psource = &.kmpc_loc_<flags>.addr.psource;
|
||||
LValue Base = CGF.MakeAddrLValue(LocValue, IdentQTy);
|
||||
auto Fields = cast<RecordDecl>(IdentQTy->getAsTagDecl())->field_begin();
|
||||
LValue PSource =
|
||||
CGF.EmitLValueForField(Base, *std::next(Fields, IdentField_PSource));
|
||||
|
||||
llvm::Value *OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
|
||||
if (OMPDebugLoc == nullptr) {
|
||||
SmallString<128> Buffer2;
|
||||
llvm::raw_svector_ostream OS2(Buffer2);
|
||||
// Build debug location
|
||||
PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
|
||||
OS2 << ";" << PLoc.getFilename() << ";";
|
||||
Loc.isInvalid()) {
|
||||
SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr();
|
||||
} else {
|
||||
std::string FunctionName = "";
|
||||
if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
|
||||
OS2 << FD->getQualifiedNameAsString();
|
||||
OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
|
||||
OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
|
||||
OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
|
||||
FunctionName = FD->getQualifiedNameAsString();
|
||||
PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
|
||||
const char *FileName = PLoc.getFilename();
|
||||
unsigned Line = PLoc.getLine();
|
||||
unsigned Column = PLoc.getColumn();
|
||||
SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName.c_str(), FileName,
|
||||
Line, Column);
|
||||
}
|
||||
// *psource = ";<File>;<Function>;<Line>;<Column>;;";
|
||||
CGF.EmitStoreOfScalar(OMPDebugLoc, PSource);
|
||||
|
||||
// Our callers always pass this to a runtime function, so for
|
||||
// convenience, go ahead and return a naked pointer.
|
||||
return LocValue.getPointer();
|
||||
unsigned Reserved2Flags = getDefaultLocationReserved2Flags();
|
||||
return OMPBuilder.getOrCreateIdent(SrcLocStr, llvm::omp::IdentFlag(Flags),
|
||||
Reserved2Flags);
|
||||
}
|
||||
|
||||
llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
|
||||
@ -1595,7 +1506,7 @@ void CGOpenMPRuntime::functionFinished(CodeGenFunction &CGF) {
|
||||
}
|
||||
|
||||
llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
|
||||
return IdentTy->getPointerTo();
|
||||
return OMPBuilder.IdentPtr;
|
||||
}
|
||||
|
||||
llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
|
||||
@ -7354,6 +7265,8 @@ class MappableExprsHandler {
|
||||
// &p, &p, sizeof(float*), TARGET_PARAM | TO | FROM
|
||||
//
|
||||
// map(p[1:24])
|
||||
// &p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM | PTR_AND_OBJ
|
||||
// in unified shared memory mode or for local pointers
|
||||
// p, &p[1], 24*sizeof(float), TARGET_PARAM | TO | FROM
|
||||
//
|
||||
// map(s)
|
||||
@ -7489,6 +7402,7 @@ class MappableExprsHandler {
|
||||
// Track if the map information being generated is the first for a list of
|
||||
// components.
|
||||
bool IsExpressionFirstInfo = true;
|
||||
bool FirstPointerInComplexData = false;
|
||||
Address BP = Address::invalid();
|
||||
const Expr *AssocExpr = I->getAssociatedExpression();
|
||||
const auto *AE = dyn_cast<ArraySubscriptExpr>(AssocExpr);
|
||||
@ -7531,10 +7445,15 @@ class MappableExprsHandler {
|
||||
QualType Ty =
|
||||
I->getAssociatedDeclaration()->getType().getNonReferenceType();
|
||||
if (Ty->isAnyPointerType() && std::next(I) != CE) {
|
||||
BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
|
||||
|
||||
// We do not need to generate individual map information for the
|
||||
// pointer, it can be associated with the combined storage.
|
||||
// No need to generate individual map information for the pointer, it
|
||||
// can be associated with the combined storage if shared memory mode is
|
||||
// active or the base declaration is not global variable.
|
||||
const auto *VD = dyn_cast<VarDecl>(I->getAssociatedDeclaration());
|
||||
if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
|
||||
!VD || VD->hasLocalStorage())
|
||||
BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
|
||||
else
|
||||
FirstPointerInComplexData = IsCaptureFirstInfo;
|
||||
++I;
|
||||
}
|
||||
}
|
||||
@ -7570,8 +7489,19 @@ class MappableExprsHandler {
|
||||
EncounteredME = dyn_cast<MemberExpr>(I->getAssociatedExpression());
|
||||
// If we encounter a PTR_AND_OBJ entry from now on it should be marked
|
||||
// as MEMBER_OF the parent struct.
|
||||
if (EncounteredME)
|
||||
if (EncounteredME) {
|
||||
ShouldBeMemberOf = true;
|
||||
// Do not emit as complex pointer if this is actually not array-like
|
||||
// expression.
|
||||
if (FirstPointerInComplexData) {
|
||||
QualType Ty = std::prev(I)
|
||||
->getAssociatedDeclaration()
|
||||
->getType()
|
||||
.getNonReferenceType();
|
||||
BP = CGF.EmitLoadOfPointer(BP, Ty->castAs<PointerType>());
|
||||
FirstPointerInComplexData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Next = std::next(I);
|
||||
@ -7704,10 +7634,11 @@ class MappableExprsHandler {
|
||||
// same expression except for the first one. We also need to signal
|
||||
// this map is the first one that relates with the current capture
|
||||
// (there is a set of entries for each capture).
|
||||
OpenMPOffloadMappingFlags Flags = getMapTypeBits(
|
||||
MapType, MapModifiers, IsImplicit,
|
||||
!IsExpressionFirstInfo || RequiresReference,
|
||||
IsCaptureFirstInfo && !RequiresReference);
|
||||
OpenMPOffloadMappingFlags Flags =
|
||||
getMapTypeBits(MapType, MapModifiers, IsImplicit,
|
||||
!IsExpressionFirstInfo || RequiresReference ||
|
||||
FirstPointerInComplexData,
|
||||
IsCaptureFirstInfo && !RequiresReference);
|
||||
|
||||
if (!IsExpressionFirstInfo) {
|
||||
// If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
|
||||
@ -7765,6 +7696,7 @@ class MappableExprsHandler {
|
||||
|
||||
IsExpressionFirstInfo = false;
|
||||
IsCaptureFirstInfo = false;
|
||||
FirstPointerInComplexData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7995,6 +7927,10 @@ class MappableExprsHandler {
|
||||
// emission of that entry until the whole struct has been processed.
|
||||
llvm::MapVector<const ValueDecl *, SmallVector<DeferredDevicePtrEntryTy, 4>>
|
||||
DeferredInfo;
|
||||
MapBaseValuesArrayTy UseDevicePtrBasePointers;
|
||||
MapValuesArrayTy UseDevicePtrPointers;
|
||||
MapValuesArrayTy UseDevicePtrSizes;
|
||||
MapFlagsArrayTy UseDevicePtrTypes;
|
||||
|
||||
for (const auto *C :
|
||||
CurExecDir->getClausesOfKind<OMPUseDevicePtrClause>()) {
|
||||
@ -8011,15 +7947,27 @@ class MappableExprsHandler {
|
||||
// We potentially have map information for this declaration already.
|
||||
// Look for the first set of components that refer to it.
|
||||
if (It != Info.end()) {
|
||||
auto CI = std::find_if(
|
||||
It->second.begin(), It->second.end(), [VD](const MapInfo &MI) {
|
||||
return MI.Components.back().getAssociatedDeclaration() == VD;
|
||||
});
|
||||
auto *CI = llvm::find_if(It->second, [VD](const MapInfo &MI) {
|
||||
return MI.Components.back().getAssociatedDeclaration() == VD;
|
||||
});
|
||||
// If we found a map entry, signal that the pointer has to be returned
|
||||
// and move on to the next declaration.
|
||||
// Exclude cases where the base pointer is mapped as array subscript,
|
||||
// array section or array shaping. The base address is passed as a
|
||||
// pointer to base in this case and cannot be used as a base for
|
||||
// use_device_ptr list item.
|
||||
if (CI != It->second.end()) {
|
||||
CI->ReturnDevicePointer = true;
|
||||
continue;
|
||||
auto PrevCI = std::next(CI->Components.rbegin());
|
||||
const auto *VarD = dyn_cast<VarDecl>(VD);
|
||||
if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
|
||||
isa<MemberExpr>(IE) ||
|
||||
!VD->getType().getNonReferenceType()->isPointerType() ||
|
||||
PrevCI == CI->Components.rend() ||
|
||||
isa<MemberExpr>(PrevCI->getAssociatedExpression()) || !VarD ||
|
||||
VarD->hasLocalStorage()) {
|
||||
CI->ReturnDevicePointer = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8040,10 +7988,12 @@ class MappableExprsHandler {
|
||||
} else {
|
||||
llvm::Value *Ptr =
|
||||
CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
|
||||
BasePointers.emplace_back(Ptr, VD);
|
||||
Pointers.push_back(Ptr);
|
||||
Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
|
||||
Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM);
|
||||
UseDevicePtrBasePointers.emplace_back(Ptr, VD);
|
||||
UseDevicePtrPointers.push_back(Ptr);
|
||||
UseDevicePtrSizes.push_back(
|
||||
llvm::Constant::getNullValue(CGF.Int64Ty));
|
||||
UseDevicePtrTypes.push_back(OMP_MAP_RETURN_PARAM |
|
||||
OMP_MAP_TARGET_PARAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8104,10 +8054,12 @@ class MappableExprsHandler {
|
||||
Ptr = CGF.EmitLValue(IE).getPointer(CGF);
|
||||
else
|
||||
Ptr = CGF.EmitScalarExpr(IE);
|
||||
BasePointers.emplace_back(Ptr, VD);
|
||||
Pointers.push_back(Ptr);
|
||||
Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
|
||||
Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM);
|
||||
UseDevicePtrBasePointers.emplace_back(Ptr, VD);
|
||||
UseDevicePtrPointers.push_back(Ptr);
|
||||
UseDevicePtrSizes.push_back(
|
||||
llvm::Constant::getNullValue(CGF.Int64Ty));
|
||||
UseDevicePtrTypes.push_back(OMP_MAP_RETURN_PARAM |
|
||||
OMP_MAP_TARGET_PARAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8197,6 +8149,12 @@ class MappableExprsHandler {
|
||||
Sizes.append(CurSizes.begin(), CurSizes.end());
|
||||
Types.append(CurTypes.begin(), CurTypes.end());
|
||||
}
|
||||
// Append data for use_device_ptr clauses.
|
||||
BasePointers.append(UseDevicePtrBasePointers.begin(),
|
||||
UseDevicePtrBasePointers.end());
|
||||
Pointers.append(UseDevicePtrPointers.begin(), UseDevicePtrPointers.end());
|
||||
Sizes.append(UseDevicePtrSizes.begin(), UseDevicePtrSizes.end());
|
||||
Types.append(UseDevicePtrTypes.begin(), UseDevicePtrTypes.end());
|
||||
}
|
||||
|
||||
/// Generate all the base pointers, section pointers, sizes and map types for
|
||||
|
@ -374,17 +374,7 @@ class CGOpenMPRuntime {
|
||||
private:
|
||||
/// An OpenMP-IR-Builder instance.
|
||||
llvm::OpenMPIRBuilder OMPBuilder;
|
||||
/// Default const ident_t object used for initialization of all other
|
||||
/// ident_t objects.
|
||||
llvm::Constant *DefaultOpenMPPSource = nullptr;
|
||||
using FlagsTy = std::pair<unsigned, unsigned>;
|
||||
/// Map of flags and corresponding default locations.
|
||||
using OpenMPDefaultLocMapTy = llvm::DenseMap<FlagsTy, llvm::Value *>;
|
||||
OpenMPDefaultLocMapTy OpenMPDefaultLocMap;
|
||||
Address getOrCreateDefaultLocation(unsigned Flags);
|
||||
|
||||
QualType IdentQTy;
|
||||
llvm::StructType *IdentTy = nullptr;
|
||||
/// Map for SourceLocation and OpenMP runtime library debug locations.
|
||||
typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy;
|
||||
OpenMPDebugLocMapTy OpenMPDebugLocMap;
|
||||
|
@ -2857,8 +2857,12 @@ static llvm::Value *castValueToType(CodeGenFunction &CGF, llvm::Value *Val,
|
||||
Address CastItem = CGF.CreateMemTemp(CastTy);
|
||||
Address ValCastItem = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||
CastItem, Val->getType()->getPointerTo(CastItem.getAddressSpace()));
|
||||
CGF.EmitStoreOfScalar(Val, ValCastItem, /*Volatile=*/false, ValTy);
|
||||
return CGF.EmitLoadOfScalar(CastItem, /*Volatile=*/false, CastTy, Loc);
|
||||
CGF.EmitStoreOfScalar(Val, ValCastItem, /*Volatile=*/false, ValTy,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
return CGF.EmitLoadOfScalar(CastItem, /*Volatile=*/false, CastTy, Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
}
|
||||
|
||||
/// This function creates calls to one of two shuffle functions to copy
|
||||
@ -2945,9 +2949,14 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr,
|
||||
ThenBB, ExitBB);
|
||||
CGF.EmitBlock(ThenBB);
|
||||
llvm::Value *Res = createRuntimeShuffleFunction(
|
||||
CGF, CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc),
|
||||
CGF,
|
||||
CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo()),
|
||||
IntType, Offset, Loc);
|
||||
CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType);
|
||||
CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
Address LocalPtr = Bld.CreateConstGEP(Ptr, 1);
|
||||
Address LocalElemPtr = Bld.CreateConstGEP(ElemPtr, 1);
|
||||
PhiSrc->addIncoming(LocalPtr.getPointer(), ThenBB);
|
||||
@ -2956,9 +2965,14 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr,
|
||||
CGF.EmitBlock(ExitBB);
|
||||
} else {
|
||||
llvm::Value *Res = createRuntimeShuffleFunction(
|
||||
CGF, CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc),
|
||||
CGF,
|
||||
CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo()),
|
||||
IntType, Offset, Loc);
|
||||
CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType);
|
||||
CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
Ptr = Bld.CreateConstGEP(Ptr, 1);
|
||||
ElemPtr = Bld.CreateConstGEP(ElemPtr, 1);
|
||||
}
|
||||
@ -3112,12 +3126,14 @@ static void emitReductionListCopy(
|
||||
} else {
|
||||
switch (CGF.getEvaluationKind(Private->getType())) {
|
||||
case TEK_Scalar: {
|
||||
llvm::Value *Elem =
|
||||
CGF.EmitLoadOfScalar(SrcElementAddr, /*Volatile=*/false,
|
||||
Private->getType(), Private->getExprLoc());
|
||||
llvm::Value *Elem = CGF.EmitLoadOfScalar(
|
||||
SrcElementAddr, /*Volatile=*/false, Private->getType(),
|
||||
Private->getExprLoc(), LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
// Store the source element value to the dest element address.
|
||||
CGF.EmitStoreOfScalar(Elem, DestElementAddr, /*Volatile=*/false,
|
||||
Private->getType());
|
||||
CGF.EmitStoreOfScalar(
|
||||
Elem, DestElementAddr, /*Volatile=*/false, Private->getType(),
|
||||
LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo());
|
||||
break;
|
||||
}
|
||||
case TEK_Complex: {
|
||||
@ -3260,8 +3276,9 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM,
|
||||
Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg);
|
||||
Address LocalReduceList(
|
||||
Bld.CreatePointerBitCastOrAddrSpaceCast(
|
||||
CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false,
|
||||
C.VoidPtrTy, Loc),
|
||||
CGF.EmitLoadOfScalar(
|
||||
AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo()),
|
||||
CGF.ConvertTypeForMem(ReductionArrayTy)->getPointerTo()),
|
||||
CGF.getPointerAlign());
|
||||
|
||||
@ -3339,10 +3356,13 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM,
|
||||
|
||||
// elem = *elemptr
|
||||
//*MediumPtr = elem
|
||||
llvm::Value *Elem =
|
||||
CGF.EmitLoadOfScalar(ElemPtr, /*Volatile=*/false, CType, Loc);
|
||||
llvm::Value *Elem = CGF.EmitLoadOfScalar(
|
||||
ElemPtr, /*Volatile=*/false, CType, Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo());
|
||||
// Store the source element value to the dest element address.
|
||||
CGF.EmitStoreOfScalar(Elem, MediumPtr, /*Volatile=*/true, CType);
|
||||
CGF.EmitStoreOfScalar(Elem, MediumPtr, /*Volatile=*/true, CType,
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
|
||||
Bld.CreateBr(MergeBB);
|
||||
|
||||
@ -3722,8 +3742,9 @@ static llvm::Value *emitListToGlobalCopyFunction(
|
||||
GlobLVal.setAddress(Address(BufferPtr, GlobLVal.getAlignment()));
|
||||
switch (CGF.getEvaluationKind(Private->getType())) {
|
||||
case TEK_Scalar: {
|
||||
llvm::Value *V = CGF.EmitLoadOfScalar(ElemPtr, /*Volatile=*/false,
|
||||
Private->getType(), Loc);
|
||||
llvm::Value *V = CGF.EmitLoadOfScalar(
|
||||
ElemPtr, /*Volatile=*/false, Private->getType(), Loc,
|
||||
LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo());
|
||||
CGF.EmitStoreOfScalar(V, GlobLVal);
|
||||
break;
|
||||
}
|
||||
@ -3926,7 +3947,9 @@ static llvm::Value *emitGlobalToListCopyFunction(
|
||||
switch (CGF.getEvaluationKind(Private->getType())) {
|
||||
case TEK_Scalar: {
|
||||
llvm::Value *V = CGF.EmitLoadOfScalar(GlobLVal, Loc);
|
||||
CGF.EmitStoreOfScalar(V, ElemPtr, /*Volatile=*/false, Private->getType());
|
||||
CGF.EmitStoreOfScalar(V, ElemPtr, /*Volatile=*/false, Private->getType(),
|
||||
LValueBaseInfo(AlignmentSource::Type),
|
||||
TBAAAccessInfo());
|
||||
break;
|
||||
}
|
||||
case TEK_Complex: {
|
||||
|
@ -533,99 +533,60 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
|
||||
case BuiltinType::OCLReserveID:
|
||||
ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
|
||||
break;
|
||||
#define GET_SVE_INT_VEC(BITS, ELTS) \
|
||||
llvm::ScalableVectorType::get( \
|
||||
llvm::IntegerType::get(getLLVMContext(), BITS), ELTS);
|
||||
case BuiltinType::SveInt8:
|
||||
case BuiltinType::SveUint8:
|
||||
return GET_SVE_INT_VEC(8, 16);
|
||||
case BuiltinType::SveInt8x2:
|
||||
case BuiltinType::SveUint8x2:
|
||||
return GET_SVE_INT_VEC(8, 32);
|
||||
case BuiltinType::SveInt8x3:
|
||||
case BuiltinType::SveUint8x3:
|
||||
return GET_SVE_INT_VEC(8, 48);
|
||||
case BuiltinType::SveInt8x4:
|
||||
case BuiltinType::SveUint8x4:
|
||||
return GET_SVE_INT_VEC(8, 64);
|
||||
case BuiltinType::SveInt16:
|
||||
case BuiltinType::SveUint16:
|
||||
return GET_SVE_INT_VEC(16, 8);
|
||||
case BuiltinType::SveInt16x2:
|
||||
case BuiltinType::SveUint16x2:
|
||||
return GET_SVE_INT_VEC(16, 16);
|
||||
case BuiltinType::SveInt16x3:
|
||||
case BuiltinType::SveUint16x3:
|
||||
return GET_SVE_INT_VEC(16, 24);
|
||||
case BuiltinType::SveInt16x4:
|
||||
case BuiltinType::SveUint16x4:
|
||||
return GET_SVE_INT_VEC(16, 32);
|
||||
case BuiltinType::SveInt32:
|
||||
case BuiltinType::SveUint32:
|
||||
return GET_SVE_INT_VEC(32, 4);
|
||||
case BuiltinType::SveInt32x2:
|
||||
case BuiltinType::SveUint32x2:
|
||||
return GET_SVE_INT_VEC(32, 8);
|
||||
case BuiltinType::SveInt32x3:
|
||||
case BuiltinType::SveUint32x3:
|
||||
return GET_SVE_INT_VEC(32, 12);
|
||||
case BuiltinType::SveInt32x4:
|
||||
case BuiltinType::SveUint32x4:
|
||||
return GET_SVE_INT_VEC(32, 16);
|
||||
case BuiltinType::SveInt64:
|
||||
case BuiltinType::SveUint64:
|
||||
return GET_SVE_INT_VEC(64, 2);
|
||||
case BuiltinType::SveInt64x2:
|
||||
case BuiltinType::SveUint64x2:
|
||||
return GET_SVE_INT_VEC(64, 4);
|
||||
case BuiltinType::SveInt64x3:
|
||||
case BuiltinType::SveUint64x3:
|
||||
return GET_SVE_INT_VEC(64, 6);
|
||||
case BuiltinType::SveInt64x4:
|
||||
case BuiltinType::SveUint64x4:
|
||||
return GET_SVE_INT_VEC(64, 8);
|
||||
case BuiltinType::SveBool:
|
||||
return GET_SVE_INT_VEC(1, 16);
|
||||
#undef GET_SVE_INT_VEC
|
||||
#define GET_SVE_FP_VEC(TY, ISFP16, ELTS) \
|
||||
llvm::ScalableVectorType::get( \
|
||||
getTypeForFormat(getLLVMContext(), \
|
||||
Context.getFloatTypeSemantics(Context.TY), \
|
||||
/* UseNativeHalf = */ ISFP16), \
|
||||
ELTS);
|
||||
case BuiltinType::SveFloat16:
|
||||
return GET_SVE_FP_VEC(HalfTy, true, 8);
|
||||
case BuiltinType::SveFloat16x2:
|
||||
return GET_SVE_FP_VEC(HalfTy, true, 16);
|
||||
case BuiltinType::SveFloat16x3:
|
||||
return GET_SVE_FP_VEC(HalfTy, true, 24);
|
||||
case BuiltinType::SveFloat16x4:
|
||||
return GET_SVE_FP_VEC(HalfTy, true, 32);
|
||||
case BuiltinType::SveFloat32:
|
||||
return GET_SVE_FP_VEC(FloatTy, false, 4);
|
||||
case BuiltinType::SveFloat32x2:
|
||||
return GET_SVE_FP_VEC(FloatTy, false, 8);
|
||||
case BuiltinType::SveFloat32x3:
|
||||
return GET_SVE_FP_VEC(FloatTy, false, 12);
|
||||
case BuiltinType::SveFloat32x4:
|
||||
return GET_SVE_FP_VEC(FloatTy, false, 16);
|
||||
case BuiltinType::SveFloat64:
|
||||
return GET_SVE_FP_VEC(DoubleTy, false, 2);
|
||||
case BuiltinType::SveFloat64x2:
|
||||
return GET_SVE_FP_VEC(DoubleTy, false, 4);
|
||||
case BuiltinType::SveFloat64x3:
|
||||
return GET_SVE_FP_VEC(DoubleTy, false, 6);
|
||||
case BuiltinType::SveFloat64x4:
|
||||
return GET_SVE_FP_VEC(DoubleTy, false, 8);
|
||||
case BuiltinType::SveBFloat16:
|
||||
return GET_SVE_FP_VEC(BFloat16Ty, false, 8);
|
||||
case BuiltinType::SveBFloat16x2:
|
||||
return GET_SVE_FP_VEC(BFloat16Ty, false, 16);
|
||||
case BuiltinType::SveBFloat16x3:
|
||||
return GET_SVE_FP_VEC(BFloat16Ty, false, 24);
|
||||
case BuiltinType::SveBFloat16x4:
|
||||
return GET_SVE_FP_VEC(BFloat16Ty, false, 32);
|
||||
#undef GET_SVE_FP_VEC
|
||||
case BuiltinType::SveBFloat16x4: {
|
||||
ASTContext::BuiltinVectorTypeInfo Info =
|
||||
Context.getBuiltinVectorTypeInfo(cast<BuiltinType>(Ty));
|
||||
return llvm::ScalableVectorType::get(ConvertType(Info.ElementType),
|
||||
Info.EC.Min * Info.NumVectors);
|
||||
}
|
||||
case BuiltinType::Dependent:
|
||||
#define BUILTIN_TYPE(Id, SingletonId)
|
||||
#define PLACEHOLDER_TYPE(Id, SingletonId) \
|
||||
|
@ -21,12 +21,19 @@ using namespace llvm::opt;
|
||||
const char *sparc::getSparcAsmModeForCPU(StringRef Name,
|
||||
const llvm::Triple &Triple) {
|
||||
if (Triple.getArch() == llvm::Triple::sparcv9) {
|
||||
const char *DefV9CPU;
|
||||
|
||||
if (Triple.isOSLinux() || Triple.isOSFreeBSD() || Triple.isOSOpenBSD())
|
||||
DefV9CPU = "-Av9a";
|
||||
else
|
||||
DefV9CPU = "-Av9";
|
||||
|
||||
return llvm::StringSwitch<const char *>(Name)
|
||||
.Case("niagara", "-Av9b")
|
||||
.Case("niagara2", "-Av9b")
|
||||
.Case("niagara3", "-Av9d")
|
||||
.Case("niagara4", "-Av9d")
|
||||
.Default("-Av9");
|
||||
.Default(DefV9CPU);
|
||||
} else {
|
||||
return llvm::StringSwitch<const char *>(Name)
|
||||
.Case("v8", "-Av8")
|
||||
|
@ -498,7 +498,7 @@ static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
|
||||
return codegenoptions::DebugLineTablesOnly;
|
||||
if (A.getOption().matches(options::OPT_gline_directives_only))
|
||||
return codegenoptions::DebugDirectivesOnly;
|
||||
return codegenoptions::DebugInfoConstructor;
|
||||
return codegenoptions::LimitedDebugInfo;
|
||||
}
|
||||
|
||||
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
|
||||
@ -2380,7 +2380,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
|
||||
CmdArgs.push_back(Value.data());
|
||||
} else {
|
||||
RenderDebugEnablingArgs(Args, CmdArgs,
|
||||
codegenoptions::DebugInfoConstructor,
|
||||
codegenoptions::LimitedDebugInfo,
|
||||
DwarfVersion, llvm::DebuggerKind::Default);
|
||||
}
|
||||
} else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
|
||||
@ -3653,7 +3653,7 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
|
||||
if (const Arg *A =
|
||||
Args.getLastArg(options::OPT_g_Group, options::OPT_gsplit_dwarf,
|
||||
options::OPT_gsplit_dwarf_EQ)) {
|
||||
DebugInfoKind = codegenoptions::DebugInfoConstructor;
|
||||
DebugInfoKind = codegenoptions::LimitedDebugInfo;
|
||||
|
||||
// If the last option explicitly specified a debug-info level, use it.
|
||||
if (checkDebugInfoOption(A, Args, D, TC) &&
|
||||
@ -3758,7 +3758,7 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
|
||||
if (checkDebugInfoOption(A, Args, D, TC)) {
|
||||
if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
|
||||
DebugInfoKind != codegenoptions::DebugDirectivesOnly) {
|
||||
DebugInfoKind = codegenoptions::DebugInfoConstructor;
|
||||
DebugInfoKind = codegenoptions::LimitedDebugInfo;
|
||||
CmdArgs.push_back("-dwarf-ext-refs");
|
||||
CmdArgs.push_back("-fmodule-format=obj");
|
||||
}
|
||||
@ -3778,9 +3778,7 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
|
||||
TC.GetDefaultStandaloneDebug());
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_fstandalone_debug))
|
||||
(void)checkDebugInfoOption(A, Args, D, TC);
|
||||
if ((DebugInfoKind == codegenoptions::LimitedDebugInfo ||
|
||||
DebugInfoKind == codegenoptions::DebugInfoConstructor) &&
|
||||
NeedFullDebug)
|
||||
if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
|
||||
DebugInfoKind = codegenoptions::FullDebugInfo;
|
||||
|
||||
if (Args.hasFlag(options::OPT_gembed_source, options::OPT_gno_embed_source,
|
||||
@ -6566,7 +6564,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
|
||||
options::OPT_gline_tables_only)) {
|
||||
*EmitCodeView = true;
|
||||
if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7))
|
||||
*DebugInfoKind = codegenoptions::DebugInfoConstructor;
|
||||
*DebugInfoKind = codegenoptions::LimitedDebugInfo;
|
||||
else
|
||||
*DebugInfoKind = codegenoptions::DebugLineTablesOnly;
|
||||
} else {
|
||||
@ -6863,7 +6861,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
// the guard for source type, however there is a test which asserts
|
||||
// that some assembler invocation receives no -debug-info-kind,
|
||||
// and it's not clear whether that test is just overly restrictive.
|
||||
DebugInfoKind = (WantDebug ? codegenoptions::DebugInfoConstructor
|
||||
DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo
|
||||
: codegenoptions::NoDebugInfo);
|
||||
// Add the -fdebug-compilation-dir flag if needed.
|
||||
addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS());
|
||||
|
@ -10,10 +10,12 @@
|
||||
#include "Arch/Mips.h"
|
||||
#include "Arch/Sparc.h"
|
||||
#include "CommonArgs.h"
|
||||
#include "clang/Config/config.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Driver/SanitizerArgs.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::tools;
|
||||
@ -41,15 +43,6 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back("-many");
|
||||
break;
|
||||
|
||||
case llvm::Triple::sparc:
|
||||
case llvm::Triple::sparcel: {
|
||||
CmdArgs.push_back("-32");
|
||||
std::string CPU = getCPUName(Args, getToolChain().getTriple());
|
||||
CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
|
||||
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case llvm::Triple::sparcv9: {
|
||||
CmdArgs.push_back("-64");
|
||||
std::string CPU = getCPUName(Args, getToolChain().getTriple());
|
||||
@ -256,6 +249,45 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple,
|
||||
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
|
||||
}
|
||||
|
||||
void OpenBSD::AddClangSystemIncludeArgs(
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const {
|
||||
const Driver &D = getDriver();
|
||||
|
||||
if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
|
||||
return;
|
||||
|
||||
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
|
||||
SmallString<128> Dir(D.ResourceDir);
|
||||
llvm::sys::path::append(Dir, "include");
|
||||
addSystemInclude(DriverArgs, CC1Args, Dir.str());
|
||||
}
|
||||
|
||||
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
|
||||
return;
|
||||
|
||||
// Check for configure-time C include directories.
|
||||
StringRef CIncludeDirs(C_INCLUDE_DIRS);
|
||||
if (CIncludeDirs != "") {
|
||||
SmallVector<StringRef, 5> dirs;
|
||||
CIncludeDirs.split(dirs, ":");
|
||||
for (StringRef dir : dirs) {
|
||||
StringRef Prefix =
|
||||
llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
|
||||
}
|
||||
|
||||
void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const {
|
||||
addSystemInclude(DriverArgs, CC1Args,
|
||||
getDriver().SysRoot + "/usr/include/c++/v1");
|
||||
}
|
||||
|
||||
void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
bool Profiling = Args.hasArg(options::OPT_pg);
|
||||
@ -264,17 +296,18 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
|
||||
CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
|
||||
}
|
||||
|
||||
std::string OpenBSD::getCompilerRT(const ArgList &Args,
|
||||
StringRef Component,
|
||||
FileType Type) const {
|
||||
SmallString<128> Path(getDriver().SysRoot);
|
||||
llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
|
||||
return std::string(Path.str());
|
||||
}
|
||||
|
||||
Tool *OpenBSD::buildAssembler() const {
|
||||
return new tools::openbsd::Assembler(*this);
|
||||
}
|
||||
|
||||
Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
|
||||
|
||||
void OpenBSD::addClangTargetOptions(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args,
|
||||
Action::OffloadKind) const {
|
||||
// Support for .init_array is still new (Aug 2016).
|
||||
if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
|
||||
options::OPT_fno_use_init_array, false))
|
||||
CC1Args.push_back("-fno-use-init-array");
|
||||
}
|
||||
bool OpenBSD::HasNativeLLVMSupport() const { return true; }
|
||||
|
@ -54,6 +54,8 @@ class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
|
||||
OpenBSD(const Driver &D, const llvm::Triple &Triple,
|
||||
const llvm::opt::ArgList &Args);
|
||||
|
||||
bool HasNativeLLVMSupport() const override;
|
||||
|
||||
bool IsMathErrnoDefault() const override { return false; }
|
||||
bool IsObjCNonFragileABIDefault() const override { return true; }
|
||||
bool isPIEDefault() const override { return true; }
|
||||
@ -65,9 +67,18 @@ class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
|
||||
return ToolChain::CST_Libcxx;
|
||||
}
|
||||
|
||||
void
|
||||
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
|
||||
void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs) const override;
|
||||
|
||||
std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
|
||||
FileType Type = ToolChain::FT_Static) const override;
|
||||
|
||||
unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
|
||||
return 2;
|
||||
}
|
||||
@ -75,11 +86,6 @@ class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF {
|
||||
|
||||
SanitizerMask getSupportedSanitizers() const override;
|
||||
|
||||
void
|
||||
addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
Action::OffloadKind DeviceOffloadKind) const override;
|
||||
|
||||
protected:
|
||||
Tool *buildAssembler() const override;
|
||||
Tool *buildLinker() const override;
|
||||
|
@ -56,6 +56,13 @@ static bool isLambdaParameterList(const FormatToken *Left) {
|
||||
Left->Previous->MatchingParen->is(TT_LambdaLSquare);
|
||||
}
|
||||
|
||||
/// Returns \c true if the token is followed by a boolean condition, \c false
|
||||
/// otherwise.
|
||||
static bool isKeywordWithCondition(const FormatToken &Tok) {
|
||||
return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
|
||||
tok::kw_constexpr, tok::kw_catch);
|
||||
}
|
||||
|
||||
/// A parser that gathers additional information about tokens.
|
||||
///
|
||||
/// The \c TokenAnnotator tries to match parenthesis and square brakets and
|
||||
@ -108,6 +115,12 @@ class AnnotatingParser {
|
||||
|
||||
while (CurrentToken) {
|
||||
if (CurrentToken->is(tok::greater)) {
|
||||
// Try to do a better job at looking for ">>" within the condition of
|
||||
// a statement.
|
||||
if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) &&
|
||||
Left->ParentBracket != tok::less &&
|
||||
isKeywordWithCondition(*Line.First))
|
||||
return false;
|
||||
Left->MatchingParen = CurrentToken;
|
||||
CurrentToken->MatchingParen = Left;
|
||||
// In TT_Proto, we must distignuish between:
|
||||
@ -2733,13 +2746,6 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
|
||||
Right.ParameterCount > 0);
|
||||
}
|
||||
|
||||
/// Returns \c true if the token is followed by a boolean condition, \c false
|
||||
/// otherwise.
|
||||
static bool isKeywordWithCondition(const FormatToken &Tok) {
|
||||
return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
|
||||
tok::kw_constexpr, tok::kw_catch);
|
||||
}
|
||||
|
||||
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
||||
const FormatToken &Left,
|
||||
const FormatToken &Right) {
|
||||
|
@ -270,6 +270,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
|
||||
case llvm::Triple::Linux:
|
||||
case llvm::Triple::Hurd:
|
||||
case llvm::Triple::Solaris:
|
||||
case llvm::Triple::OpenBSD:
|
||||
llvm_unreachable("Include management is handled in the driver.");
|
||||
|
||||
case llvm::Triple::CloudABI: {
|
||||
@ -423,6 +424,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
|
||||
case llvm::Triple::Emscripten:
|
||||
case llvm::Triple::Linux:
|
||||
case llvm::Triple::Hurd:
|
||||
case llvm::Triple::OpenBSD:
|
||||
case llvm::Triple::Solaris:
|
||||
case llvm::Triple::WASI:
|
||||
case llvm::Triple::AIX:
|
||||
|
@ -1766,36 +1766,12 @@ vec_cmpne(vector unsigned int __a, vector unsigned int __b) {
|
||||
(vector int)__b);
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector bool long long __a, vector bool long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector signed long long __a, vector signed long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector unsigned long long __a, vector unsigned long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool int __ATTRS_o_ai
|
||||
vec_cmpne(vector float __a, vector float __b) {
|
||||
return (vector bool int)__builtin_altivec_vcmpnew((vector int)__a,
|
||||
(vector int)__b);
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector double __a, vector double __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
/* vec_cmpnez */
|
||||
|
||||
static __inline__ vector bool char __ATTRS_o_ai
|
||||
@ -1900,6 +1876,86 @@ vec_parity_lsbb(vector signed long long __a) {
|
||||
return __builtin_altivec_vprtybd(__a);
|
||||
}
|
||||
|
||||
#else
|
||||
/* vec_cmpne */
|
||||
|
||||
static __inline__ vector bool char __ATTRS_o_ai
|
||||
vec_cmpne(vector bool char __a, vector bool char __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool char __ATTRS_o_ai
|
||||
vec_cmpne(vector signed char __a, vector signed char __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool char __ATTRS_o_ai
|
||||
vec_cmpne(vector unsigned char __a, vector unsigned char __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool short __ATTRS_o_ai
|
||||
vec_cmpne(vector bool short __a, vector bool short __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool short __ATTRS_o_ai
|
||||
vec_cmpne(vector signed short __a, vector signed short __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool short __ATTRS_o_ai
|
||||
vec_cmpne(vector unsigned short __a, vector unsigned short __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool int __ATTRS_o_ai
|
||||
vec_cmpne(vector bool int __a, vector bool int __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool int __ATTRS_o_ai
|
||||
vec_cmpne(vector signed int __a, vector signed int __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool int __ATTRS_o_ai
|
||||
vec_cmpne(vector unsigned int __a, vector unsigned int __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool int __ATTRS_o_ai
|
||||
vec_cmpne(vector float __a, vector float __b) {
|
||||
return ~(vec_cmpeq(__a, __b));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __POWER8_VECTOR__
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector bool long long __a, vector bool long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector signed long long __a, vector signed long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector unsigned long long __a, vector unsigned long long __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __VSX__
|
||||
static __inline__ vector bool long long __ATTRS_o_ai
|
||||
vec_cmpne(vector double __a, vector double __b) {
|
||||
return (vector bool long long)
|
||||
~(__builtin_altivec_vcmpequd((vector long long)__a, (vector long long)__b));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* vec_cmpgt */
|
||||
@ -2702,67 +2758,67 @@ vec_insert_exp(vector unsigned int __a, vector unsigned int __b) {
|
||||
}
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
static __inline__ vector signed char __ATTRS_o_ai vec_xl_len(signed char *__a,
|
||||
static __inline__ vector signed char __ATTRS_o_ai vec_xl_len(const signed char *__a,
|
||||
size_t __b) {
|
||||
return (vector signed char)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned char __ATTRS_o_ai
|
||||
vec_xl_len(unsigned char *__a, size_t __b) {
|
||||
vec_xl_len(const unsigned char *__a, size_t __b) {
|
||||
return (vector unsigned char)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector signed short __ATTRS_o_ai vec_xl_len(signed short *__a,
|
||||
static __inline__ vector signed short __ATTRS_o_ai vec_xl_len(const signed short *__a,
|
||||
size_t __b) {
|
||||
return (vector signed short)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned short __ATTRS_o_ai
|
||||
vec_xl_len(unsigned short *__a, size_t __b) {
|
||||
vec_xl_len(const unsigned short *__a, size_t __b) {
|
||||
return (vector unsigned short)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector signed int __ATTRS_o_ai vec_xl_len(signed int *__a,
|
||||
static __inline__ vector signed int __ATTRS_o_ai vec_xl_len(const signed int *__a,
|
||||
size_t __b) {
|
||||
return (vector signed int)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned int __ATTRS_o_ai vec_xl_len(unsigned int *__a,
|
||||
static __inline__ vector unsigned int __ATTRS_o_ai vec_xl_len(const unsigned int *__a,
|
||||
size_t __b) {
|
||||
return (vector unsigned int)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector float __ATTRS_o_ai vec_xl_len(float *__a, size_t __b) {
|
||||
static __inline__ vector float __ATTRS_o_ai vec_xl_len(const float *__a, size_t __b) {
|
||||
return (vector float)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector signed __int128 __ATTRS_o_ai
|
||||
vec_xl_len(signed __int128 *__a, size_t __b) {
|
||||
vec_xl_len(const signed __int128 *__a, size_t __b) {
|
||||
return (vector signed __int128)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned __int128 __ATTRS_o_ai
|
||||
vec_xl_len(unsigned __int128 *__a, size_t __b) {
|
||||
vec_xl_len(const unsigned __int128 *__a, size_t __b) {
|
||||
return (vector unsigned __int128)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector signed long long __ATTRS_o_ai
|
||||
vec_xl_len(signed long long *__a, size_t __b) {
|
||||
vec_xl_len(const signed long long *__a, size_t __b) {
|
||||
return (vector signed long long)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned long long __ATTRS_o_ai
|
||||
vec_xl_len(unsigned long long *__a, size_t __b) {
|
||||
vec_xl_len(const unsigned long long *__a, size_t __b) {
|
||||
return (vector unsigned long long)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector double __ATTRS_o_ai vec_xl_len(double *__a,
|
||||
static __inline__ vector double __ATTRS_o_ai vec_xl_len(const double *__a,
|
||||
size_t __b) {
|
||||
return (vector double)__builtin_vsx_lxvl(__a, (__b << 56));
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned char __ATTRS_o_ai
|
||||
vec_xl_len_r(unsigned char *__a, size_t __b) {
|
||||
vec_xl_len_r(const unsigned char *__a, size_t __b) {
|
||||
vector unsigned char __res =
|
||||
(vector unsigned char)__builtin_vsx_lxvll(__a, (__b << 56));
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
@ -16353,41 +16409,41 @@ typedef vector unsigned int unaligned_vec_uint __attribute__((aligned(1)));
|
||||
typedef vector float unaligned_vec_float __attribute__((aligned(1)));
|
||||
|
||||
static inline __ATTRS_o_ai vector signed char vec_xl(signed long long __offset,
|
||||
signed char *__ptr) {
|
||||
const signed char *__ptr) {
|
||||
return *(unaligned_vec_schar *)(__ptr + __offset);
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector unsigned char
|
||||
vec_xl(signed long long __offset, unsigned char *__ptr) {
|
||||
vec_xl(signed long long __offset, const unsigned char *__ptr) {
|
||||
return *(unaligned_vec_uchar*)(__ptr + __offset);
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector signed short vec_xl(signed long long __offset,
|
||||
signed short *__ptr) {
|
||||
const signed short *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_sshort *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector unsigned short
|
||||
vec_xl(signed long long __offset, unsigned short *__ptr) {
|
||||
vec_xl(signed long long __offset, const unsigned short *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_ushort *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector signed int vec_xl(signed long long __offset,
|
||||
signed int *__ptr) {
|
||||
const signed int *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_sint *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector unsigned int vec_xl(signed long long __offset,
|
||||
unsigned int *__ptr) {
|
||||
const unsigned int *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_uint *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector float vec_xl(signed long long __offset,
|
||||
float *__ptr) {
|
||||
const float *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_float *)__addr;
|
||||
}
|
||||
@ -16398,19 +16454,19 @@ typedef vector unsigned long long unaligned_vec_ull __attribute__((aligned(1)));
|
||||
typedef vector double unaligned_vec_double __attribute__((aligned(1)));
|
||||
|
||||
static inline __ATTRS_o_ai vector signed long long
|
||||
vec_xl(signed long long __offset, signed long long *__ptr) {
|
||||
vec_xl(signed long long __offset, const signed long long *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_sll *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector unsigned long long
|
||||
vec_xl(signed long long __offset, unsigned long long *__ptr) {
|
||||
vec_xl(signed long long __offset, const unsigned long long *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_ull *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector double vec_xl(signed long long __offset,
|
||||
double *__ptr) {
|
||||
const double *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_double *)__addr;
|
||||
}
|
||||
@ -16421,13 +16477,13 @@ typedef vector signed __int128 unaligned_vec_si128 __attribute__((aligned(1)));
|
||||
typedef vector unsigned __int128 unaligned_vec_ui128
|
||||
__attribute__((aligned(1)));
|
||||
static inline __ATTRS_o_ai vector signed __int128
|
||||
vec_xl(signed long long __offset, signed __int128 *__ptr) {
|
||||
vec_xl(signed long long __offset, const signed __int128 *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_si128 *)__addr;
|
||||
}
|
||||
|
||||
static inline __ATTRS_o_ai vector unsigned __int128
|
||||
vec_xl(signed long long __offset, unsigned __int128 *__ptr) {
|
||||
vec_xl(signed long long __offset, const unsigned __int128 *__ptr) {
|
||||
signed char *__addr = (signed char *)__ptr + __offset;
|
||||
return *(unaligned_vec_ui128 *)__addr;
|
||||
}
|
||||
@ -16437,71 +16493,71 @@ vec_xl(signed long long __offset, unsigned __int128 *__ptr) {
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
static __inline__ vector signed char __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, signed char *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const signed char *__ptr) {
|
||||
vector signed char __vec = (vector signed char)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
return __builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
|
||||
13, 12, 11, 10, 9, 8);
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned char __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, unsigned char *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const unsigned char *__ptr) {
|
||||
vector unsigned char __vec = (vector unsigned char)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
return __builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
|
||||
13, 12, 11, 10, 9, 8);
|
||||
}
|
||||
|
||||
static __inline__ vector signed short __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, signed short *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const signed short *__ptr) {
|
||||
vector signed short __vec = (vector signed short)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
return __builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned short __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, unsigned short *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const unsigned short *__ptr) {
|
||||
vector unsigned short __vec = (vector unsigned short)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
return __builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
|
||||
}
|
||||
|
||||
static __inline__ vector signed int __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, signed int *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const signed int *__ptr) {
|
||||
return (vector signed int)__builtin_vsx_lxvw4x_be(__offset, __ptr);
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned int __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, unsigned int *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const unsigned int *__ptr) {
|
||||
return (vector unsigned int)__builtin_vsx_lxvw4x_be(__offset, __ptr);
|
||||
}
|
||||
|
||||
static __inline__ vector float __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, float *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const float *__ptr) {
|
||||
return (vector float)__builtin_vsx_lxvw4x_be(__offset, __ptr);
|
||||
}
|
||||
|
||||
#ifdef __VSX__
|
||||
static __inline__ vector signed long long __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, signed long long *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const signed long long *__ptr) {
|
||||
return (vector signed long long)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned long long __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, unsigned long long *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const unsigned long long *__ptr) {
|
||||
return (vector unsigned long long)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
}
|
||||
|
||||
static __inline__ vector double __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, double *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const double *__ptr) {
|
||||
return (vector double)__builtin_vsx_lxvd2x_be(__offset, __ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__POWER8_VECTOR__) && defined(__powerpc64__)
|
||||
static __inline__ vector signed __int128 __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, signed __int128 *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const signed __int128 *__ptr) {
|
||||
return vec_xl(__offset, __ptr);
|
||||
}
|
||||
|
||||
static __inline__ vector unsigned __int128 __ATTRS_o_ai
|
||||
vec_xl_be(signed long long __offset, unsigned __int128 *__ptr) {
|
||||
vec_xl_be(signed long long __offset, const unsigned __int128 *__ptr) {
|
||||
return vec_xl(__offset, __ptr);
|
||||
}
|
||||
#endif
|
||||
|
@ -4956,6 +4956,11 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
|
||||
? 0
|
||||
: 1);
|
||||
|
||||
if (ValType->isExtIntType()) {
|
||||
Diag(Ptr->getExprLoc(), diag::err_atomic_builtin_ext_int_prohibit);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
return AE;
|
||||
}
|
||||
|
||||
|
@ -2053,6 +2053,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
|
||||
// typedef (C++ [dcl.typedef]p4).
|
||||
if (Previous.isSingleTagDecl())
|
||||
Previous.clear();
|
||||
|
||||
// Filter out previous declarations that don't match the scope. The only
|
||||
// effect this has is to remove declarations found in inline namespaces
|
||||
// for friend declarations with unqualified names.
|
||||
SemaRef.FilterLookupForScope(Previous, DC, /*Scope*/ nullptr,
|
||||
/*ConsiderLinkage*/ true,
|
||||
QualifierLoc.hasQualifier());
|
||||
}
|
||||
|
||||
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
|
||||
|
@ -8880,11 +8880,8 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
|
||||
else if (!T.isTriviallyCopyableType(Context))
|
||||
// Some other non-trivially-copyable type (probably a C++ class)
|
||||
DisallowedKind = 7;
|
||||
else if (auto *ExtTy = T->getAs<ExtIntType>()) {
|
||||
if (ExtTy->getNumBits() < 8)
|
||||
else if (T->isExtIntType()) {
|
||||
DisallowedKind = 8;
|
||||
else if (!llvm::isPowerOf2_32(ExtTy->getNumBits()))
|
||||
DisallowedKind = 9;
|
||||
}
|
||||
|
||||
if (DisallowedKind != -1) {
|
||||
|
@ -583,7 +583,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
|
||||
Reader.getContext());
|
||||
}
|
||||
D->setLocation(ThisDeclLoc);
|
||||
D->setInvalidDecl(Record.readInt());
|
||||
D->InvalidDecl = Record.readInt();
|
||||
if (Record.readInt()) { // hasAttrs
|
||||
AttrVec Attrs;
|
||||
Record.readAttributes(Attrs);
|
||||
|
@ -106,7 +106,7 @@ static const NoteTag *getNoteTag(CheckerContext &C,
|
||||
QualType CastToTy, const Expr *Object,
|
||||
bool CastSucceeds, bool IsKnownCast) {
|
||||
std::string CastToName =
|
||||
CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
|
||||
CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString()
|
||||
: CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
|
||||
Object = Object->IgnoreParenImpCasts();
|
||||
|
||||
@ -135,6 +135,47 @@ static const NoteTag *getNoteTag(CheckerContext &C,
|
||||
/*IsPrunable=*/true);
|
||||
}
|
||||
|
||||
static const NoteTag *getNoteTag(CheckerContext &C,
|
||||
SmallVector<QualType, 4> CastToTyVec,
|
||||
const Expr *Object,
|
||||
bool IsKnownCast) {
|
||||
Object = Object->IgnoreParenImpCasts();
|
||||
|
||||
return C.getNoteTag(
|
||||
[=]() -> std::string {
|
||||
SmallString<128> Msg;
|
||||
llvm::raw_svector_ostream Out(Msg);
|
||||
|
||||
if (!IsKnownCast)
|
||||
Out << "Assuming ";
|
||||
|
||||
if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
|
||||
Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
|
||||
} else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
|
||||
Out << (IsKnownCast ? "Field '" : "field '")
|
||||
<< ME->getMemberDecl()->getNameAsString() << '\'';
|
||||
} else {
|
||||
Out << (IsKnownCast ? "The object" : "the object");
|
||||
}
|
||||
Out << " is";
|
||||
|
||||
bool First = true;
|
||||
for (QualType CastToTy: CastToTyVec) {
|
||||
std::string CastToName =
|
||||
CastToTy->getAsCXXRecordDecl() ?
|
||||
CastToTy->getAsCXXRecordDecl()->getNameAsString() :
|
||||
CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
|
||||
Out << ' ' << ((CastToTyVec.size() == 1) ? "not" :
|
||||
(First ? "neither" : "nor")) << " a '" << CastToName
|
||||
<< '\'';
|
||||
First = false;
|
||||
}
|
||||
|
||||
return std::string(Out.str());
|
||||
},
|
||||
/*IsPrunable=*/true);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Main logic to evaluate a cast.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -220,40 +261,76 @@ static void addInstanceOfTransition(const CallEvent &Call,
|
||||
bool IsInstanceOf) {
|
||||
const FunctionDecl *FD = Call.getDecl()->getAsFunction();
|
||||
QualType CastFromTy = Call.parameters()[0]->getType();
|
||||
QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
|
||||
if (CastFromTy->isPointerType())
|
||||
CastToTy = C.getASTContext().getPointerType(CastToTy);
|
||||
else if (CastFromTy->isReferenceType())
|
||||
CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
|
||||
else
|
||||
return;
|
||||
|
||||
const MemRegion *MR = DV.getAsRegion();
|
||||
const DynamicCastInfo *CastInfo =
|
||||
getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
|
||||
|
||||
bool CastSucceeds;
|
||||
if (CastInfo)
|
||||
CastSucceeds = IsInstanceOf && CastInfo->succeeds();
|
||||
else
|
||||
CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
|
||||
|
||||
if (isInfeasibleCast(CastInfo, CastSucceeds)) {
|
||||
C.generateSink(State, C.getPredecessor());
|
||||
return;
|
||||
SmallVector<QualType, 4> CastToTyVec;
|
||||
for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1;
|
||||
++idx) {
|
||||
TemplateArgument CastToTempArg =
|
||||
FD->getTemplateSpecializationArgs()->get(idx);
|
||||
switch (CastToTempArg.getKind()) {
|
||||
default:
|
||||
return;
|
||||
case TemplateArgument::Type:
|
||||
CastToTyVec.push_back(CastToTempArg.getAsType());
|
||||
break;
|
||||
case TemplateArgument::Pack:
|
||||
for (TemplateArgument ArgInPack: CastToTempArg.pack_elements())
|
||||
CastToTyVec.push_back(ArgInPack.getAsType());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the type and the cast information.
|
||||
bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
|
||||
if (!IsKnownCast)
|
||||
State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
|
||||
IsInstanceOf);
|
||||
const MemRegion *MR = DV.getAsRegion();
|
||||
if (MR && CastFromTy->isReferenceType())
|
||||
MR = State->getSVal(DV.castAs<Loc>()).getAsRegion();
|
||||
|
||||
C.addTransition(
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(CastSucceeds)),
|
||||
getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
|
||||
IsKnownCast));
|
||||
bool Success = false;
|
||||
bool IsAnyKnown = false;
|
||||
for (QualType CastToTy: CastToTyVec) {
|
||||
if (CastFromTy->isPointerType())
|
||||
CastToTy = C.getASTContext().getPointerType(CastToTy);
|
||||
else if (CastFromTy->isReferenceType())
|
||||
CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
|
||||
else
|
||||
return;
|
||||
|
||||
const DynamicCastInfo *CastInfo =
|
||||
getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
|
||||
|
||||
bool CastSucceeds;
|
||||
if (CastInfo)
|
||||
CastSucceeds = IsInstanceOf && CastInfo->succeeds();
|
||||
else
|
||||
CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
|
||||
|
||||
// Store the type and the cast information.
|
||||
bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
|
||||
IsAnyKnown = IsAnyKnown || IsKnownCast;
|
||||
ProgramStateRef NewState = State;
|
||||
if (!IsKnownCast)
|
||||
NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
|
||||
IsInstanceOf);
|
||||
|
||||
if (CastSucceeds) {
|
||||
Success = true;
|
||||
C.addTransition(
|
||||
NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(true)),
|
||||
getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
|
||||
IsKnownCast));
|
||||
if (IsKnownCast)
|
||||
return;
|
||||
} else if (CastInfo && CastInfo->succeeds()) {
|
||||
C.generateSink(NewState, C.getPredecessor());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Success) {
|
||||
C.addTransition(
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(false)),
|
||||
getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -402,8 +479,9 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
|
||||
QualType ParamT = Call.parameters()[0]->getType();
|
||||
QualType ResultT = Call.getResultType();
|
||||
if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
|
||||
!(ParamT->isReferenceType() && ResultT->isReferenceType()))
|
||||
!(ParamT->isReferenceType() && ResultT->isReferenceType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
|
||||
break;
|
||||
|
@ -65,6 +65,13 @@ const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
|
||||
return State->get<DynamicTypeMap>(MR);
|
||||
}
|
||||
|
||||
static void unbox(QualType &Ty) {
|
||||
// FIXME: Why are we being fed references to pointers in the first place?
|
||||
while (Ty->isReferenceType() || Ty->isPointerType())
|
||||
Ty = Ty->getPointeeType();
|
||||
Ty = Ty.getCanonicalType().getUnqualifiedType();
|
||||
}
|
||||
|
||||
const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
|
||||
const MemRegion *MR,
|
||||
QualType CastFromTy,
|
||||
@ -73,6 +80,9 @@ const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
|
||||
if (!Lookup)
|
||||
return nullptr;
|
||||
|
||||
unbox(CastFromTy);
|
||||
unbox(CastToTy);
|
||||
|
||||
for (const DynamicCastInfo &Cast : *Lookup)
|
||||
if (Cast.equals(CastFromTy, CastToTy))
|
||||
return &Cast;
|
||||
@ -112,6 +122,9 @@ ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
|
||||
State = State->set<DynamicTypeMap>(MR, CastToTy);
|
||||
}
|
||||
|
||||
unbox(CastFromTy);
|
||||
unbox(CastToTy);
|
||||
|
||||
DynamicCastInfo::CastResult ResultKind =
|
||||
CastSucceeds ? DynamicCastInfo::CastResult::Success
|
||||
: DynamicCastInfo::CastResult::Failure;
|
||||
|
@ -33,7 +33,7 @@ uintptr_t GetCurrentProcess(void);
|
||||
#include <machine/sysarch.h>
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__) && defined(__mips__)
|
||||
#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__))
|
||||
// clang-format off
|
||||
#include <sys/types.h>
|
||||
#include <machine/sysarch.h>
|
||||
@ -58,7 +58,7 @@ void __clear_cache(void *start, void *end) {
|
||||
#elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__))
|
||||
FlushInstructionCache(GetCurrentProcess(), start, end - start);
|
||||
#elif defined(__arm__) && !defined(__APPLE__)
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
struct arm_sync_icache_args arg;
|
||||
|
||||
arg.addr = (uintptr_t)start;
|
||||
|
@ -277,7 +277,7 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
|
||||
const unsigned *Features,
|
||||
unsigned *Type, unsigned *Subtype) {
|
||||
#define testFeature(F) \
|
||||
(Features[F / 32] & (F % 32)) != 0
|
||||
(Features[F / 32] & (1 << (F % 32))) != 0
|
||||
|
||||
// We select CPU strings to match the code in Host.cpp, but we don't use them
|
||||
// in compiler-rt.
|
||||
|
@ -210,22 +210,6 @@ static void write_64bit_value(uint64_t i) {
|
||||
write_32bit_value(hi);
|
||||
}
|
||||
|
||||
static uint32_t length_of_string(const char *s) {
|
||||
return (strlen(s) / 4) + 1;
|
||||
}
|
||||
|
||||
// Remove when we support libgcov 9 current_working_directory.
|
||||
#if !defined(_MSC_VER) && defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static void
|
||||
write_string(const char *s) {
|
||||
uint32_t len = length_of_string(s);
|
||||
write_32bit_value(len);
|
||||
write_bytes(s, strlen(s));
|
||||
write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
|
||||
}
|
||||
|
||||
static uint32_t read_32bit_value() {
|
||||
uint32_t val;
|
||||
|
||||
@ -632,6 +616,9 @@ void llvm_writeout_files(void) {
|
||||
// __attribute__((destructor)) and destructors whose priorities are greater than
|
||||
// 100 run before this function and can thus be tracked. The priority is
|
||||
// compatible with GCC 7 onwards.
|
||||
#if __GNUC__ >= 9
|
||||
#pragma GCC diagnostic ignored "-Wprio-ctor-dtor"
|
||||
#endif
|
||||
__attribute__((destructor(100)))
|
||||
#endif
|
||||
static void llvm_writeout_and_clear(void) {
|
||||
|
@ -129,6 +129,12 @@ struct __sanitizer_shmid_ds {
|
||||
void *_shm_internal;
|
||||
};
|
||||
|
||||
struct __sanitizer_protoent {
|
||||
char *p_name;
|
||||
char **p_aliases;
|
||||
int p_proto;
|
||||
};
|
||||
|
||||
struct __sanitizer_netent {
|
||||
char *n_name;
|
||||
char **n_aliases;
|
||||
|
@ -473,8 +473,8 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
|
||||
return false;
|
||||
}
|
||||
|
||||
int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
|
||||
void *data) {
|
||||
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
|
||||
size_t pinfo_size, void *data) {
|
||||
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||
if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
|
||||
return 0;
|
||||
@ -523,7 +523,8 @@ int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
|
||||
// Given all the #ifdef's above, the code here is for
|
||||
// defined(LIBUNWIND_ARM_EHABI)
|
||||
|
||||
int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
|
||||
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t,
|
||||
void *data) {
|
||||
auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
|
||||
bool found_obj = false;
|
||||
bool found_hdr = false;
|
||||
|
@ -599,6 +599,9 @@ void Writer::finalizeAddresses() {
|
||||
void Writer::run() {
|
||||
ScopedTimer t1(codeLayoutTimer);
|
||||
|
||||
// First, clear the output sections from previous runs
|
||||
outputSections.clear();
|
||||
|
||||
createImportTables();
|
||||
createSections();
|
||||
createMiscChunks();
|
||||
|
@ -26,7 +26,12 @@ using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
|
||||
for (InputSectionBase *sec : obj->getSections()) {
|
||||
// Get the ELF sections to retrieve sh_flags. See the SHF_GROUP comment below.
|
||||
ArrayRef<typename ELFT::Shdr> objSections =
|
||||
CHECK(obj->getObj().sections(), obj);
|
||||
assert(objSections.size() == obj->getSections().size());
|
||||
for (auto it : llvm::enumerate(obj->getSections())) {
|
||||
InputSectionBase *sec = it.value();
|
||||
if (!sec)
|
||||
continue;
|
||||
|
||||
@ -35,7 +40,6 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
|
||||
.Case(".debug_addr", &addrSection)
|
||||
.Case(".debug_gnu_pubnames", &gnuPubnamesSection)
|
||||
.Case(".debug_gnu_pubtypes", &gnuPubtypesSection)
|
||||
.Case(".debug_info", &infoSection)
|
||||
.Case(".debug_loclists", &loclistsSection)
|
||||
.Case(".debug_ranges", &rangesSection)
|
||||
.Case(".debug_rnglists", &rnglistsSection)
|
||||
@ -53,6 +57,20 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
|
||||
strSection = toStringRef(sec->data());
|
||||
else if (sec->name == ".debug_line_str")
|
||||
lineStrSection = toStringRef(sec->data());
|
||||
else if (sec->name == ".debug_info" &&
|
||||
!(objSections[it.index()].sh_flags & ELF::SHF_GROUP)) {
|
||||
// In DWARF v5, -fdebug-types-section places type units in .debug_info
|
||||
// sections in COMDAT groups. They are not compile units and thus should
|
||||
// be ignored for .gdb_index/diagnostics purposes.
|
||||
//
|
||||
// We use a simple heuristic: the compile unit does not have the SHF_GROUP
|
||||
// flag. If we place compile units in COMDAT groups in the future, we may
|
||||
// need to perform a lightweight parsing. We drop the SHF_GROUP flag when
|
||||
// the InputSection was created, so we need to retrieve sh_flags from the
|
||||
// associated ELF section header.
|
||||
infoSection.Data = toStringRef(sec->data());
|
||||
infoSection.sec = sec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
|
||||
f(infoSection);
|
||||
}
|
||||
|
||||
InputSection *getInfoSection() const {
|
||||
return cast<InputSection>(infoSection.sec);
|
||||
}
|
||||
|
||||
const llvm::DWARFSection &getLoclistsSection() const override {
|
||||
return loclistsSection;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) {
|
||||
// write expressions like this: `alignment = 16; . = ALIGN(., alignment)`.
|
||||
uint64_t symValue = value.sec ? 0 : value.getValue();
|
||||
|
||||
Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE,
|
||||
Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, value.type,
|
||||
symValue, 0, sec);
|
||||
|
||||
Symbol *sym = symtab->insert(cmd->name);
|
||||
@ -317,6 +317,7 @@ void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) {
|
||||
cmd->sym->section = v.sec;
|
||||
cmd->sym->value = v.getSectionOffset();
|
||||
}
|
||||
cmd->sym->type = v.type;
|
||||
}
|
||||
|
||||
static std::string getFilename(InputFile *file) {
|
||||
@ -1215,8 +1216,14 @@ ExprValue LinkerScript::getSymbolValue(StringRef name, const Twine &loc) {
|
||||
}
|
||||
|
||||
if (Symbol *sym = symtab->find(name)) {
|
||||
if (auto *ds = dyn_cast<Defined>(sym))
|
||||
return {ds->section, false, ds->value, loc};
|
||||
if (auto *ds = dyn_cast<Defined>(sym)) {
|
||||
ExprValue v{ds->section, false, ds->value, loc};
|
||||
// Retain the original st_type, so that the alias will get the same
|
||||
// behavior in relocation processing. Any operation will reset st_type to
|
||||
// STT_NOTYPE.
|
||||
v.type = ds->type;
|
||||
return v;
|
||||
}
|
||||
if (isa<SharedSymbol>(sym))
|
||||
if (!errorOnMissingSection)
|
||||
return {nullptr, false, 0, loc};
|
||||
|
@ -59,6 +59,10 @@ struct ExprValue {
|
||||
uint64_t val;
|
||||
uint64_t alignment = 1;
|
||||
|
||||
// The original st_type if the expression represents a symbol. Any operation
|
||||
// resets type to STT_NOTYPE.
|
||||
uint8_t type = llvm::ELF::STT_NOTYPE;
|
||||
|
||||
// Original source location. Used for error messages.
|
||||
std::string loc;
|
||||
};
|
||||
|
@ -77,10 +77,14 @@ OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags)
|
||||
// to be allocated for nobits sections. Other ones don't require
|
||||
// any special treatment on top of progbits, so there doesn't
|
||||
// seem to be a harm in merging them.
|
||||
//
|
||||
// NOTE: clang since rL252300 emits SHT_X86_64_UNWIND .eh_frame sections. Allow
|
||||
// them to be merged into SHT_PROGBITS .eh_frame (GNU as .cfi_*).
|
||||
static bool canMergeToProgbits(unsigned type) {
|
||||
return type == SHT_NOBITS || type == SHT_PROGBITS || type == SHT_INIT_ARRAY ||
|
||||
type == SHT_PREINIT_ARRAY || type == SHT_FINI_ARRAY ||
|
||||
type == SHT_NOTE;
|
||||
type == SHT_NOTE ||
|
||||
(type == SHT_X86_64_UNWIND && config->emachine == EM_X86_64);
|
||||
}
|
||||
|
||||
// Record that isec will be placed in the OutputSection. isec does not become
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "lld/Common/Strings.h"
|
||||
#include "lld/Common/Version.h"
|
||||
#include "llvm/ADT/SetOperations.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
|
||||
@ -2653,15 +2654,6 @@ void GdbIndexSection::initOutputSize() {
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<InputSection *> getDebugInfoSections() {
|
||||
std::vector<InputSection *> ret;
|
||||
for (InputSectionBase *s : inputSections)
|
||||
if (InputSection *isec = dyn_cast<InputSection>(s))
|
||||
if (isec->name == ".debug_info")
|
||||
ret.push_back(isec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &dwarf) {
|
||||
std::vector<GdbIndexSection::CuEntry> ret;
|
||||
for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units())
|
||||
@ -2815,30 +2807,40 @@ createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> nameAttrs,
|
||||
|
||||
// Returns a newly-created .gdb_index section.
|
||||
template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
|
||||
std::vector<InputSection *> sections = getDebugInfoSections();
|
||||
|
||||
// .debug_gnu_pub{names,types} are useless in executables.
|
||||
// They are present in input object files solely for creating
|
||||
// a .gdb_index. So we can remove them from the output.
|
||||
for (InputSectionBase *s : inputSections)
|
||||
// Collect InputFiles with .debug_info. See the comment in
|
||||
// LLDDwarfObj<ELFT>::LLDDwarfObj. If we do lightweight parsing in the future,
|
||||
// note that isec->data() may uncompress the full content, which should be
|
||||
// parallelized.
|
||||
SetVector<InputFile *> files;
|
||||
for (InputSectionBase *s : inputSections) {
|
||||
InputSection *isec = dyn_cast<InputSection>(s);
|
||||
if (!isec)
|
||||
continue;
|
||||
// .debug_gnu_pub{names,types} are useless in executables.
|
||||
// They are present in input object files solely for creating
|
||||
// a .gdb_index. So we can remove them from the output.
|
||||
if (s->name == ".debug_gnu_pubnames" || s->name == ".debug_gnu_pubtypes")
|
||||
s->markDead();
|
||||
else if (isec->name == ".debug_info")
|
||||
files.insert(isec->file);
|
||||
}
|
||||
|
||||
std::vector<GdbChunk> chunks(sections.size());
|
||||
std::vector<std::vector<NameAttrEntry>> nameAttrs(sections.size());
|
||||
std::vector<GdbChunk> chunks(files.size());
|
||||
std::vector<std::vector<NameAttrEntry>> nameAttrs(files.size());
|
||||
|
||||
parallelForEachN(0, sections.size(), [&](size_t i) {
|
||||
parallelForEachN(0, files.size(), [&](size_t i) {
|
||||
// To keep memory usage low, we don't want to keep cached DWARFContext, so
|
||||
// avoid getDwarf() here.
|
||||
ObjFile<ELFT> *file = sections[i]->getFile<ELFT>();
|
||||
ObjFile<ELFT> *file = cast<ObjFile<ELFT>>(files[i]);
|
||||
DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
|
||||
auto &dobj = static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj());
|
||||
|
||||
chunks[i].sec = sections[i];
|
||||
// If the are multiple compile units .debug_info (very rare ld -r --unique),
|
||||
// this only picks the last one. Other address ranges are lost.
|
||||
chunks[i].sec = dobj.getInfoSection();
|
||||
chunks[i].compilationUnits = readCuList(dwarf);
|
||||
chunks[i].addressAreas = readAddressAreas(dwarf, sections[i]);
|
||||
nameAttrs[i] = readPubNamesAndTypes<ELFT>(
|
||||
static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj()),
|
||||
chunks[i].compilationUnits);
|
||||
chunks[i].addressAreas = readAddressAreas(dwarf, chunks[i].sec);
|
||||
nameAttrs[i] = readPubNamesAndTypes<ELFT>(dobj, chunks[i].compilationUnits);
|
||||
});
|
||||
|
||||
auto *ret = make<GdbIndexSection>();
|
||||
|
@ -17,6 +17,25 @@ possible. We reserve the right to make different implementation choices where
|
||||
it is appropriate for LLD. Intentional deviations will be documented in this
|
||||
file.
|
||||
|
||||
Symbol assignment
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
A symbol assignment looks like:
|
||||
|
||||
::
|
||||
|
||||
symbol = expression;
|
||||
symbol += expression;
|
||||
|
||||
The first form defines ``symbol``. If ``symbol`` is already defined, it will be
|
||||
overridden. The other form requires ``symbol`` to be already defined.
|
||||
|
||||
For a simple assignment like ``alias = aliasee;``, the ``st_type`` field is
|
||||
copied from the original symbol. Any arithmetic operation (e.g. ``+ 0`` will
|
||||
reset ``st_type`` to ``STT_NOTYPE``.
|
||||
|
||||
The ``st_size`` field is set to 0.
|
||||
|
||||
Output section description
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -24,22 +24,143 @@ Non-comprehensive list of changes in this release
|
||||
ELF Improvements
|
||||
----------------
|
||||
|
||||
* New ``--time-trace`` option records a time trace file that can be viewed in
|
||||
* ``--lto-emit-asm`` is added to emit assembly output for debugging purposes.
|
||||
(`D77231 <https://reviews.llvm.org/D77231>`_)
|
||||
* ``--lto-whole-program-visibility`` is added to specify that classes have hidden LTO visibility in LTO and ThinLTO links of source files compiled with ``-fwhole-program-vtables``. See `LTOVisibility <https://clang.llvm.org/docs/LTOVisibility.html>`_ for details.
|
||||
(`D71913 <https://reviews.llvm.org/D71913>`_)
|
||||
* ``--print-archive-stats=`` is added to print the number of members and the number of fetched members for each archive.
|
||||
The feature is similar to GNU gold's ``--print-symbol-counts=``.
|
||||
(`D78983 <https://reviews.llvm.org/D78983>`_)
|
||||
* ``--shuffle-sections=`` is added to introduce randomization in the output to help reduce measurement bias and detect static initialization order fiasco.
|
||||
(`D74791 <https://reviews.llvm.org/D74791>`_)
|
||||
(`D74887 <https://reviews.llvm.org/D74887>`_)
|
||||
* ``--time-trace`` is added. It records a time trace file that can be viewed in
|
||||
chrome://tracing. The file can be specified with ``--time-trace-file``.
|
||||
Trace granularity can be specified with ``--time-trace-granularity``.
|
||||
(`D71060 <https://reviews.llvm.org/D71060>`_)
|
||||
* For ARM architectures the default max page size was increased to 64k.
|
||||
This increases compatibility with systems where a non standard page
|
||||
size was configured. This also is inline with GNU ld defaults.
|
||||
(`D77330 <https://reviews.llvm.org/D77330>`_)
|
||||
* ...
|
||||
* ``--thinlto-single-module`` is added to compile a subset of modules in ThinLTO for debugging purposes.
|
||||
(`D80406 <https://reviews.llvm.org/D80406>`_)
|
||||
* ``--unique`` is added to create separate output sections for orphan sections.
|
||||
(`D75536 <https://reviews.llvm.org/D75536>`_)
|
||||
* ``--warn-backrefs`` has been improved to emulate GNU ld's archive semantics.
|
||||
If a link passes with warnings from ``--warn-backrefs``, it almost assuredly
|
||||
means that the link will fail with GNU ld, or the symbol will get different
|
||||
resolutions in GNU ld and LLD. ``--warn-backrefs-exclude=`` is added to
|
||||
exclude known issues.
|
||||
(`D77522 <https://reviews.llvm.org/D77522>`_)
|
||||
(`D77630 <https://reviews.llvm.org/D77630>`_)
|
||||
(`D77512 <https://reviews.llvm.org/D77512>`_)
|
||||
* ``--no-relax`` is accepted but ignored. The Linux kernel's RISC-V port uses this option.
|
||||
(`D81359 <https://reviews.llvm.org/D81359>`_)
|
||||
* ``--rosegment`` (default) is added to complement ``--no-rosegment``.
|
||||
GNU gold from 2.35 onwards support both options.
|
||||
* ``--threads=N`` is added. The default uses all threads.
|
||||
(`D76885 <https://reviews.llvm.org/D76885>`_)
|
||||
* ``--wrap`` has better compatibility with GNU ld.
|
||||
* ``-z dead-reloc-in-nonalloc=<section_glob>=<value>`` is added to resolve an absolute relocation
|
||||
referencing a discarded symbol.
|
||||
(`D83264 <https://reviews.llvm.org/D83264>`_)
|
||||
* Changed tombstone values to (``.debug_ranges``/``.debug_loc``) 1 and (other ``.debug_*``) 0.
|
||||
A tombstone value is the computed value of a relocation referencing a discarded symbol (``--gc-sections``, ICF or ``/DISCARD/``).
|
||||
(`D84825 <https://reviews.llvm.org/D84825>`_)
|
||||
In the future many .debug_* may switch to 0xffffffff/0xffffffffffffffff as the tombstone value.
|
||||
* ``-z keep-text-section-prefix`` moves ``.text.unknown.*`` input sections to ``.text.unknown``.
|
||||
* ``-z rel`` and ``-z rela`` are added to select the REL/RELA format for dynamic relocations.
|
||||
The default is target specific and typically matches the form used in relocatable objects.
|
||||
* ``-z start-stop-visibility={default,protected,internal,hidden}`` is added.
|
||||
GNU ld/gold from 2.35 onwards support this option.
|
||||
(`D55682 <https://reviews.llvm.org/D55682>`_)
|
||||
* When ``-r`` or ``--emit-relocs`` is specified, the GNU ld compatible
|
||||
``--discard-all`` and ``--discard-locals`` semantics are implemented.
|
||||
(`D77807 <https://reviews.llvm.org/D77807>`_)
|
||||
* ``--emit-relocs --strip-debug`` can now be used together.
|
||||
(`D74375 <https://reviews.llvm.org/D74375>`_)
|
||||
* ``--gdb-index`` supports DWARF v5.
|
||||
(`D79061 <https://reviews.llvm.org/D79061>`_)
|
||||
(`D85579 <https://reviews.llvm.org/D85579>`_)
|
||||
* ``-r`` allows SHT_X86_64_UNWIND to be merged into SHT_PROGBITS.
|
||||
This allows clang/GCC produced object files to be mixed together.
|
||||
(`D85785 <https://reviews.llvm.org/D85785>`_)
|
||||
* Better linker script support related to output section alignments and LMA regions.
|
||||
(`D74286 <https://reviews.llvm.org/D75724>`_)
|
||||
(`D74297 <https://reviews.llvm.org/D75724>`_)
|
||||
(`D75724 <https://reviews.llvm.org/D75724>`_)
|
||||
(`D81986 <https://reviews.llvm.org/D81986>`_)
|
||||
* In a input section description, the filename can be specified in double quotes.
|
||||
``archive:file`` syntax is added.
|
||||
(`D72517 <https://reviews.llvm.org/D72517>`_)
|
||||
(`D75100 <https://reviews.llvm.org/D75100>`_)
|
||||
* Linker script specified empty ``(.init|.preinit|.fini)_array`` are allowed with RELRO.
|
||||
(`D76915 <https://reviews.llvm.org/D76915>`_)
|
||||
* ``INSERT AFTER`` and ``INSERT BEFORE`` work for orphan sections now.
|
||||
(`D74375 <https://reviews.llvm.org/D74375>`_)
|
||||
* ``INPUT_SECTION_FLAGS`` is supported in linker scripts.
|
||||
(`D72745 <https://reviews.llvm.org/D72745>`_)
|
||||
* ``DF_1_PIE`` is set for position-independent executables.
|
||||
(`D80872 <https://reviews.llvm.org/D80872>`_)
|
||||
* For a symbol assignment ``alias = aliasee;``, ``alias`` inherits the ``aliasee``'s symbol type.
|
||||
(`D86263 <https://reviews.llvm.org/D86263>`_)
|
||||
* ``SHT_GNU_verneed`` in shared objects are parsed, and versioned undefined symbols in shared objects are respected.
|
||||
(`D80059 <https://reviews.llvm.org/D80059>`_)
|
||||
* SHF_LINK_ORDER and non-SHF_LINK_ORDER sections can be mixed along as the SHF_LINK_ORDER components are contiguous.
|
||||
(`D77007 <https://reviews.llvm.org/D77007>`_)
|
||||
* An out-of-range relocation diagnostic mentions the referenced symbol now.
|
||||
(`D73518 <https://reviews.llvm.org/D73518>`_)
|
||||
* AArch64: ``R_AARCH64_PLT32`` is supported.
|
||||
(`D81184 <https://reviews.llvm.org/D81184>`_)
|
||||
* ARM: SBREL type relocations are supported.
|
||||
(`D74375 <https://reviews.llvm.org/D74375>`_)
|
||||
* ARM: ``R_ARM_ALU_PC_G0``, ``R_ARM_LDR_PC_G0``, ``R_ARM_THUMB_PC8`` and ``R_ARM_THUMB__PC12`` are supported.
|
||||
(`D75349 <https://reviews.llvm.org/D75349>`_)
|
||||
(`D77200 <https://reviews.llvm.org/D77200>`_)
|
||||
* ARM: various improvements to .ARM.exidx: ``/DISCARD/`` support for a subset, out-of-range handling, support for non monotonic section order.
|
||||
(`PR44824 <https://llvm.org/PR44824>`_)
|
||||
* AVR: many relocation types are supported.
|
||||
(`D78741 <https://reviews.llvm.org/D78741>`_)
|
||||
* Hexagon: General Dynamic and some other relocation types are supported.
|
||||
* PPC: Canonical PLT and range extension thunks with addends are supported.
|
||||
(`D73399 <https://reviews.llvm.org/D73399>`_)
|
||||
(`D73424 <https://reviews.llvm.org/D73424>`_)
|
||||
(`D75394 <https://reviews.llvm.org/D75394>`_)
|
||||
* PPC and PPC64: copy relocations.
|
||||
(`D73255 <https://reviews.llvm.org/D73255>`_)
|
||||
* PPC64: ``_savegpr[01]_{14..31}`` and ``_restgpr[01]_{14..31}`` can be synthesized.
|
||||
(`D79977 <https://reviews.llvm.org/D79977>`_)
|
||||
* PPC64: ``R_PPC64_GOT_PCREL34`` and ``R_PPC64_REL24_NOTOC`` are supported. r2 save stub is supported.
|
||||
(`D81948 <https://reviews.llvm.org/D81948>`_)
|
||||
(`D82950 <https://reviews.llvm.org/D82950>`_)
|
||||
(`D82816 <https://reviews.llvm.org/D82816>`_)
|
||||
* RISC-V: ``R_RISCV_IRELATIVE`` is supported.
|
||||
(`D74022 <https://reviews.llvm.org/D74022>`_)
|
||||
* RISC-V: ``R_RISCV_ALIGN`` is errored because GNU ld style linker relaxation is not supported.
|
||||
(`D71820 <https://reviews.llvm.org/D71820>`_)
|
||||
* SPARCv9: more relocation types are supported.
|
||||
(`D77672 <https://reviews.llvm.org/D77672>`_)
|
||||
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
* One-dash form of some long option (``--thinlto-*``, ``--lto-*``, ``--shuffle-sections=``)
|
||||
are no longer supported.
|
||||
(`D79371 <https://reviews.llvm.org/D79371>`_)
|
||||
* ``--export-dynamic-symbol`` no longer implies ``-u``.
|
||||
The new behavior matches GNU ld from binutils 2.35 onwards.
|
||||
(`D80487 <https://reviews.llvm.org/D80487>`_)
|
||||
* ARM: the default max page size was increased from 4096 to 65536.
|
||||
This increases compatibility with systems where a non standard page
|
||||
size was configured. This also is inline with GNU ld defaults.
|
||||
(`D77330 <https://reviews.llvm.org/D77330>`_)
|
||||
* ARM: for non-STT_FUNC symbols, Thumb interworking thunks are not added and BL/BLX are not substituted.
|
||||
(`D73474 <https://reviews.llvm.org/D73474>`_)
|
||||
(`D73542 <https://reviews.llvm.org/D73542>`_)
|
||||
* AArch64: ``--force-bti`` is renamed to ``-z force-bti`. ``--pac-plt`` is renamed to ``-z pac-plt``.
|
||||
This change is compatibile with GNU ld.
|
||||
* A readonly ``PT_LOAD`` is created in the presence of a ``SECTIONS`` command.
|
||||
The new behavior is consistent with the longstanding behavior in the absence of a SECTIONS command.
|
||||
* Orphan section names like ``.rodata.foo`` and ``.text.foo`` are not grouped into ``.rodata`` and ``.text`` in the presence of a ``SECTIONS`` command.
|
||||
The new behavior matches GNU ld.
|
||||
(`D75225 <https://reviews.llvm.org/D75225>`_)
|
||||
* ``--no-threads`` is removed. Use ``--threads=1`` instead. ``--threads`` (no-op) is removed.
|
||||
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
@ -2401,21 +2401,13 @@ lldb::addr_t Target::GetPersistentSymbol(ConstString name) {
|
||||
|
||||
llvm::Expected<lldb_private::Address> Target::GetEntryPointAddress() {
|
||||
Module *exe_module = GetExecutableModulePointer();
|
||||
llvm::Error error = llvm::Error::success();
|
||||
assert(!error); // Check the success value when assertions are enabled.
|
||||
|
||||
if (!exe_module || !exe_module->GetObjectFile()) {
|
||||
error = llvm::make_error<llvm::StringError>("No primary executable found",
|
||||
llvm::inconvertibleErrorCode());
|
||||
} else {
|
||||
// Try to find the entry point address in the primary executable.
|
||||
const bool has_primary_executable = exe_module && exe_module->GetObjectFile();
|
||||
if (has_primary_executable) {
|
||||
Address entry_addr = exe_module->GetObjectFile()->GetEntryPointAddress();
|
||||
if (entry_addr.IsValid())
|
||||
return entry_addr;
|
||||
|
||||
error = llvm::make_error<llvm::StringError>(
|
||||
"Could not find entry point address for executable module \"" +
|
||||
exe_module->GetFileSpec().GetFilename().GetStringRef() + "\"",
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
const ModuleList &modules = GetImages();
|
||||
@ -2426,14 +2418,21 @@ llvm::Expected<lldb_private::Address> Target::GetEntryPointAddress() {
|
||||
continue;
|
||||
|
||||
Address entry_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
|
||||
if (entry_addr.IsValid()) {
|
||||
// Discard the error.
|
||||
llvm::consumeError(std::move(error));
|
||||
if (entry_addr.IsValid())
|
||||
return entry_addr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(error);
|
||||
// We haven't found the entry point address. Return an appropriate error.
|
||||
if (!has_primary_executable)
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"No primary executable found and could not find entry point address in "
|
||||
"any executable module",
|
||||
llvm::inconvertibleErrorCode());
|
||||
|
||||
return llvm::make_error<llvm::StringError>(
|
||||
"Could not find entry point address for primary executable module \"" +
|
||||
exe_module->GetFileSpec().GetFilename().GetStringRef() + "\"",
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr,
|
||||
|
@ -34,15 +34,14 @@ namespace llvm {
|
||||
/// performance for non-sequential find() operations.
|
||||
///
|
||||
/// \tparam IndexT - The type of the index into the bitvector.
|
||||
/// \tparam N - The first N coalesced intervals of set bits are stored in-place.
|
||||
template <typename IndexT, unsigned N = 16> class CoalescingBitVector {
|
||||
template <typename IndexT> class CoalescingBitVector {
|
||||
static_assert(std::is_unsigned<IndexT>::value,
|
||||
"Index must be an unsigned integer.");
|
||||
|
||||
using ThisT = CoalescingBitVector<IndexT, N>;
|
||||
using ThisT = CoalescingBitVector<IndexT>;
|
||||
|
||||
/// An interval map for closed integer ranges. The mapped values are unused.
|
||||
using MapT = IntervalMap<IndexT, char, N>;
|
||||
using MapT = IntervalMap<IndexT, char>;
|
||||
|
||||
using UnderlyingIterator = typename MapT::const_iterator;
|
||||
|
||||
|
@ -268,6 +268,12 @@ Value *SimplifyFreezeInst(Value *Op, const SimplifyQuery &Q);
|
||||
Value *SimplifyInstruction(Instruction *I, const SimplifyQuery &Q,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
|
||||
/// See if V simplifies when its operand Op is replaced with RepOp.
|
||||
/// AllowRefinement specifies whether the simplification can be a refinement,
|
||||
/// or whether it needs to be strictly identical.
|
||||
Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
const SimplifyQuery &Q, bool AllowRefinement);
|
||||
|
||||
/// Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively.
|
||||
///
|
||||
/// This first performs a normal RAUW of I with SimpleV. It then recursively
|
||||
|
@ -210,12 +210,19 @@ class OpenMPIRBuilder {
|
||||
/// Return the (LLVM-IR) string describing the default source location.
|
||||
Constant *getOrCreateDefaultSrcLocStr();
|
||||
|
||||
/// Return the (LLVM-IR) string describing the source location identified by
|
||||
/// the arguments.
|
||||
Constant *getOrCreateSrcLocStr(StringRef FunctionName, StringRef FileName,
|
||||
unsigned Line, unsigned Column);
|
||||
|
||||
/// Return the (LLVM-IR) string describing the source location \p Loc.
|
||||
Constant *getOrCreateSrcLocStr(const LocationDescription &Loc);
|
||||
|
||||
/// Return an ident_t* encoding the source location \p SrcLocStr and \p Flags.
|
||||
/// TODO: Create a enum class for the Reserve2Flags
|
||||
Value *getOrCreateIdent(Constant *SrcLocStr,
|
||||
omp::IdentFlag Flags = omp::IdentFlag(0));
|
||||
omp::IdentFlag Flags = omp::IdentFlag(0),
|
||||
unsigned Reserve2Flags = 0);
|
||||
|
||||
/// Generate control flow and cleanup for cancellation.
|
||||
///
|
||||
@ -280,7 +287,7 @@ class OpenMPIRBuilder {
|
||||
StringMap<Constant *> SrcLocStrMap;
|
||||
|
||||
/// Map to remember existing ident_t*.
|
||||
DenseMap<std::pair<Constant *, uint64_t>, GlobalVariable *> IdentMap;
|
||||
DenseMap<std::pair<Constant *, uint64_t>, Value *> IdentMap;
|
||||
|
||||
/// Helper that contains information about regions we need to outline
|
||||
/// during finalization.
|
||||
|
@ -386,8 +386,12 @@ class IRBuilderBase {
|
||||
/// filled in with the null terminated string value specified. The new global
|
||||
/// variable will be marked mergable with any others of the same contents. If
|
||||
/// Name is specified, it is the name of the global variable created.
|
||||
///
|
||||
/// If no module is given via \p M, it is take from the insertion point basic
|
||||
/// block.
|
||||
GlobalVariable *CreateGlobalString(StringRef Str, const Twine &Name = "",
|
||||
unsigned AddressSpace = 0);
|
||||
unsigned AddressSpace = 0,
|
||||
Module *M = nullptr);
|
||||
|
||||
/// Get a constant value representing either true or false.
|
||||
ConstantInt *getInt1(bool V) {
|
||||
@ -1934,9 +1938,13 @@ class IRBuilderBase {
|
||||
|
||||
/// Same as CreateGlobalString, but return a pointer with "i8*" type
|
||||
/// instead of a pointer to array of i8.
|
||||
///
|
||||
/// If no module is given via \p M, it is take from the insertion point basic
|
||||
/// block.
|
||||
Constant *CreateGlobalStringPtr(StringRef Str, const Twine &Name = "",
|
||||
unsigned AddressSpace = 0) {
|
||||
GlobalVariable *GV = CreateGlobalString(Str, Name, AddressSpace);
|
||||
unsigned AddressSpace = 0,
|
||||
Module *M = nullptr) {
|
||||
GlobalVariable *GV = CreateGlobalString(Str, Name, AddressSpace, M);
|
||||
Constant *Zero = ConstantInt::get(Type::getInt32Ty(Context), 0);
|
||||
Constant *Indices[] = {Zero, Zero};
|
||||
return ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV,
|
||||
|
@ -3810,10 +3810,10 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
return ::SimplifyFCmpInst(Predicate, LHS, RHS, FMF, Q, RecursionLimit);
|
||||
}
|
||||
|
||||
/// See if V simplifies when its operand Op is replaced with RepOp.
|
||||
static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
const SimplifyQuery &Q,
|
||||
unsigned MaxRecurse) {
|
||||
static Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
const SimplifyQuery &Q,
|
||||
bool AllowRefinement,
|
||||
unsigned MaxRecurse) {
|
||||
// Trivial replacement.
|
||||
if (V == Op)
|
||||
return RepOp;
|
||||
@ -3826,23 +3826,19 @@ static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
if (!I)
|
||||
return nullptr;
|
||||
|
||||
// Consider:
|
||||
// %cmp = icmp eq i32 %x, 2147483647
|
||||
// %add = add nsw i32 %x, 1
|
||||
// %sel = select i1 %cmp, i32 -2147483648, i32 %add
|
||||
//
|
||||
// We can't replace %sel with %add unless we strip away the flags (which will
|
||||
// be done in InstCombine).
|
||||
// TODO: This is unsound, because it only catches some forms of refinement.
|
||||
if (!AllowRefinement && canCreatePoison(I))
|
||||
return nullptr;
|
||||
|
||||
// If this is a binary operator, try to simplify it with the replaced op.
|
||||
if (auto *B = dyn_cast<BinaryOperator>(I)) {
|
||||
// Consider:
|
||||
// %cmp = icmp eq i32 %x, 2147483647
|
||||
// %add = add nsw i32 %x, 1
|
||||
// %sel = select i1 %cmp, i32 -2147483648, i32 %add
|
||||
//
|
||||
// We can't replace %sel with %add unless we strip away the flags.
|
||||
// TODO: This is an unusual limitation because better analysis results in
|
||||
// worse simplification. InstCombine can do this fold more generally
|
||||
// by dropping the flags. Remove this fold to save compile-time?
|
||||
if (isa<OverflowingBinaryOperator>(B))
|
||||
if (Q.IIQ.hasNoSignedWrap(B) || Q.IIQ.hasNoUnsignedWrap(B))
|
||||
return nullptr;
|
||||
if (isa<PossiblyExactOperator>(B) && Q.IIQ.isExact(B))
|
||||
return nullptr;
|
||||
|
||||
if (MaxRecurse) {
|
||||
if (B->getOperand(0) == Op)
|
||||
return SimplifyBinOp(B->getOpcode(), RepOp, B->getOperand(1), Q,
|
||||
@ -3909,6 +3905,13 @@ static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value *llvm::SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
const SimplifyQuery &Q,
|
||||
bool AllowRefinement) {
|
||||
return ::SimplifyWithOpReplaced(V, Op, RepOp, Q, AllowRefinement,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// Try to simplify a select instruction when its condition operand is an
|
||||
/// integer comparison where one operand of the compare is a constant.
|
||||
static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X,
|
||||
@ -3968,12 +3971,18 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
|
||||
if (!match(CondVal, m_ICmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS))))
|
||||
return nullptr;
|
||||
|
||||
if (ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero())) {
|
||||
// Canonicalize ne to eq predicate.
|
||||
if (Pred == ICmpInst::ICMP_NE) {
|
||||
Pred = ICmpInst::ICMP_EQ;
|
||||
std::swap(TrueVal, FalseVal);
|
||||
}
|
||||
|
||||
if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) {
|
||||
Value *X;
|
||||
const APInt *Y;
|
||||
if (match(CmpLHS, m_And(m_Value(X), m_APInt(Y))))
|
||||
if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, Y,
|
||||
Pred == ICmpInst::ICMP_EQ))
|
||||
/*TrueWhenUnset=*/true))
|
||||
return V;
|
||||
|
||||
// Test for a bogus zero-shift-guard-op around funnel-shift or rotate.
|
||||
@ -3984,13 +3993,7 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
|
||||
m_Value(ShAmt)));
|
||||
// (ShAmt == 0) ? fshl(X, *, ShAmt) : X --> X
|
||||
// (ShAmt == 0) ? fshr(*, X, ShAmt) : X --> X
|
||||
if (match(TrueVal, isFsh) && FalseVal == X && CmpLHS == ShAmt &&
|
||||
Pred == ICmpInst::ICMP_EQ)
|
||||
return X;
|
||||
// (ShAmt != 0) ? X : fshl(X, *, ShAmt) --> X
|
||||
// (ShAmt != 0) ? X : fshr(*, X, ShAmt) --> X
|
||||
if (match(FalseVal, isFsh) && TrueVal == X && CmpLHS == ShAmt &&
|
||||
Pred == ICmpInst::ICMP_NE)
|
||||
if (match(TrueVal, isFsh) && FalseVal == X && CmpLHS == ShAmt)
|
||||
return X;
|
||||
|
||||
// Test for a zero-shift-guard-op around rotates. These are used to
|
||||
@ -4004,11 +4007,6 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
|
||||
m_Intrinsic<Intrinsic::fshr>(m_Value(X),
|
||||
m_Deferred(X),
|
||||
m_Value(ShAmt)));
|
||||
// (ShAmt != 0) ? fshl(X, X, ShAmt) : X --> fshl(X, X, ShAmt)
|
||||
// (ShAmt != 0) ? fshr(X, X, ShAmt) : X --> fshr(X, X, ShAmt)
|
||||
if (match(TrueVal, isRotate) && FalseVal == X && CmpLHS == ShAmt &&
|
||||
Pred == ICmpInst::ICMP_NE)
|
||||
return TrueVal;
|
||||
// (ShAmt == 0) ? X : fshl(X, X, ShAmt) --> fshl(X, X, ShAmt)
|
||||
// (ShAmt == 0) ? X : fshr(X, X, ShAmt) --> fshr(X, X, ShAmt)
|
||||
if (match(FalseVal, isRotate) && TrueVal == X && CmpLHS == ShAmt &&
|
||||
@ -4025,27 +4023,20 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
|
||||
// arms of the select. See if substituting this value into the arm and
|
||||
// simplifying the result yields the same value as the other arm.
|
||||
if (Pred == ICmpInst::ICMP_EQ) {
|
||||
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, MaxRecurse) ==
|
||||
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q,
|
||||
/* AllowRefinement */ false, MaxRecurse) ==
|
||||
TrueVal ||
|
||||
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q, MaxRecurse) ==
|
||||
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q,
|
||||
/* AllowRefinement */ false, MaxRecurse) ==
|
||||
TrueVal)
|
||||
return FalseVal;
|
||||
if (SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, MaxRecurse) ==
|
||||
if (SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q,
|
||||
/* AllowRefinement */ true, MaxRecurse) ==
|
||||
FalseVal ||
|
||||
SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q, MaxRecurse) ==
|
||||
SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q,
|
||||
/* AllowRefinement */ true, MaxRecurse) ==
|
||||
FalseVal)
|
||||
return FalseVal;
|
||||
} else if (Pred == ICmpInst::ICMP_NE) {
|
||||
if (SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q, MaxRecurse) ==
|
||||
FalseVal ||
|
||||
SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q, MaxRecurse) ==
|
||||
FalseVal)
|
||||
return TrueVal;
|
||||
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, MaxRecurse) ==
|
||||
TrueVal ||
|
||||
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q, MaxRecurse) ==
|
||||
TrueVal)
|
||||
return TrueVal;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -1592,11 +1592,16 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
|
||||
assert(Element->getTag() == dwarf::DW_TAG_subrange_type);
|
||||
|
||||
const DISubrange *Subrange = cast<DISubrange>(Element);
|
||||
assert(!Subrange->getRawLowerBound() &&
|
||||
"codeview doesn't support subranges with lower bounds");
|
||||
int64_t Count = -1;
|
||||
if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>())
|
||||
Count = CI->getSExtValue();
|
||||
// Calculate the count if either LowerBound is absent or is zero and
|
||||
// either of Count or UpperBound are constant.
|
||||
auto *LI = Subrange->getLowerBound().dyn_cast<ConstantInt *>();
|
||||
if (!Subrange->getRawLowerBound() || (LI && (LI->getSExtValue() == 0))) {
|
||||
if (auto *CI = Subrange->getCount().dyn_cast<ConstantInt*>())
|
||||
Count = CI->getSExtValue();
|
||||
else if (auto *UI = Subrange->getUpperBound().dyn_cast<ConstantInt*>())
|
||||
Count = UI->getSExtValue() + 1; // LowerBound is zero
|
||||
}
|
||||
|
||||
// Forward declarations of arrays without a size and VLAs use a count of -1.
|
||||
// Emit a count of zero in these cases to match what MSVC does for arrays
|
||||
|
@ -1417,8 +1417,10 @@ static bool hasVectorBeenPadded(const DICompositeType *CTy) {
|
||||
Elements[0]->getTag() == dwarf::DW_TAG_subrange_type &&
|
||||
"Invalid vector element array, expected one element of type subrange");
|
||||
const auto Subrange = cast<DISubrange>(Elements[0]);
|
||||
const auto CI = Subrange->getCount().get<ConstantInt *>();
|
||||
const int32_t NumVecElements = CI->getSExtValue();
|
||||
const auto NumVecElements =
|
||||
Subrange->getCount()
|
||||
? Subrange->getCount().get<ConstantInt *>()->getSExtValue()
|
||||
: 0;
|
||||
|
||||
// Ensure we found the element count and that the actual size is wide
|
||||
// enough to contain the requested size.
|
||||
|
@ -336,10 +336,8 @@ static bool isNopCopy(const MachineInstr &PreviousCopy, unsigned Src,
|
||||
unsigned Def, const TargetRegisterInfo *TRI) {
|
||||
Register PreviousSrc = PreviousCopy.getOperand(1).getReg();
|
||||
Register PreviousDef = PreviousCopy.getOperand(0).getReg();
|
||||
if (Src == PreviousSrc) {
|
||||
assert(Def == PreviousDef);
|
||||
if (Src == PreviousSrc && Def == PreviousDef)
|
||||
return true;
|
||||
}
|
||||
if (!TRI->isSubRegister(PreviousSrc, Src))
|
||||
return false;
|
||||
unsigned SubIdx = TRI->getSubRegIndex(PreviousSrc, Src);
|
||||
|
@ -106,8 +106,13 @@ namespace {
|
||||
/// that it is alive across blocks.
|
||||
BitVector MayLiveAcrossBlocks;
|
||||
|
||||
/// State of a register unit.
|
||||
enum RegUnitState {
|
||||
/// State of a physical register.
|
||||
enum RegState {
|
||||
/// A disabled register is not available for allocation, but an alias may
|
||||
/// be in use. A register can only be moved out of the disabled state if
|
||||
/// all aliases are disabled.
|
||||
regDisabled,
|
||||
|
||||
/// A free register is not currently in use and can be allocated
|
||||
/// immediately without checking aliases.
|
||||
regFree,
|
||||
@ -121,8 +126,8 @@ namespace {
|
||||
/// register. In that case, LiveVirtRegs contains the inverse mapping.
|
||||
};
|
||||
|
||||
/// Maps each physical register to a RegUnitState enum or virtual register.
|
||||
std::vector<unsigned> RegUnitStates;
|
||||
/// Maps each physical register to a RegState enum or a virtual register.
|
||||
std::vector<unsigned> PhysRegState;
|
||||
|
||||
SmallVector<Register, 16> VirtDead;
|
||||
SmallVector<MachineInstr *, 32> Coalesced;
|
||||
@ -184,10 +189,6 @@ namespace {
|
||||
bool isLastUseOfLocalReg(const MachineOperand &MO) const;
|
||||
|
||||
void addKillFlag(const LiveReg &LRI);
|
||||
#ifndef NDEBUG
|
||||
bool verifyRegStateMapping(const LiveReg &LR) const;
|
||||
#endif
|
||||
|
||||
void killVirtReg(LiveReg &LR);
|
||||
void killVirtReg(Register VirtReg);
|
||||
void spillVirtReg(MachineBasicBlock::iterator MI, LiveReg &LR);
|
||||
@ -195,7 +196,7 @@ namespace {
|
||||
|
||||
void usePhysReg(MachineOperand &MO);
|
||||
void definePhysReg(MachineBasicBlock::iterator MI, MCPhysReg PhysReg,
|
||||
unsigned NewState);
|
||||
RegState NewState);
|
||||
unsigned calcSpillCost(MCPhysReg PhysReg) const;
|
||||
void assignVirtToPhysReg(LiveReg &, MCPhysReg PhysReg);
|
||||
|
||||
@ -228,7 +229,7 @@ namespace {
|
||||
bool mayLiveOut(Register VirtReg);
|
||||
bool mayLiveIn(Register VirtReg);
|
||||
|
||||
void dumpState() const;
|
||||
void dumpState();
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -239,8 +240,7 @@ INITIALIZE_PASS(RegAllocFast, "regallocfast", "Fast Register Allocator", false,
|
||||
false)
|
||||
|
||||
void RegAllocFast::setPhysRegState(MCPhysReg PhysReg, unsigned NewState) {
|
||||
for (MCRegUnitIterator UI(PhysReg, TRI); UI.isValid(); ++UI)
|
||||
RegUnitStates[*UI] = NewState;
|
||||
PhysRegState[PhysReg] = NewState;
|
||||
}
|
||||
|
||||
/// This allocates space for the specified virtual register to be held on the
|
||||
@ -384,23 +384,12 @@ void RegAllocFast::addKillFlag(const LiveReg &LR) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool RegAllocFast::verifyRegStateMapping(const LiveReg &LR) const {
|
||||
for (MCRegUnitIterator UI(LR.PhysReg, TRI); UI.isValid(); ++UI) {
|
||||
if (RegUnitStates[*UI] != LR.VirtReg)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Mark virtreg as no longer available.
|
||||
void RegAllocFast::killVirtReg(LiveReg &LR) {
|
||||
assert(verifyRegStateMapping(LR) && "Broken RegState mapping");
|
||||
addKillFlag(LR);
|
||||
MCPhysReg PhysReg = LR.PhysReg;
|
||||
setPhysRegState(PhysReg, regFree);
|
||||
assert(PhysRegState[LR.PhysReg] == LR.VirtReg &&
|
||||
"Broken RegState mapping");
|
||||
setPhysRegState(LR.PhysReg, regFree);
|
||||
LR.PhysReg = 0;
|
||||
}
|
||||
|
||||
@ -427,9 +416,7 @@ void RegAllocFast::spillVirtReg(MachineBasicBlock::iterator MI,
|
||||
|
||||
/// Do the actual work of spilling.
|
||||
void RegAllocFast::spillVirtReg(MachineBasicBlock::iterator MI, LiveReg &LR) {
|
||||
assert(verifyRegStateMapping(LR) && "Broken RegState mapping");
|
||||
|
||||
MCPhysReg PhysReg = LR.PhysReg;
|
||||
assert(PhysRegState[LR.PhysReg] == LR.VirtReg && "Broken RegState mapping");
|
||||
|
||||
if (LR.Dirty) {
|
||||
// If this physreg is used by the instruction, we want to kill it on the
|
||||
@ -437,7 +424,7 @@ void RegAllocFast::spillVirtReg(MachineBasicBlock::iterator MI, LiveReg &LR) {
|
||||
bool SpillKill = MachineBasicBlock::iterator(LR.LastUse) != MI;
|
||||
LR.Dirty = false;
|
||||
|
||||
spill(MI, LR.VirtReg, PhysReg, SpillKill);
|
||||
spill(MI, LR.VirtReg, LR.PhysReg, SpillKill);
|
||||
|
||||
if (SpillKill)
|
||||
LR.LastUse = nullptr; // Don't kill register again
|
||||
@ -473,16 +460,53 @@ void RegAllocFast::usePhysReg(MachineOperand &MO) {
|
||||
assert(PhysReg.isPhysical() && "Bad usePhysReg operand");
|
||||
|
||||
markRegUsedInInstr(PhysReg);
|
||||
switch (PhysRegState[PhysReg]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
case regReserved:
|
||||
PhysRegState[PhysReg] = regFree;
|
||||
LLVM_FALLTHROUGH;
|
||||
case regFree:
|
||||
MO.setIsKill();
|
||||
return;
|
||||
default:
|
||||
// The physreg was allocated to a virtual register. That means the value we
|
||||
// wanted has been clobbered.
|
||||
llvm_unreachable("Instruction uses an allocated register");
|
||||
}
|
||||
|
||||
for (MCRegUnitIterator UI(PhysReg, TRI); UI.isValid(); ++UI) {
|
||||
switch (RegUnitStates[*UI]) {
|
||||
// Maybe a superregister is reserved?
|
||||
for (MCRegAliasIterator AI(PhysReg, TRI, false); AI.isValid(); ++AI) {
|
||||
MCPhysReg Alias = *AI;
|
||||
switch (PhysRegState[Alias]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
case regReserved:
|
||||
RegUnitStates[*UI] = regFree;
|
||||
// Either PhysReg is a subregister of Alias and we mark the
|
||||
// whole register as free, or PhysReg is the superregister of
|
||||
// Alias and we mark all the aliases as disabled before freeing
|
||||
// PhysReg.
|
||||
// In the latter case, since PhysReg was disabled, this means that
|
||||
// its value is defined only by physical sub-registers. This check
|
||||
// is performed by the assert of the default case in this loop.
|
||||
// Note: The value of the superregister may only be partial
|
||||
// defined, that is why regDisabled is a valid state for aliases.
|
||||
assert((TRI->isSuperRegister(PhysReg, Alias) ||
|
||||
TRI->isSuperRegister(Alias, PhysReg)) &&
|
||||
"Instruction is not using a subregister of a reserved register");
|
||||
LLVM_FALLTHROUGH;
|
||||
case regFree:
|
||||
if (TRI->isSuperRegister(PhysReg, Alias)) {
|
||||
// Leave the superregister in the working set.
|
||||
setPhysRegState(Alias, regFree);
|
||||
MO.getParent()->addRegisterKilled(Alias, TRI, true);
|
||||
return;
|
||||
}
|
||||
// Some other alias was in the working set - clear it.
|
||||
setPhysRegState(Alias, regDisabled);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unexpected reg unit state");
|
||||
llvm_unreachable("Instruction uses an alias of an allocated register");
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,20 +519,38 @@ void RegAllocFast::usePhysReg(MachineOperand &MO) {
|
||||
/// similar to defineVirtReg except the physreg is reserved instead of
|
||||
/// allocated.
|
||||
void RegAllocFast::definePhysReg(MachineBasicBlock::iterator MI,
|
||||
MCPhysReg PhysReg, unsigned NewState) {
|
||||
for (MCRegUnitIterator UI(PhysReg, TRI); UI.isValid(); ++UI) {
|
||||
switch (unsigned VirtReg = RegUnitStates[*UI]) {
|
||||
MCPhysReg PhysReg, RegState NewState) {
|
||||
markRegUsedInInstr(PhysReg);
|
||||
switch (Register VirtReg = PhysRegState[PhysReg]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
default:
|
||||
spillVirtReg(MI, VirtReg);
|
||||
LLVM_FALLTHROUGH;
|
||||
case regFree:
|
||||
case regReserved:
|
||||
setPhysRegState(PhysReg, NewState);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a disabled register, disable all aliases.
|
||||
setPhysRegState(PhysReg, NewState);
|
||||
for (MCRegAliasIterator AI(PhysReg, TRI, false); AI.isValid(); ++AI) {
|
||||
MCPhysReg Alias = *AI;
|
||||
switch (Register VirtReg = PhysRegState[Alias]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
default:
|
||||
spillVirtReg(MI, VirtReg);
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
case regFree:
|
||||
case regReserved:
|
||||
setPhysRegState(Alias, regDisabled);
|
||||
if (TRI->isSuperRegister(PhysReg, Alias))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
markRegUsedInInstr(PhysReg);
|
||||
setPhysRegState(PhysReg, NewState);
|
||||
}
|
||||
|
||||
/// Return the cost of spilling clearing out PhysReg and aliases so it is free
|
||||
@ -521,24 +563,46 @@ unsigned RegAllocFast::calcSpillCost(MCPhysReg PhysReg) const {
|
||||
<< " is already used in instr.\n");
|
||||
return spillImpossible;
|
||||
}
|
||||
switch (Register VirtReg = PhysRegState[PhysReg]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
case regFree:
|
||||
return 0;
|
||||
case regReserved:
|
||||
LLVM_DEBUG(dbgs() << printReg(VirtReg, TRI) << " corresponding "
|
||||
<< printReg(PhysReg, TRI) << " is reserved already.\n");
|
||||
return spillImpossible;
|
||||
default: {
|
||||
LiveRegMap::const_iterator LRI = findLiveVirtReg(VirtReg);
|
||||
assert(LRI != LiveVirtRegs.end() && LRI->PhysReg &&
|
||||
"Missing VirtReg entry");
|
||||
return LRI->Dirty ? spillDirty : spillClean;
|
||||
}
|
||||
}
|
||||
|
||||
for (MCRegUnitIterator UI(PhysReg, TRI); UI.isValid(); ++UI) {
|
||||
switch (unsigned VirtReg = RegUnitStates[*UI]) {
|
||||
// This is a disabled register, add up cost of aliases.
|
||||
LLVM_DEBUG(dbgs() << printReg(PhysReg, TRI) << " is disabled.\n");
|
||||
unsigned Cost = 0;
|
||||
for (MCRegAliasIterator AI(PhysReg, TRI, false); AI.isValid(); ++AI) {
|
||||
MCPhysReg Alias = *AI;
|
||||
switch (Register VirtReg = PhysRegState[Alias]) {
|
||||
case regDisabled:
|
||||
break;
|
||||
case regFree:
|
||||
++Cost;
|
||||
break;
|
||||
case regReserved:
|
||||
LLVM_DEBUG(dbgs() << printReg(VirtReg, TRI) << " corresponding "
|
||||
<< printReg(PhysReg, TRI) << " is reserved already.\n");
|
||||
return spillImpossible;
|
||||
default: {
|
||||
LiveRegMap::const_iterator LRI = findLiveVirtReg(VirtReg);
|
||||
assert(LRI != LiveVirtRegs.end() && LRI->PhysReg &&
|
||||
"Missing VirtReg entry");
|
||||
return LRI->Dirty ? spillDirty : spillClean;
|
||||
Cost += LRI->Dirty ? spillDirty : spillClean;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// This method updates local state so that we know that PhysReg is the
|
||||
@ -845,17 +909,9 @@ void RegAllocFast::handleThroughOperands(MachineInstr &MI,
|
||||
if (!Reg || !Reg.isPhysical())
|
||||
continue;
|
||||
markRegUsedInInstr(Reg);
|
||||
|
||||
for (MCRegUnitIterator UI(Reg, TRI); UI.isValid(); ++UI) {
|
||||
if (!ThroughRegs.count(RegUnitStates[*UI]))
|
||||
continue;
|
||||
|
||||
// Need to spill any aliasing registers.
|
||||
for (MCRegUnitRootIterator RI(*UI, TRI); RI.isValid(); ++RI) {
|
||||
for (MCSuperRegIterator SI(*RI, TRI, true); SI.isValid(); ++SI) {
|
||||
definePhysReg(MI, *SI, regFree);
|
||||
}
|
||||
}
|
||||
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
|
||||
if (ThroughRegs.count(PhysRegState[*AI]))
|
||||
definePhysReg(MI, *AI, regFree);
|
||||
}
|
||||
}
|
||||
|
||||
@ -919,40 +975,37 @@ void RegAllocFast::handleThroughOperands(MachineInstr &MI,
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void RegAllocFast::dumpState() const {
|
||||
for (unsigned Unit = 1, UnitE = TRI->getNumRegUnits(); Unit != UnitE;
|
||||
++Unit) {
|
||||
switch (unsigned VirtReg = RegUnitStates[Unit]) {
|
||||
void RegAllocFast::dumpState() {
|
||||
for (unsigned Reg = 1, E = TRI->getNumRegs(); Reg != E; ++Reg) {
|
||||
if (PhysRegState[Reg] == regDisabled) continue;
|
||||
dbgs() << " " << printReg(Reg, TRI);
|
||||
switch(PhysRegState[Reg]) {
|
||||
case regFree:
|
||||
break;
|
||||
case regReserved:
|
||||
dbgs() << " " << printRegUnit(Unit, TRI) << "[P]";
|
||||
dbgs() << "*";
|
||||
break;
|
||||
default: {
|
||||
dbgs() << ' ' << printRegUnit(Unit, TRI) << '=' << printReg(VirtReg);
|
||||
LiveRegMap::const_iterator I = findLiveVirtReg(VirtReg);
|
||||
assert(I != LiveVirtRegs.end() && "have LiveVirtRegs entry");
|
||||
if (I->Dirty)
|
||||
dbgs() << "[D]";
|
||||
assert(TRI->hasRegUnit(I->PhysReg, Unit) && "inverse mapping present");
|
||||
dbgs() << '=' << printReg(PhysRegState[Reg]);
|
||||
LiveRegMap::iterator LRI = findLiveVirtReg(PhysRegState[Reg]);
|
||||
assert(LRI != LiveVirtRegs.end() && LRI->PhysReg &&
|
||||
"Missing VirtReg entry");
|
||||
if (LRI->Dirty)
|
||||
dbgs() << "*";
|
||||
assert(LRI->PhysReg == Reg && "Bad inverse map");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbgs() << '\n';
|
||||
// Check that LiveVirtRegs is the inverse.
|
||||
for (const LiveReg &LR : LiveVirtRegs) {
|
||||
Register VirtReg = LR.VirtReg;
|
||||
assert(VirtReg.isVirtual() && "Bad map key");
|
||||
MCPhysReg PhysReg = LR.PhysReg;
|
||||
if (PhysReg != 0) {
|
||||
assert(Register::isPhysicalRegister(PhysReg) &&
|
||||
"mapped to physreg");
|
||||
for (MCRegUnitIterator UI(PhysReg, TRI); UI.isValid(); ++UI) {
|
||||
assert(RegUnitStates[*UI] == VirtReg && "inverse map valid");
|
||||
}
|
||||
}
|
||||
for (LiveRegMap::iterator i = LiveVirtRegs.begin(),
|
||||
e = LiveVirtRegs.end(); i != e; ++i) {
|
||||
if (!i->PhysReg)
|
||||
continue;
|
||||
assert(i->VirtReg.isVirtual() && "Bad map key");
|
||||
assert(Register::isPhysicalRegister(i->PhysReg) && "Bad map value");
|
||||
assert(PhysRegState[i->PhysReg] == i->VirtReg && "Bad inverse map");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1194,7 +1247,7 @@ void RegAllocFast::allocateBasicBlock(MachineBasicBlock &MBB) {
|
||||
this->MBB = &MBB;
|
||||
LLVM_DEBUG(dbgs() << "\nAllocating " << MBB);
|
||||
|
||||
RegUnitStates.assign(TRI->getNumRegUnits(), regFree);
|
||||
PhysRegState.assign(TRI->getNumRegs(), regDisabled);
|
||||
assert(LiveVirtRegs.empty() && "Mapping not cleared from last block?");
|
||||
|
||||
MachineBasicBlock::iterator MII = MBB.begin();
|
||||
|
@ -690,6 +690,12 @@ bool FastISel::selectGetElementPtr(const User *I) {
|
||||
Register N = getRegForValue(I->getOperand(0));
|
||||
if (!N) // Unhandled operand. Halt "fast" selection and bail.
|
||||
return false;
|
||||
|
||||
// FIXME: The code below does not handle vector GEPs. Halt "fast" selection
|
||||
// and bail.
|
||||
if (isa<VectorType>(I->getType()))
|
||||
return false;
|
||||
|
||||
bool NIsKill = hasTrivialKill(I->getOperand(0));
|
||||
|
||||
// Keep a running tab of the total offset to coalesce multiple N = N + Offset
|
||||
|
@ -409,7 +409,7 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, const SDLoc &DL,
|
||||
// as appropriate.
|
||||
for (unsigned i = 0; i != NumParts; ++i)
|
||||
Ops[i] = getCopyFromParts(DAG, DL, &Parts[i], 1,
|
||||
PartVT, IntermediateVT, V);
|
||||
PartVT, IntermediateVT, V, CallConv);
|
||||
} else if (NumParts > 0) {
|
||||
// If the intermediate type was expanded, build the intermediate
|
||||
// operands from the parts.
|
||||
@ -418,7 +418,7 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, const SDLoc &DL,
|
||||
unsigned Factor = NumParts / NumIntermediates;
|
||||
for (unsigned i = 0; i != NumIntermediates; ++i)
|
||||
Ops[i] = getCopyFromParts(DAG, DL, &Parts[i * Factor], Factor,
|
||||
PartVT, IntermediateVT, V);
|
||||
PartVT, IntermediateVT, V, CallConv);
|
||||
}
|
||||
|
||||
// Build a vector with BUILD_VECTOR or CONCAT_VECTORS from the
|
||||
|
@ -5726,6 +5726,11 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG,
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
auto RemoveDeadNode = [&](SDValue N) {
|
||||
if (N && N.getNode()->use_empty())
|
||||
DAG.RemoveDeadNode(N.getNode());
|
||||
};
|
||||
|
||||
SDLoc DL(Op);
|
||||
|
||||
switch (Opcode) {
|
||||
@ -5804,13 +5809,17 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG,
|
||||
// Negate the X if its cost is less or equal than Y.
|
||||
if (NegX && (CostX <= CostY)) {
|
||||
Cost = CostX;
|
||||
return DAG.getNode(ISD::FSUB, DL, VT, NegX, Y, Flags);
|
||||
SDValue N = DAG.getNode(ISD::FSUB, DL, VT, NegX, Y, Flags);
|
||||
RemoveDeadNode(NegY);
|
||||
return N;
|
||||
}
|
||||
|
||||
// Negate the Y if it is not expensive.
|
||||
if (NegY) {
|
||||
Cost = CostY;
|
||||
return DAG.getNode(ISD::FSUB, DL, VT, NegY, X, Flags);
|
||||
SDValue N = DAG.getNode(ISD::FSUB, DL, VT, NegY, X, Flags);
|
||||
RemoveDeadNode(NegX);
|
||||
return N;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5847,7 +5856,9 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG,
|
||||
// Negate the X if its cost is less or equal than Y.
|
||||
if (NegX && (CostX <= CostY)) {
|
||||
Cost = CostX;
|
||||
return DAG.getNode(Opcode, DL, VT, NegX, Y, Flags);
|
||||
SDValue N = DAG.getNode(Opcode, DL, VT, NegX, Y, Flags);
|
||||
RemoveDeadNode(NegY);
|
||||
return N;
|
||||
}
|
||||
|
||||
// Ignore X * 2.0 because that is expected to be canonicalized to X + X.
|
||||
@ -5858,7 +5869,9 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG,
|
||||
// Negate the Y if it is not expensive.
|
||||
if (NegY) {
|
||||
Cost = CostY;
|
||||
return DAG.getNode(Opcode, DL, VT, X, NegY, Flags);
|
||||
SDValue N = DAG.getNode(Opcode, DL, VT, X, NegY, Flags);
|
||||
RemoveDeadNode(NegX);
|
||||
return N;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5887,13 +5900,17 @@ SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG,
|
||||
// Negate the X if its cost is less or equal than Y.
|
||||
if (NegX && (CostX <= CostY)) {
|
||||
Cost = std::min(CostX, CostZ);
|
||||
return DAG.getNode(Opcode, DL, VT, NegX, Y, NegZ, Flags);
|
||||
SDValue N = DAG.getNode(Opcode, DL, VT, NegX, Y, NegZ, Flags);
|
||||
RemoveDeadNode(NegY);
|
||||
return N;
|
||||
}
|
||||
|
||||
// Negate the Y if it is not expensive.
|
||||
if (NegY) {
|
||||
Cost = std::min(CostY, CostZ);
|
||||
return DAG.getNode(Opcode, DL, VT, X, NegY, NegZ, Flags);
|
||||
SDValue N = DAG.getNode(Opcode, DL, VT, X, NegY, NegZ, Flags);
|
||||
RemoveDeadNode(NegX);
|
||||
return N;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1827,7 +1827,10 @@ Value *TargetLoweringBase::getIRStackGuard(IRBuilder<> &IRB) const {
|
||||
if (getTargetMachine().getTargetTriple().isOSOpenBSD()) {
|
||||
Module &M = *IRB.GetInsertBlock()->getParent()->getParent();
|
||||
PointerType *PtrTy = Type::getInt8PtrTy(M.getContext());
|
||||
return M.getOrInsertGlobal("__guard_local", PtrTy);
|
||||
Constant *C = M.getOrInsertGlobal("__guard_local", PtrTy);
|
||||
if (GlobalVariable *G = dyn_cast_or_null<GlobalVariable>(C))
|
||||
G->setVisibility(GlobalValue::HiddenVisibility);
|
||||
return C;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -185,16 +185,18 @@ void OpenMPIRBuilder::finalize() {
|
||||
}
|
||||
|
||||
Value *OpenMPIRBuilder::getOrCreateIdent(Constant *SrcLocStr,
|
||||
IdentFlag LocFlags) {
|
||||
IdentFlag LocFlags,
|
||||
unsigned Reserve2Flags) {
|
||||
// Enable "C-mode".
|
||||
LocFlags |= OMP_IDENT_FLAG_KMPC;
|
||||
|
||||
GlobalVariable *&DefaultIdent = IdentMap[{SrcLocStr, uint64_t(LocFlags)}];
|
||||
if (!DefaultIdent) {
|
||||
Value *&Ident =
|
||||
IdentMap[{SrcLocStr, uint64_t(LocFlags) << 31 | Reserve2Flags}];
|
||||
if (!Ident) {
|
||||
Constant *I32Null = ConstantInt::getNullValue(Int32);
|
||||
Constant *IdentData[] = {I32Null,
|
||||
ConstantInt::get(Int32, uint64_t(LocFlags)),
|
||||
I32Null, I32Null, SrcLocStr};
|
||||
Constant *IdentData[] = {
|
||||
I32Null, ConstantInt::get(Int32, uint32_t(LocFlags)),
|
||||
ConstantInt::get(Int32, Reserve2Flags), I32Null, SrcLocStr};
|
||||
Constant *Initializer = ConstantStruct::get(
|
||||
cast<StructType>(IdentPtr->getPointerElementType()), IdentData);
|
||||
|
||||
@ -203,15 +205,16 @@ Value *OpenMPIRBuilder::getOrCreateIdent(Constant *SrcLocStr,
|
||||
for (GlobalVariable &GV : M.getGlobalList())
|
||||
if (GV.getType() == IdentPtr && GV.hasInitializer())
|
||||
if (GV.getInitializer() == Initializer)
|
||||
return DefaultIdent = &GV;
|
||||
return Ident = &GV;
|
||||
|
||||
DefaultIdent = new GlobalVariable(M, IdentPtr->getPointerElementType(),
|
||||
/* isConstant = */ false,
|
||||
GlobalValue::PrivateLinkage, Initializer);
|
||||
DefaultIdent->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
DefaultIdent->setAlignment(Align(8));
|
||||
auto *GV = new GlobalVariable(M, IdentPtr->getPointerElementType(),
|
||||
/* isConstant = */ true,
|
||||
GlobalValue::PrivateLinkage, Initializer);
|
||||
GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
GV->setAlignment(Align(8));
|
||||
Ident = GV;
|
||||
}
|
||||
return DefaultIdent;
|
||||
return Ident;
|
||||
}
|
||||
|
||||
Constant *OpenMPIRBuilder::getOrCreateSrcLocStr(StringRef LocStr) {
|
||||
@ -227,11 +230,30 @@ Constant *OpenMPIRBuilder::getOrCreateSrcLocStr(StringRef LocStr) {
|
||||
GV.getInitializer() == Initializer)
|
||||
return SrcLocStr = ConstantExpr::getPointerCast(&GV, Int8Ptr);
|
||||
|
||||
SrcLocStr = Builder.CreateGlobalStringPtr(LocStr);
|
||||
SrcLocStr = Builder.CreateGlobalStringPtr(LocStr, /* Name */ "",
|
||||
/* AddressSpace */ 0, &M);
|
||||
}
|
||||
return SrcLocStr;
|
||||
}
|
||||
|
||||
Constant *OpenMPIRBuilder::getOrCreateSrcLocStr(StringRef FunctionName,
|
||||
StringRef FileName,
|
||||
unsigned Line,
|
||||
unsigned Column) {
|
||||
SmallString<128> Buffer;
|
||||
Buffer.push_back(';');
|
||||
Buffer.append(FileName);
|
||||
Buffer.push_back(';');
|
||||
Buffer.append(FunctionName);
|
||||
Buffer.push_back(';');
|
||||
Buffer.append(std::to_string(Line));
|
||||
Buffer.push_back(';');
|
||||
Buffer.append(std::to_string(Column));
|
||||
Buffer.push_back(';');
|
||||
Buffer.push_back(';');
|
||||
return getOrCreateSrcLocStr(Buffer.str());
|
||||
}
|
||||
|
||||
Constant *OpenMPIRBuilder::getOrCreateDefaultSrcLocStr() {
|
||||
return getOrCreateSrcLocStr(";unknown;unknown;0;0;;");
|
||||
}
|
||||
@ -241,17 +263,13 @@ OpenMPIRBuilder::getOrCreateSrcLocStr(const LocationDescription &Loc) {
|
||||
DILocation *DIL = Loc.DL.get();
|
||||
if (!DIL)
|
||||
return getOrCreateDefaultSrcLocStr();
|
||||
StringRef Filename =
|
||||
StringRef FileName =
|
||||
!DIL->getFilename().empty() ? DIL->getFilename() : M.getName();
|
||||
StringRef Function = DIL->getScope()->getSubprogram()->getName();
|
||||
Function =
|
||||
!Function.empty() ? Function : Loc.IP.getBlock()->getParent()->getName();
|
||||
std::string LineStr = std::to_string(DIL->getLine());
|
||||
std::string ColumnStr = std::to_string(DIL->getColumn());
|
||||
std::stringstream SrcLocStr;
|
||||
SrcLocStr << ";" << Filename.data() << ";" << Function.data() << ";"
|
||||
<< LineStr << ";" << ColumnStr << ";;";
|
||||
return getOrCreateSrcLocStr(SrcLocStr.str());
|
||||
return getOrCreateSrcLocStr(Function, FileName, DIL->getLine(),
|
||||
DIL->getColumn());
|
||||
}
|
||||
|
||||
Value *OpenMPIRBuilder::getOrCreateThreadID(Value *Ident) {
|
||||
|
@ -42,13 +42,14 @@ using namespace llvm;
|
||||
/// created.
|
||||
GlobalVariable *IRBuilderBase::CreateGlobalString(StringRef Str,
|
||||
const Twine &Name,
|
||||
unsigned AddressSpace) {
|
||||
unsigned AddressSpace,
|
||||
Module *M) {
|
||||
Constant *StrConstant = ConstantDataArray::getString(Context, Str);
|
||||
Module &M = *BB->getParent()->getParent();
|
||||
auto *GV = new GlobalVariable(M, StrConstant->getType(), true,
|
||||
GlobalValue::PrivateLinkage, StrConstant, Name,
|
||||
nullptr, GlobalVariable::NotThreadLocal,
|
||||
AddressSpace);
|
||||
if (!M)
|
||||
M = BB->getParent()->getParent();
|
||||
auto *GV = new GlobalVariable(
|
||||
*M, StrConstant->getType(), true, GlobalValue::PrivateLinkage,
|
||||
StrConstant, Name, nullptr, GlobalVariable::NotThreadLocal, AddressSpace);
|
||||
GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
GV->setAlignment(Align(1));
|
||||
return GV;
|
||||
|
@ -1475,74 +1475,6 @@ void FPPassManager::dumpPassStructure(unsigned Offset) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
namespace {
|
||||
namespace details {
|
||||
|
||||
// Basic hashing mechanism to detect structural change to the IR, used to verify
|
||||
// pass return status consistency with actual change. Loosely copied from
|
||||
// llvm/lib/Transforms/Utils/FunctionComparator.cpp
|
||||
|
||||
class StructuralHash {
|
||||
uint64_t Hash = 0x6acaa36bef8325c5ULL;
|
||||
|
||||
void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); }
|
||||
|
||||
public:
|
||||
StructuralHash() = default;
|
||||
|
||||
void update(Function &F) {
|
||||
if (F.empty())
|
||||
return;
|
||||
|
||||
update(F.isVarArg());
|
||||
update(F.arg_size());
|
||||
|
||||
SmallVector<const BasicBlock *, 8> BBs;
|
||||
SmallPtrSet<const BasicBlock *, 16> VisitedBBs;
|
||||
|
||||
BBs.push_back(&F.getEntryBlock());
|
||||
VisitedBBs.insert(BBs[0]);
|
||||
while (!BBs.empty()) {
|
||||
const BasicBlock *BB = BBs.pop_back_val();
|
||||
update(45798); // Block header
|
||||
for (auto &Inst : *BB)
|
||||
update(Inst.getOpcode());
|
||||
|
||||
const Instruction *Term = BB->getTerminator();
|
||||
for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
|
||||
if (!VisitedBBs.insert(Term->getSuccessor(i)).second)
|
||||
continue;
|
||||
BBs.push_back(Term->getSuccessor(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update(Module &M) {
|
||||
for (Function &F : M)
|
||||
update(F);
|
||||
}
|
||||
|
||||
uint64_t getHash() const { return Hash; }
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
uint64_t StructuralHash(Function &F) {
|
||||
details::StructuralHash H;
|
||||
H.update(F);
|
||||
return H.getHash();
|
||||
}
|
||||
|
||||
uint64_t StructuralHash(Module &M) {
|
||||
details::StructuralHash H;
|
||||
H.update(M);
|
||||
return H.getHash();
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
#endif
|
||||
|
||||
/// Execute all of the passes scheduled for execution by invoking
|
||||
/// runOnFunction method. Keep track of whether any of the passes modifies
|
||||
@ -1581,16 +1513,7 @@ bool FPPassManager::runOnFunction(Function &F) {
|
||||
{
|
||||
PassManagerPrettyStackEntry X(FP, F);
|
||||
TimeRegion PassTimer(getPassTimer(FP));
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
uint64_t RefHash = StructuralHash(F);
|
||||
#endif
|
||||
LocalChanged |= FP->runOnFunction(F);
|
||||
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
assert((LocalChanged || (RefHash == StructuralHash(F))) &&
|
||||
"Pass modifies its input and doesn't report it.");
|
||||
#endif
|
||||
|
||||
if (EmitICRemark) {
|
||||
unsigned NewSize = F.getInstructionCount();
|
||||
|
||||
@ -1691,17 +1614,7 @@ MPPassManager::runOnModule(Module &M) {
|
||||
PassManagerPrettyStackEntry X(MP, M);
|
||||
TimeRegion PassTimer(getPassTimer(MP));
|
||||
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
uint64_t RefHash = StructuralHash(M);
|
||||
#endif
|
||||
|
||||
LocalChanged |= MP->runOnModule(M);
|
||||
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
assert((LocalChanged || (RefHash == StructuralHash(M))) &&
|
||||
"Pass modifies its input and doesn't report it.");
|
||||
#endif
|
||||
|
||||
if (EmitICRemark) {
|
||||
// Update the size of the module.
|
||||
unsigned ModuleCount = M.getInstructionCount();
|
||||
|
@ -522,7 +522,7 @@ static constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {};
|
||||
static constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {};
|
||||
|
||||
// SSE4_A->FMA4->XOP chain.
|
||||
static constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSSE3;
|
||||
static constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSE3;
|
||||
static constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A;
|
||||
static constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4;
|
||||
|
||||
|
@ -1694,11 +1694,10 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize;
|
||||
MachineBasicBlock::iterator RestoreBegin = LastPopI, RestoreEnd = LastPopI;
|
||||
if (int64_t CalleeSavedSize = AFI->getSVECalleeSavedStackSize()) {
|
||||
RestoreBegin = std::prev(RestoreEnd);;
|
||||
while (IsSVECalleeSave(RestoreBegin) &&
|
||||
RestoreBegin != MBB.begin())
|
||||
RestoreBegin = std::prev(RestoreEnd);
|
||||
while (RestoreBegin != MBB.begin() &&
|
||||
IsSVECalleeSave(std::prev(RestoreBegin)))
|
||||
--RestoreBegin;
|
||||
++RestoreBegin;
|
||||
|
||||
assert(IsSVECalleeSave(RestoreBegin) &&
|
||||
IsSVECalleeSave(std::prev(RestoreEnd)) && "Unexpected instruction");
|
||||
|
@ -5416,7 +5416,7 @@ multiclass sve_mem_64b_sst_vi_ptrs<bits<3> opc, string asm,
|
||||
def : InstAlias<asm # "\t$Zt, $Pg, [$Zn, $imm5]",
|
||||
(!cast<Instruction>(NAME # _IMM) ZPR64:$Zt, PPR3bAny:$Pg, ZPR64:$Zn, imm_ty:$imm5), 0>;
|
||||
def : InstAlias<asm # "\t$Zt, $Pg, [$Zn]",
|
||||
(!cast<Instruction>(NAME # _IMM) Z_s:$Zt, PPR3bAny:$Pg, ZPR64:$Zn, 0), 1>;
|
||||
(!cast<Instruction>(NAME # _IMM) Z_d:$Zt, PPR3bAny:$Pg, ZPR64:$Zn, 0), 1>;
|
||||
|
||||
def : Pat<(op (nxv2i64 ZPR:$data), (nxv2i1 PPR:$gp), (nxv2i64 ZPR:$ptrs), imm_ty:$index, vt),
|
||||
(!cast<Instruction>(NAME # _IMM) ZPR:$data, PPR:$gp, ZPR:$ptrs, imm_ty:$index)>;
|
||||
|
@ -192,8 +192,8 @@ static bool updateOperand(FoldCandidate &Fold,
|
||||
if (Fold.isImm()) {
|
||||
if (MI->getDesc().TSFlags & SIInstrFlags::IsPacked &&
|
||||
!(MI->getDesc().TSFlags & SIInstrFlags::IsMAI) &&
|
||||
AMDGPU::isInlinableLiteralV216(static_cast<uint16_t>(Fold.ImmToFold),
|
||||
ST.hasInv2PiInlineImm())) {
|
||||
AMDGPU::isFoldableLiteralV216(Fold.ImmToFold,
|
||||
ST.hasInv2PiInlineImm())) {
|
||||
// Set op_sel/op_sel_hi on this operand or bail out if op_sel is
|
||||
// already set.
|
||||
unsigned Opcode = MI->getOpcode();
|
||||
@ -209,30 +209,30 @@ static bool updateOperand(FoldCandidate &Fold,
|
||||
ModIdx = AMDGPU::getNamedOperandIdx(Opcode, ModIdx);
|
||||
MachineOperand &Mod = MI->getOperand(ModIdx);
|
||||
unsigned Val = Mod.getImm();
|
||||
if ((Val & SISrcMods::OP_SEL_0) || !(Val & SISrcMods::OP_SEL_1))
|
||||
return false;
|
||||
// Only apply the following transformation if that operand requries
|
||||
// a packed immediate.
|
||||
switch (TII.get(Opcode).OpInfo[OpNo].OperandType) {
|
||||
case AMDGPU::OPERAND_REG_IMM_V2FP16:
|
||||
case AMDGPU::OPERAND_REG_IMM_V2INT16:
|
||||
case AMDGPU::OPERAND_REG_INLINE_C_V2FP16:
|
||||
case AMDGPU::OPERAND_REG_INLINE_C_V2INT16:
|
||||
// If upper part is all zero we do not need op_sel_hi.
|
||||
if (!isUInt<16>(Fold.ImmToFold)) {
|
||||
if (!(Fold.ImmToFold & 0xffff)) {
|
||||
Mod.setImm(Mod.getImm() | SISrcMods::OP_SEL_0);
|
||||
if (!(Val & SISrcMods::OP_SEL_0) && (Val & SISrcMods::OP_SEL_1)) {
|
||||
// Only apply the following transformation if that operand requries
|
||||
// a packed immediate.
|
||||
switch (TII.get(Opcode).OpInfo[OpNo].OperandType) {
|
||||
case AMDGPU::OPERAND_REG_IMM_V2FP16:
|
||||
case AMDGPU::OPERAND_REG_IMM_V2INT16:
|
||||
case AMDGPU::OPERAND_REG_INLINE_C_V2FP16:
|
||||
case AMDGPU::OPERAND_REG_INLINE_C_V2INT16:
|
||||
// If upper part is all zero we do not need op_sel_hi.
|
||||
if (!isUInt<16>(Fold.ImmToFold)) {
|
||||
if (!(Fold.ImmToFold & 0xffff)) {
|
||||
Mod.setImm(Mod.getImm() | SISrcMods::OP_SEL_0);
|
||||
Mod.setImm(Mod.getImm() & ~SISrcMods::OP_SEL_1);
|
||||
Old.ChangeToImmediate((Fold.ImmToFold >> 16) & 0xffff);
|
||||
return true;
|
||||
}
|
||||
Mod.setImm(Mod.getImm() & ~SISrcMods::OP_SEL_1);
|
||||
Old.ChangeToImmediate((Fold.ImmToFold >> 16) & 0xffff);
|
||||
Old.ChangeToImmediate(Fold.ImmToFold & 0xffff);
|
||||
return true;
|
||||
}
|
||||
Mod.setImm(Mod.getImm() & ~SISrcMods::OP_SEL_1);
|
||||
Old.ChangeToImmediate(Fold.ImmToFold & 0xffff);
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1282,6 +1282,19 @@ bool isInlinableIntLiteralV216(int32_t Literal) {
|
||||
return Lo16 == Hi16 && isInlinableIntLiteral(Lo16);
|
||||
}
|
||||
|
||||
bool isFoldableLiteralV216(int32_t Literal, bool HasInv2Pi) {
|
||||
assert(HasInv2Pi);
|
||||
|
||||
int16_t Lo16 = static_cast<int16_t>(Literal);
|
||||
if (isInt<16>(Literal) || isUInt<16>(Literal))
|
||||
return true;
|
||||
|
||||
int16_t Hi16 = static_cast<int16_t>(Literal >> 16);
|
||||
if (!(Literal & 0xffff))
|
||||
return true;
|
||||
return Lo16 == Hi16;
|
||||
}
|
||||
|
||||
bool isArgPassedInSGPR(const Argument *A) {
|
||||
const Function *F = A->getParent();
|
||||
|
||||
|
@ -660,6 +660,9 @@ bool isInlinableLiteralV216(int32_t Literal, bool HasInv2Pi);
|
||||
LLVM_READNONE
|
||||
bool isInlinableIntLiteralV216(int32_t Literal);
|
||||
|
||||
LLVM_READNONE
|
||||
bool isFoldableLiteralV216(int32_t Literal, bool HasInv2Pi);
|
||||
|
||||
bool isArgPassedInSGPR(const Argument *Arg);
|
||||
|
||||
LLVM_READONLY
|
||||
|
@ -78,9 +78,9 @@ class PPCBoolRetToInt : public FunctionPass {
|
||||
Value *Curr = WorkList.back();
|
||||
WorkList.pop_back();
|
||||
auto *CurrUser = dyn_cast<User>(Curr);
|
||||
// Operands of CallInst are skipped because they may not be Bool type,
|
||||
// and their positions are defined by ABI.
|
||||
if (CurrUser && !isa<CallInst>(Curr))
|
||||
// Operands of CallInst/Constant are skipped because they may not be Bool
|
||||
// type. For CallInst, their positions are defined by ABI.
|
||||
if (CurrUser && !isa<CallInst>(Curr) && !isa<Constant>(Curr))
|
||||
for (auto &Op : CurrUser->operands())
|
||||
if (Defs.insert(Op).second)
|
||||
WorkList.push_back(Op);
|
||||
@ -90,6 +90,9 @@ class PPCBoolRetToInt : public FunctionPass {
|
||||
|
||||
// Translate a i1 value to an equivalent i32/i64 value:
|
||||
Value *translate(Value *V) {
|
||||
assert(V->getType() == Type::getInt1Ty(V->getContext()) &&
|
||||
"Expect an i1 value");
|
||||
|
||||
Type *IntTy = ST->isPPC64() ? Type::getInt64Ty(V->getContext())
|
||||
: Type::getInt32Ty(V->getContext());
|
||||
|
||||
@ -252,9 +255,9 @@ class PPCBoolRetToInt : public FunctionPass {
|
||||
auto *First = dyn_cast<User>(Pair.first);
|
||||
auto *Second = dyn_cast<User>(Pair.second);
|
||||
assert((!First || Second) && "translated from user to non-user!?");
|
||||
// Operands of CallInst are skipped because they may not be Bool type,
|
||||
// and their positions are defined by ABI.
|
||||
if (First && !isa<CallInst>(First))
|
||||
// Operands of CallInst/Constant are skipped because they may not be Bool
|
||||
// type. For CallInst, their positions are defined by ABI.
|
||||
if (First && !isa<CallInst>(First) && !isa<Constant>(First))
|
||||
for (unsigned i = 0; i < First->getNumOperands(); ++i)
|
||||
Second->setOperand(i, BoolToIntMap[First->getOperand(i)]);
|
||||
}
|
||||
|
@ -799,7 +799,7 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setOperationAction(ISD::MUL, MVT::v4f32, Legal);
|
||||
setOperationAction(ISD::FMA, MVT::v4f32, Legal);
|
||||
|
||||
if (TM.Options.UnsafeFPMath || Subtarget.hasVSX()) {
|
||||
if (Subtarget.hasVSX()) {
|
||||
setOperationAction(ISD::FDIV, MVT::v4f32, Legal);
|
||||
setOperationAction(ISD::FSQRT, MVT::v4f32, Legal);
|
||||
}
|
||||
@ -920,6 +920,8 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setOperationAction(ISD::SUB, MVT::v2i64, Expand);
|
||||
}
|
||||
|
||||
setOperationAction(ISD::SETCC, MVT::v1i128, Expand);
|
||||
|
||||
setOperationAction(ISD::LOAD, MVT::v2i64, Promote);
|
||||
AddPromotedToType (ISD::LOAD, MVT::v2i64, MVT::v2f64);
|
||||
setOperationAction(ISD::STORE, MVT::v2i64, Promote);
|
||||
@ -1258,6 +1260,9 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setLibcallName(RTLIB::SRA_I128, nullptr);
|
||||
}
|
||||
|
||||
if (!isPPC64)
|
||||
setMaxAtomicSizeInBitsSupported(32);
|
||||
|
||||
setStackPointerRegisterToSaveRestore(isPPC64 ? PPC::X1 : PPC::R1);
|
||||
|
||||
// We have target-specific dag combine patterns for the following nodes:
|
||||
@ -1295,12 +1300,6 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setTargetDAGCombine(ISD::SELECT_CC);
|
||||
}
|
||||
|
||||
// Use reciprocal estimates.
|
||||
if (TM.Options.UnsafeFPMath) {
|
||||
setTargetDAGCombine(ISD::FDIV);
|
||||
setTargetDAGCombine(ISD::FSQRT);
|
||||
}
|
||||
|
||||
if (Subtarget.hasP9Altivec()) {
|
||||
setTargetDAGCombine(ISD::ABS);
|
||||
setTargetDAGCombine(ISD::VSELECT);
|
||||
|
@ -1026,8 +1026,8 @@ def : InstAlias<"mfamr $Rx", (MFSPR8 g8rc:$Rx, 29)>;
|
||||
foreach SPRG = 0-3 in {
|
||||
def : InstAlias<"mfsprg $RT, "#SPRG, (MFSPR8 g8rc:$RT, !add(SPRG, 272))>;
|
||||
def : InstAlias<"mfsprg"#SPRG#" $RT", (MFSPR8 g8rc:$RT, !add(SPRG, 272))>;
|
||||
def : InstAlias<"mfsprg "#SPRG#", $RT", (MTSPR8 !add(SPRG, 272), g8rc:$RT)>;
|
||||
def : InstAlias<"mfsprg"#SPRG#" $RT", (MTSPR8 !add(SPRG, 272), g8rc:$RT)>;
|
||||
def : InstAlias<"mtsprg "#SPRG#", $RT", (MTSPR8 !add(SPRG, 272), g8rc:$RT)>;
|
||||
def : InstAlias<"mtsprg"#SPRG#" $RT", (MTSPR8 !add(SPRG, 272), g8rc:$RT)>;
|
||||
}
|
||||
|
||||
def : InstAlias<"mfasr $RT", (MFSPR8 g8rc:$RT, 280)>;
|
||||
|
@ -1555,6 +1555,8 @@ bool PPCMIPeephole::emitRLDICWhenLoweringJumpTables(MachineInstr &MI) {
|
||||
MI.getOperand(1).setReg(SrcMI->getOperand(1).getReg());
|
||||
MI.getOperand(2).setImm(NewSH);
|
||||
MI.getOperand(3).setImm(NewMB);
|
||||
MI.getOperand(1).setIsKill(SrcMI->getOperand(1).isKill());
|
||||
SrcMI->getOperand(1).setIsKill(false);
|
||||
|
||||
LLVM_DEBUG(dbgs() << "To: ");
|
||||
LLVM_DEBUG(MI.dump());
|
||||
|
@ -601,8 +601,8 @@ bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT,
|
||||
}
|
||||
|
||||
bool WebAssemblyTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
|
||||
MVT ExtT = ExtVal.getSimpleValueType();
|
||||
MVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getSimpleValueType(0);
|
||||
EVT ExtT = ExtVal.getValueType();
|
||||
EVT MemT = cast<LoadSDNode>(ExtVal->getOperand(0))->getValueType(0);
|
||||
return (ExtT == MVT::v8i16 && MemT == MVT::v8i8) ||
|
||||
(ExtT == MVT::v4i32 && MemT == MVT::v4i16) ||
|
||||
(ExtT == MVT::v2i64 && MemT == MVT::v2i32);
|
||||
|
@ -1148,22 +1148,6 @@ static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp,
|
||||
return &Sel;
|
||||
}
|
||||
|
||||
static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *ReplaceOp,
|
||||
const SimplifyQuery &Q) {
|
||||
// If this is a binary operator, try to simplify it with the replaced op
|
||||
// because we know Op and ReplaceOp are equivalant.
|
||||
// For example: V = X + 1, Op = X, ReplaceOp = 42
|
||||
// Simplifies as: add(42, 1) --> 43
|
||||
if (auto *BO = dyn_cast<BinaryOperator>(V)) {
|
||||
if (BO->getOperand(0) == Op)
|
||||
return SimplifyBinOp(BO->getOpcode(), ReplaceOp, BO->getOperand(1), Q);
|
||||
if (BO->getOperand(1) == Op)
|
||||
return SimplifyBinOp(BO->getOpcode(), BO->getOperand(0), ReplaceOp, Q);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// If we have a select with an equality comparison, then we know the value in
|
||||
/// one of the arms of the select. See if substituting this value into an arm
|
||||
/// and simplifying the result yields the same value as the other arm.
|
||||
@ -1190,20 +1174,45 @@ static Value *foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp,
|
||||
if (Cmp.getPredicate() == ICmpInst::ICMP_NE)
|
||||
std::swap(TrueVal, FalseVal);
|
||||
|
||||
auto *FalseInst = dyn_cast<Instruction>(FalseVal);
|
||||
if (!FalseInst)
|
||||
return nullptr;
|
||||
|
||||
// InstSimplify already performed this fold if it was possible subject to
|
||||
// current poison-generating flags. Try the transform again with
|
||||
// poison-generating flags temporarily dropped.
|
||||
bool WasNUW = false, WasNSW = false, WasExact = false;
|
||||
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(FalseVal)) {
|
||||
WasNUW = OBO->hasNoUnsignedWrap();
|
||||
WasNSW = OBO->hasNoSignedWrap();
|
||||
FalseInst->setHasNoUnsignedWrap(false);
|
||||
FalseInst->setHasNoSignedWrap(false);
|
||||
}
|
||||
if (auto *PEO = dyn_cast<PossiblyExactOperator>(FalseVal)) {
|
||||
WasExact = PEO->isExact();
|
||||
FalseInst->setIsExact(false);
|
||||
}
|
||||
|
||||
// Try each equivalence substitution possibility.
|
||||
// We have an 'EQ' comparison, so the select's false value will propagate.
|
||||
// Example:
|
||||
// (X == 42) ? 43 : (X + 1) --> (X == 42) ? (X + 1) : (X + 1) --> X + 1
|
||||
// (X == 42) ? (X + 1) : 43 --> (X == 42) ? (42 + 1) : 43 --> 43
|
||||
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
|
||||
if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q) == TrueVal ||
|
||||
simplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q) == TrueVal ||
|
||||
simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q) == FalseVal ||
|
||||
simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q) == FalseVal) {
|
||||
if (auto *FalseInst = dyn_cast<Instruction>(FalseVal))
|
||||
FalseInst->dropPoisonGeneratingFlags();
|
||||
if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q,
|
||||
/* AllowRefinement */ false) == TrueVal ||
|
||||
SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q,
|
||||
/* AllowRefinement */ false) == TrueVal) {
|
||||
return FalseVal;
|
||||
}
|
||||
|
||||
// Restore poison-generating flags if the transform did not apply.
|
||||
if (WasNUW)
|
||||
FalseInst->setHasNoUnsignedWrap();
|
||||
if (WasNSW)
|
||||
FalseInst->setHasNoSignedWrap();
|
||||
if (WasExact)
|
||||
FalseInst->setIsExact();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user