mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-01 08:27:59 +00:00
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
release/11.x llvmorg-11-init-20933-g3c1fca803bc.
This commit is contained in:
commit
590d96feea
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang1100-import/; revision=363743
@ -1440,6 +1440,10 @@ def fpch_instantiate_templates:
|
||||
def fno_pch_instantiate_templates:
|
||||
Flag <["-"], "fno-pch-instantiate-templates">,
|
||||
Group<f_Group>, Flags<[CC1Option]>;
|
||||
defm pch_codegen: OptInFFlag<"pch-codegen", "Generate ", "Do not generate ",
|
||||
"code for uses of this PCH that assumes an explicit object file will be built for the PCH">;
|
||||
defm pch_debuginfo: OptInFFlag<"pch-debuginfo", "Generate ", "Do not generate ",
|
||||
"debug info for types in an object file built from this PCH and do not generate them elsewhere">;
|
||||
|
||||
def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
|
||||
Flags<[DriverOption, CC1Option]>,
|
||||
|
@ -168,6 +168,11 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer {
|
||||
return TC;
|
||||
}
|
||||
|
||||
/// In the case of deeply invalid expressions, `getNextCorrection()` will
|
||||
/// never be called since the transform never makes progress. If we don't
|
||||
/// detect this we risk trying to correct typos forever.
|
||||
bool hasMadeAnyCorrectionProgress() const { return CurrentTCIndex != 0; }
|
||||
|
||||
/// Reset the consumer's position in the stream of viable corrections
|
||||
/// (i.e. getNextCorrection() will return each of the previously returned
|
||||
/// corrections in order before returning any new corrections).
|
||||
|
@ -9930,8 +9930,7 @@ namespace {
|
||||
const ConstantArrayType *CAT =
|
||||
Info.Ctx.getAsConstantArrayType(E->getType());
|
||||
if (!CAT) {
|
||||
if (const IncompleteArrayType *IAT =
|
||||
Info.Ctx.getAsIncompleteArrayType(E->getType())) {
|
||||
if (E->getType()->isIncompleteArrayType()) {
|
||||
// We can be asked to zero-initialize a flexible array member; this
|
||||
// is represented as an ImplicitValueInitExpr of incomplete array
|
||||
// type. In this case, the array has zero elements.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "RISCV.h"
|
||||
#include "clang/Basic/MacroBuilder.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::targets;
|
||||
@ -166,3 +167,23 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
|
||||
return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
|
||||
/*Is64Bit=*/false);
|
||||
}
|
||||
|
||||
void RISCV32TargetInfo::fillValidCPUList(
|
||||
SmallVectorImpl<StringRef> &Values) const {
|
||||
llvm::RISCV::fillValidCPUArchList(Values, false);
|
||||
}
|
||||
|
||||
bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
|
||||
return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
|
||||
/*Is64Bit=*/true);
|
||||
}
|
||||
|
||||
void RISCV64TargetInfo::fillValidCPUList(
|
||||
SmallVectorImpl<StringRef> &Values) const {
|
||||
llvm::RISCV::fillValidCPUArchList(Values, true);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace targets {
|
||||
// RISC-V Target
|
||||
class RISCVTargetInfo : public TargetInfo {
|
||||
protected:
|
||||
std::string ABI;
|
||||
std::string ABI, CPU;
|
||||
bool HasM;
|
||||
bool HasA;
|
||||
bool HasF;
|
||||
@ -44,6 +44,13 @@ class RISCVTargetInfo : public TargetInfo {
|
||||
WIntType = UnsignedInt;
|
||||
}
|
||||
|
||||
bool setCPU(const std::string &Name) override {
|
||||
if (!isValidCPUName(Name))
|
||||
return false;
|
||||
CPU = Name;
|
||||
return true;
|
||||
}
|
||||
|
||||
StringRef getABI() const override { return ABI; }
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const override;
|
||||
@ -97,6 +104,9 @@ class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isValidCPUName(StringRef Name) const override;
|
||||
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
|
||||
|
||||
void setMaxAtomicWidth() override {
|
||||
MaxAtomicPromoteWidth = 128;
|
||||
|
||||
@ -121,6 +131,9 @@ class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isValidCPUName(StringRef Name) const override;
|
||||
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
|
||||
|
||||
void setMaxAtomicWidth() override {
|
||||
MaxAtomicPromoteWidth = 128;
|
||||
|
||||
|
@ -886,8 +886,11 @@ void ReductionCodeGen::emitInitialization(
|
||||
SharedType, SharedAddresses[N].first.getBaseInfo(),
|
||||
CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType));
|
||||
if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
|
||||
if (DRD && DRD->getInitializer())
|
||||
(void)DefaultInit(CGF);
|
||||
emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
|
||||
} else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
|
||||
(void)DefaultInit(CGF);
|
||||
emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp,
|
||||
PrivateAddr, SharedLVal.getAddress(CGF),
|
||||
SharedLVal.getType());
|
||||
|
@ -4770,6 +4770,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
|
||||
const VarDecl *VD) {
|
||||
if (VD && VD->hasAttr<OMPAllocateDeclAttr>()) {
|
||||
const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
|
||||
auto AS = LangAS::Default;
|
||||
switch (A->getAllocatorType()) {
|
||||
// Use the default allocator here as by default local vars are
|
||||
// threadlocal.
|
||||
@ -4783,42 +4784,30 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
|
||||
case OMPAllocateDeclAttr::OMPUserDefinedMemAlloc:
|
||||
// TODO: implement aupport for user-defined allocators.
|
||||
return Address::invalid();
|
||||
case OMPAllocateDeclAttr::OMPConstMemAlloc: {
|
||||
llvm::Type *VarTy = CGF.ConvertTypeForMem(VD->getType());
|
||||
auto *GV = new llvm::GlobalVariable(
|
||||
CGM.getModule(), VarTy, /*isConstant=*/false,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
llvm::Constant::getNullValue(VarTy), VD->getName(),
|
||||
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
|
||||
CGM.getContext().getTargetAddressSpace(LangAS::cuda_constant));
|
||||
CharUnits Align = CGM.getContext().getDeclAlign(VD);
|
||||
GV->setAlignment(Align.getAsAlign());
|
||||
return Address(GV, Align);
|
||||
}
|
||||
case OMPAllocateDeclAttr::OMPPTeamMemAlloc: {
|
||||
llvm::Type *VarTy = CGF.ConvertTypeForMem(VD->getType());
|
||||
auto *GV = new llvm::GlobalVariable(
|
||||
CGM.getModule(), VarTy, /*isConstant=*/false,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
llvm::Constant::getNullValue(VarTy), VD->getName(),
|
||||
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
|
||||
CGM.getContext().getTargetAddressSpace(LangAS::cuda_shared));
|
||||
CharUnits Align = CGM.getContext().getDeclAlign(VD);
|
||||
GV->setAlignment(Align.getAsAlign());
|
||||
return Address(GV, Align);
|
||||
}
|
||||
case OMPAllocateDeclAttr::OMPConstMemAlloc:
|
||||
AS = LangAS::cuda_constant;
|
||||
break;
|
||||
case OMPAllocateDeclAttr::OMPPTeamMemAlloc:
|
||||
AS = LangAS::cuda_shared;
|
||||
break;
|
||||
case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
|
||||
case OMPAllocateDeclAttr::OMPCGroupMemAlloc: {
|
||||
llvm::Type *VarTy = CGF.ConvertTypeForMem(VD->getType());
|
||||
auto *GV = new llvm::GlobalVariable(
|
||||
CGM.getModule(), VarTy, /*isConstant=*/false,
|
||||
llvm::GlobalValue::InternalLinkage,
|
||||
llvm::Constant::getNullValue(VarTy), VD->getName());
|
||||
CharUnits Align = CGM.getContext().getDeclAlign(VD);
|
||||
GV->setAlignment(Align.getAsAlign());
|
||||
return Address(GV, Align);
|
||||
}
|
||||
case OMPAllocateDeclAttr::OMPCGroupMemAlloc:
|
||||
break;
|
||||
}
|
||||
llvm::Type *VarTy = CGF.ConvertTypeForMem(VD->getType());
|
||||
auto *GV = new llvm::GlobalVariable(
|
||||
CGM.getModule(), VarTy, /*isConstant=*/false,
|
||||
llvm::GlobalValue::InternalLinkage, llvm::Constant::getNullValue(VarTy),
|
||||
VD->getName(),
|
||||
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
|
||||
CGM.getContext().getTargetAddressSpace(AS));
|
||||
CharUnits Align = CGM.getContext().getDeclAlign(VD);
|
||||
GV->setAlignment(Align.getAsAlign());
|
||||
return Address(
|
||||
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
|
||||
GV, VarTy->getPointerTo(CGM.getContext().getTargetAddressSpace(
|
||||
VD->getType().getAddressSpace()))),
|
||||
Align);
|
||||
}
|
||||
|
||||
if (getDataSharingMode(CGM) != CGOpenMPRuntimeNVPTX::Generic)
|
||||
|
@ -2154,39 +2154,13 @@ void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue,
|
||||
SourceLocation AssumptionLoc,
|
||||
llvm::Value *Alignment,
|
||||
llvm::Value *OffsetValue) {
|
||||
if (Alignment->getType() != IntPtrTy)
|
||||
Alignment =
|
||||
Builder.CreateIntCast(Alignment, IntPtrTy, false, "casted.align");
|
||||
if (OffsetValue && OffsetValue->getType() != IntPtrTy)
|
||||
OffsetValue =
|
||||
Builder.CreateIntCast(OffsetValue, IntPtrTy, true, "casted.offset");
|
||||
llvm::Value *TheCheck = nullptr;
|
||||
if (SanOpts.has(SanitizerKind::Alignment)) {
|
||||
llvm::Value *PtrIntValue =
|
||||
Builder.CreatePtrToInt(PtrValue, IntPtrTy, "ptrint");
|
||||
|
||||
if (OffsetValue) {
|
||||
bool IsOffsetZero = false;
|
||||
if (const auto *CI = dyn_cast<llvm::ConstantInt>(OffsetValue))
|
||||
IsOffsetZero = CI->isZero();
|
||||
|
||||
if (!IsOffsetZero)
|
||||
PtrIntValue = Builder.CreateSub(PtrIntValue, OffsetValue, "offsetptr");
|
||||
}
|
||||
|
||||
llvm::Value *Zero = llvm::ConstantInt::get(IntPtrTy, 0);
|
||||
llvm::Value *Mask =
|
||||
Builder.CreateSub(Alignment, llvm::ConstantInt::get(IntPtrTy, 1));
|
||||
llvm::Value *MaskedPtr = Builder.CreateAnd(PtrIntValue, Mask, "maskedptr");
|
||||
TheCheck = Builder.CreateICmpEQ(MaskedPtr, Zero, "maskcond");
|
||||
}
|
||||
llvm::Value *TheCheck;
|
||||
llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
|
||||
CGM.getDataLayout(), PtrValue, Alignment, OffsetValue);
|
||||
|
||||
if (!SanOpts.has(SanitizerKind::Alignment))
|
||||
return;
|
||||
emitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
|
||||
OffsetValue, TheCheck, Assumption);
|
||||
CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
|
||||
if (SanOpts.has(SanitizerKind::Alignment)) {
|
||||
emitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, Alignment,
|
||||
OffsetValue, TheCheck, Assumption);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue,
|
||||
|
@ -446,6 +446,19 @@ static bool getArchFeatures(const Driver &D, StringRef MArch,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get features except standard extension feature
|
||||
void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple,
|
||||
const llvm::opt::ArgList &Args,
|
||||
const llvm::opt::Arg *A, StringRef Mcpu,
|
||||
std::vector<StringRef> &Features) {
|
||||
bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64);
|
||||
llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
|
||||
if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) ||
|
||||
!llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) {
|
||||
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
||||
}
|
||||
}
|
||||
|
||||
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
||||
const ArgList &Args,
|
||||
std::vector<StringRef> &Features) {
|
||||
@ -454,6 +467,11 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
||||
if (!getArchFeatures(D, MArch, Features, Args))
|
||||
return;
|
||||
|
||||
// If users give march and mcpu, get std extension feature from MArch
|
||||
// and other features (ex. mirco architecture feature) from mcpu
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
|
||||
getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
|
||||
|
||||
// Handle features corresponding to "-ffixed-X" options
|
||||
if (Args.hasArg(options::OPT_ffixed_x1))
|
||||
Features.push_back("+reserve-x1");
|
||||
@ -543,11 +561,9 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
|
||||
|
||||
// GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
|
||||
// configured using `--with-abi=`, then the logic for the default choice is
|
||||
// defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
|
||||
// deviate from GCC's default only on baremetal targets (UnknownOS) where
|
||||
// neither `-march` nor `-mabi` is specified.
|
||||
// defined in config.gcc. This function is based on the logic in GCC 9.2.0.
|
||||
//
|
||||
// The logic uses the following, in order:
|
||||
// The logic used in GCC 9.2.0 is the following, in order:
|
||||
// 1. Explicit choices using `--with-abi=`
|
||||
// 2. A default based on `--with-arch=`, if provided
|
||||
// 3. A default based on the target triple's arch
|
||||
@ -556,38 +572,40 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
|
||||
//
|
||||
// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
|
||||
// and `-mabi=` respectively instead.
|
||||
//
|
||||
// In order to make chosing logic more clear, Clang uses the following logic,
|
||||
// in order:
|
||||
// 1. Explicit choices using `-mabi=`
|
||||
// 2. A default based on the architecture as determined by getRISCVArch
|
||||
// 3. Choose a default based on the triple
|
||||
|
||||
// 1. If `-mabi=` is specified, use it.
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
|
||||
return A->getValue();
|
||||
|
||||
// 2. Choose a default based on `-march=`
|
||||
// 2. Choose a default based on the target architecture.
|
||||
//
|
||||
// rv32g | rv32*d -> ilp32d
|
||||
// rv32e -> ilp32e
|
||||
// rv32* -> ilp32
|
||||
// rv64g | rv64*d -> lp64d
|
||||
// rv64* -> lp64
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
|
||||
StringRef MArch = A->getValue();
|
||||
StringRef MArch = getRISCVArch(Args, Triple);
|
||||
|
||||
if (MArch.startswith_lower("rv32")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_lower("d") ||
|
||||
MArch.startswith_lower("rv32g"))
|
||||
return "ilp32d";
|
||||
else if (MArch.startswith_lower("rv32e"))
|
||||
return "ilp32e";
|
||||
else
|
||||
return "ilp32";
|
||||
} else if (MArch.startswith_lower("rv64")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_lower("d") ||
|
||||
MArch.startswith_lower("rv64g"))
|
||||
return "lp64d";
|
||||
else
|
||||
return "lp64";
|
||||
}
|
||||
if (MArch.startswith_lower("rv32")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv32g"))
|
||||
return "ilp32d";
|
||||
else if (MArch.startswith_lower("rv32e"))
|
||||
return "ilp32e";
|
||||
else
|
||||
return "ilp32";
|
||||
} else if (MArch.startswith_lower("rv64")) {
|
||||
// FIXME: parse `March` to find `D` extension properly
|
||||
if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv64g"))
|
||||
return "lp64d";
|
||||
else
|
||||
return "lp64";
|
||||
}
|
||||
|
||||
// 3. Choose a default based on the triple
|
||||
@ -617,10 +635,11 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
|
||||
// GCC's logic around choosing a default `-march=` is complex. If GCC is not
|
||||
// configured using `--with-arch=`, then the logic for the default choice is
|
||||
// defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
|
||||
// deviate from GCC's default only on baremetal targets (UnknownOS) where
|
||||
// neither `-march` nor `-mabi` is specified.
|
||||
// deviate from GCC's default on additional `-mcpu` option (GCC does not
|
||||
// support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
|
||||
// nor `-mabi` is specified.
|
||||
//
|
||||
// The logic uses the following, in order:
|
||||
// The logic used in GCC 9.2.0 is the following, in order:
|
||||
// 1. Explicit choices using `--with-arch=`
|
||||
// 2. A default based on `--with-abi=`, if provided
|
||||
// 3. A default based on the target triple's arch
|
||||
@ -630,6 +649,12 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
|
||||
// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
|
||||
// and `-mabi=` respectively instead.
|
||||
//
|
||||
// Clang uses the following logic, in order:
|
||||
// 1. Explicit choices using `-march=`
|
||||
// 2. Based on `-mcpu` if the target CPU has a default ISA string
|
||||
// 3. A default based on `-mabi`, if provided
|
||||
// 4. A default based on the target triple's arch
|
||||
//
|
||||
// Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
|
||||
// instead of `rv{XLEN}gc` though they are (currently) equivalent.
|
||||
|
||||
@ -637,7 +662,15 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
|
||||
return A->getValue();
|
||||
|
||||
// 2. Choose a default based on `-mabi=`
|
||||
// 2. Get march (isa string) based on `-mcpu=`
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
|
||||
StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue());
|
||||
// Bypass if target cpu's default march is empty.
|
||||
if (MArch != "")
|
||||
return MArch;
|
||||
}
|
||||
|
||||
// 3. Choose a default based on `-mabi=`
|
||||
//
|
||||
// ilp32e -> rv32e
|
||||
// ilp32 | ilp32f | ilp32d -> rv32imafdc
|
||||
@ -653,7 +686,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
|
||||
return "rv64imafdc";
|
||||
}
|
||||
|
||||
// 3. Choose a default based on the triple
|
||||
// 4. Choose a default based on the triple
|
||||
//
|
||||
// We deviate from GCC's defaults here:
|
||||
// - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
|
||||
|
@ -5627,6 +5627,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (Args.hasFlag(options::OPT_fpch_instantiate_templates,
|
||||
options::OPT_fno_pch_instantiate_templates, false))
|
||||
CmdArgs.push_back("-fpch-instantiate-templates");
|
||||
if (Args.hasFlag(options::OPT_fpch_codegen, options::OPT_fno_pch_codegen,
|
||||
false))
|
||||
CmdArgs.push_back("-fmodules-codegen");
|
||||
if (Args.hasFlag(options::OPT_fpch_debuginfo, options::OPT_fno_pch_debuginfo,
|
||||
false))
|
||||
CmdArgs.push_back("-fmodules-debuginfo");
|
||||
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
|
||||
options::OPT_fno_experimental_new_pass_manager);
|
||||
|
@ -333,6 +333,11 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T,
|
||||
|
||||
return TargetCPUName;
|
||||
}
|
||||
case llvm::Triple::riscv32:
|
||||
case llvm::Triple::riscv64:
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
|
||||
return A->getValue();
|
||||
return "";
|
||||
|
||||
case llvm::Triple::bpfel:
|
||||
case llvm::Triple::bpfeb:
|
||||
|
@ -141,7 +141,7 @@ bool types::isAcceptedByClang(ID Id) {
|
||||
case TY_CXXHeader: case TY_PP_CXXHeader:
|
||||
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
|
||||
case TY_CXXModule: case TY_PP_CXXModule:
|
||||
case TY_AST: case TY_ModuleFile:
|
||||
case TY_AST: case TY_ModuleFile: case TY_PCH:
|
||||
case TY_LLVM_IR: case TY_LLVM_BC:
|
||||
return true;
|
||||
}
|
||||
|
@ -2022,8 +2022,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||
// FIXME: Supporting '<lang>-header-cpp-output' would be useful.
|
||||
bool Preprocessed = XValue.consume_back("-cpp-output");
|
||||
bool ModuleMap = XValue.consume_back("-module-map");
|
||||
IsHeaderFile =
|
||||
!Preprocessed && !ModuleMap && XValue.consume_back("-header");
|
||||
IsHeaderFile = !Preprocessed && !ModuleMap &&
|
||||
XValue != "precompiled-header" &&
|
||||
XValue.consume_back("-header");
|
||||
|
||||
// Principal languages.
|
||||
DashX = llvm::StringSwitch<InputKind>(XValue)
|
||||
@ -2050,7 +2051,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||
DashX = llvm::StringSwitch<InputKind>(XValue)
|
||||
.Case("cpp-output", InputKind(Language::C).getPreprocessed())
|
||||
.Case("assembler-with-cpp", Language::Asm)
|
||||
.Cases("ast", "pcm",
|
||||
.Cases("ast", "pcm", "precompiled-header",
|
||||
InputKind(Language::Unknown, InputKind::Precompiled))
|
||||
.Case("ir", Language::LLVM_IR)
|
||||
.Default(Language::Unknown);
|
||||
|
@ -7977,19 +7977,26 @@ class TransformTypos : public TreeTransform<TransformTypos> {
|
||||
}
|
||||
}
|
||||
|
||||
/// If corrections for the first TypoExpr have been exhausted for a
|
||||
/// given combination of the other TypoExprs, retry those corrections against
|
||||
/// the next combination of substitutions for the other TypoExprs by advancing
|
||||
/// to the next potential correction of the second TypoExpr. For the second
|
||||
/// and subsequent TypoExprs, if its stream of corrections has been exhausted,
|
||||
/// the stream is reset and the next TypoExpr's stream is advanced by one (a
|
||||
/// TypoExpr's correction stream is advanced by removing the TypoExpr from the
|
||||
/// TransformCache). Returns true if there is still any untried combinations
|
||||
/// of corrections.
|
||||
/// Try to advance the typo correction state of the first unfinished TypoExpr.
|
||||
/// We allow advancement of the correction stream by removing it from the
|
||||
/// TransformCache which allows `TransformTypoExpr` to advance during the
|
||||
/// next transformation attempt.
|
||||
///
|
||||
/// Any substitution attempts for the previous TypoExprs (which must have been
|
||||
/// finished) will need to be retried since it's possible that they will now
|
||||
/// be invalid given the latest advancement.
|
||||
///
|
||||
/// We need to be sure that we're making progress - it's possible that the
|
||||
/// tree is so malformed that the transform never makes it to the
|
||||
/// `TransformTypoExpr`.
|
||||
///
|
||||
/// Returns true if there are any untried correction combinations.
|
||||
bool CheckAndAdvanceTypoExprCorrectionStreams() {
|
||||
for (auto TE : TypoExprs) {
|
||||
auto &State = SemaRef.getTypoExprState(TE);
|
||||
TransformCache.erase(TE);
|
||||
if (!State.Consumer->hasMadeAnyCorrectionProgress())
|
||||
return false;
|
||||
if (!State.Consumer->finished())
|
||||
return true;
|
||||
State.Consumer->resetCorrectionStream();
|
||||
|
@ -15153,6 +15153,7 @@ static bool actOnOMPReductionKindClause(
|
||||
auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
|
||||
auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
|
||||
if (DRD->getInitializer()) {
|
||||
S.ActOnUninitializedDecl(PrivateVD);
|
||||
Init = DRDRef;
|
||||
RHSVD->setInit(DRDRef);
|
||||
RHSVD->setInitStyle(VarDecl::CallInit);
|
||||
@ -15259,10 +15260,19 @@ static bool actOnOMPReductionKindClause(
|
||||
llvm_unreachable("Unexpected reduction operation");
|
||||
}
|
||||
}
|
||||
if (Init && DeclareReductionRef.isUnset())
|
||||
if (Init && DeclareReductionRef.isUnset()) {
|
||||
S.AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false);
|
||||
else if (!Init)
|
||||
// Store initializer for single element in private copy. Will be used
|
||||
// during codegen.
|
||||
PrivateVD->setInit(RHSVD->getInit());
|
||||
PrivateVD->setInitStyle(RHSVD->getInitStyle());
|
||||
} else if (!Init) {
|
||||
S.ActOnUninitializedDecl(RHSVD);
|
||||
// Store initializer for single element in private copy. Will be used
|
||||
// during codegen.
|
||||
PrivateVD->setInit(RHSVD->getInit());
|
||||
PrivateVD->setInitStyle(RHSVD->getInitStyle());
|
||||
}
|
||||
if (RHSVD->isInvalidDecl())
|
||||
continue;
|
||||
if (!RHSVD->hasInit() &&
|
||||
@ -15276,10 +15286,6 @@ static bool actOnOMPReductionKindClause(
|
||||
<< D;
|
||||
continue;
|
||||
}
|
||||
// Store initializer for single element in private copy. Will be used during
|
||||
// codegen.
|
||||
PrivateVD->setInit(RHSVD->getInit());
|
||||
PrivateVD->setInitStyle(RHSVD->getInitStyle());
|
||||
DeclRefExpr *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc);
|
||||
ExprResult ReductionOp;
|
||||
if (DeclareReductionRef.isUsable()) {
|
||||
|
@ -439,65 +439,61 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
|
||||
ExtractTagFromStack(stk, tag);
|
||||
}
|
||||
|
||||
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
|
||||
uptr addr_min, uptr addr_max) {
|
||||
bool equal_stack = false;
|
||||
static bool FindRacyStacks(const RacyStacks &hash) {
|
||||
for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
|
||||
if (hash == ctx->racy_stacks[i]) {
|
||||
VPrintf(2, "ThreadSanitizer: suppressing report as doubled (stack)\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2]) {
|
||||
if (!flags()->suppress_equal_stacks)
|
||||
return false;
|
||||
RacyStacks hash;
|
||||
bool equal_address = false;
|
||||
hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
|
||||
hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
|
||||
{
|
||||
ReadLock lock(&ctx->racy_mtx);
|
||||
if (FindRacyStacks(hash))
|
||||
return true;
|
||||
}
|
||||
Lock lock(&ctx->racy_mtx);
|
||||
if (FindRacyStacks(hash))
|
||||
return true;
|
||||
ctx->racy_stacks.PushBack(hash);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool FindRacyAddress(const RacyAddress &ra0) {
|
||||
for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
|
||||
RacyAddress ra2 = ctx->racy_addresses[i];
|
||||
uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
|
||||
uptr minend = min(ra0.addr_max, ra2.addr_max);
|
||||
if (maxbeg < minend) {
|
||||
VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
|
||||
if (!flags()->suppress_equal_addresses)
|
||||
return false;
|
||||
RacyAddress ra0 = {addr_min, addr_max};
|
||||
{
|
||||
ReadLock lock(&ctx->racy_mtx);
|
||||
if (flags()->suppress_equal_stacks) {
|
||||
hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
|
||||
hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
|
||||
for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
|
||||
if (hash == ctx->racy_stacks[i]) {
|
||||
VPrintf(2,
|
||||
"ThreadSanitizer: suppressing report as doubled (stack)\n");
|
||||
equal_stack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags()->suppress_equal_addresses) {
|
||||
for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) {
|
||||
RacyAddress ra2 = ctx->racy_addresses[i];
|
||||
uptr maxbeg = max(ra0.addr_min, ra2.addr_min);
|
||||
uptr minend = min(ra0.addr_max, ra2.addr_max);
|
||||
if (maxbeg < minend) {
|
||||
VPrintf(2, "ThreadSanitizer: suppressing report as doubled (addr)\n");
|
||||
equal_address = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FindRacyAddress(ra0))
|
||||
return true;
|
||||
}
|
||||
if (!equal_stack && !equal_address)
|
||||
return false;
|
||||
if (!equal_stack) {
|
||||
Lock lock(&ctx->racy_mtx);
|
||||
ctx->racy_stacks.PushBack(hash);
|
||||
}
|
||||
if (!equal_address) {
|
||||
Lock lock(&ctx->racy_mtx);
|
||||
ctx->racy_addresses.PushBack(ra0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
|
||||
uptr addr_min, uptr addr_max) {
|
||||
Lock lock(&ctx->racy_mtx);
|
||||
if (flags()->suppress_equal_stacks) {
|
||||
RacyStacks hash;
|
||||
hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
|
||||
hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
|
||||
ctx->racy_stacks.PushBack(hash);
|
||||
}
|
||||
if (flags()->suppress_equal_addresses) {
|
||||
RacyAddress ra0 = {addr_min, addr_max};
|
||||
ctx->racy_addresses.PushBack(ra0);
|
||||
}
|
||||
if (FindRacyAddress(ra0))
|
||||
return true;
|
||||
ctx->racy_addresses.PushBack(ra0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
|
||||
@ -618,6 +614,8 @@ void ReportRace(ThreadState *thr) {
|
||||
if (IsExpectedReport(addr_min, addr_max - addr_min))
|
||||
return;
|
||||
}
|
||||
if (HandleRacyAddress(thr, addr_min, addr_max))
|
||||
return;
|
||||
|
||||
ReportType typ = ReportTypeRace;
|
||||
if (thr->is_vptr_access && freed)
|
||||
@ -668,7 +666,7 @@ void ReportRace(ThreadState *thr) {
|
||||
if (IsFiredSuppression(ctx, typ, traces[1]))
|
||||
return;
|
||||
|
||||
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
|
||||
if (HandleRacyStacks(thr, traces))
|
||||
return;
|
||||
|
||||
// If any of the accesses has a tag, treat this as an "external" race.
|
||||
@ -711,7 +709,6 @@ void ReportRace(ThreadState *thr) {
|
||||
if (!OutputReport(thr, rep))
|
||||
return;
|
||||
|
||||
AddRacyStacks(thr, traces, addr_min, addr_max);
|
||||
}
|
||||
|
||||
void PrintCurrentStack(ThreadState *thr, uptr pc) {
|
||||
|
@ -136,12 +136,16 @@ getFileLine(const SectionChunk *c, uint32_t addr) {
|
||||
// of all references to that symbol from that file. If no debug information is
|
||||
// available, returns just the name of the file, else one string per actual
|
||||
// reference as described in the debug info.
|
||||
std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
|
||||
// Returns up to maxStrings string descriptions, along with the total number of
|
||||
// locations found.
|
||||
static std::pair<std::vector<std::string>, size_t>
|
||||
getSymbolLocations(ObjFile *file, uint32_t symIndex, size_t maxStrings) {
|
||||
struct Location {
|
||||
Symbol *sym;
|
||||
std::pair<StringRef, uint32_t> fileLine;
|
||||
};
|
||||
std::vector<Location> locations;
|
||||
size_t numLocations = 0;
|
||||
|
||||
for (Chunk *c : file->getChunks()) {
|
||||
auto *sc = dyn_cast<SectionChunk>(c);
|
||||
@ -150,6 +154,10 @@ std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
|
||||
for (const coff_relocation &r : sc->getRelocs()) {
|
||||
if (r.SymbolTableIndex != symIndex)
|
||||
continue;
|
||||
numLocations++;
|
||||
if (locations.size() >= maxStrings)
|
||||
continue;
|
||||
|
||||
Optional<std::pair<StringRef, uint32_t>> fileLine =
|
||||
getFileLine(sc, r.VirtualAddress);
|
||||
Symbol *sym = getSymbol(sc, r.VirtualAddress);
|
||||
@ -160,8 +168,12 @@ std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
if (locations.empty())
|
||||
return std::vector<std::string>({"\n>>> referenced by " + toString(file)});
|
||||
if (maxStrings == 0)
|
||||
return std::make_pair(std::vector<std::string>(), numLocations);
|
||||
|
||||
if (numLocations == 0)
|
||||
return std::make_pair(
|
||||
std::vector<std::string>{"\n>>> referenced by " + toString(file)}, 1);
|
||||
|
||||
std::vector<std::string> symbolLocations(locations.size());
|
||||
size_t i = 0;
|
||||
@ -175,17 +187,26 @@ std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
|
||||
if (loc.sym)
|
||||
os << ":(" << toString(*loc.sym) << ')';
|
||||
}
|
||||
return symbolLocations;
|
||||
return std::make_pair(symbolLocations, numLocations);
|
||||
}
|
||||
|
||||
std::vector<std::string> getSymbolLocations(InputFile *file,
|
||||
uint32_t symIndex) {
|
||||
std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
|
||||
return getSymbolLocations(file, symIndex, SIZE_MAX).first;
|
||||
}
|
||||
|
||||
static std::pair<std::vector<std::string>, size_t>
|
||||
getSymbolLocations(InputFile *file, uint32_t symIndex, size_t maxStrings) {
|
||||
if (auto *o = dyn_cast<ObjFile>(file))
|
||||
return getSymbolLocations(o, symIndex);
|
||||
if (auto *b = dyn_cast<BitcodeFile>(file))
|
||||
return getSymbolLocations(b);
|
||||
return getSymbolLocations(o, symIndex, maxStrings);
|
||||
if (auto *b = dyn_cast<BitcodeFile>(file)) {
|
||||
std::vector<std::string> symbolLocations = getSymbolLocations(b);
|
||||
size_t numLocations = symbolLocations.size();
|
||||
if (symbolLocations.size() > maxStrings)
|
||||
symbolLocations.resize(maxStrings);
|
||||
return std::make_pair(symbolLocations, numLocations);
|
||||
}
|
||||
llvm_unreachable("unsupported file type passed to getSymbolLocations");
|
||||
return {};
|
||||
return std::make_pair(std::vector<std::string>(), (size_t)0);
|
||||
}
|
||||
|
||||
// For an undefined symbol, stores all files referencing it and the index of
|
||||
@ -205,20 +226,21 @@ static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
|
||||
os << "undefined symbol: " << toString(*undefDiag.sym);
|
||||
|
||||
const size_t maxUndefReferences = 3;
|
||||
size_t i = 0, numRefs = 0;
|
||||
size_t numDisplayedRefs = 0, numRefs = 0;
|
||||
for (const UndefinedDiag::File &ref : undefDiag.files) {
|
||||
std::vector<std::string> symbolLocations =
|
||||
getSymbolLocations(ref.file, ref.symIndex);
|
||||
numRefs += symbolLocations.size();
|
||||
std::vector<std::string> symbolLocations;
|
||||
size_t totalLocations = 0;
|
||||
std::tie(symbolLocations, totalLocations) = getSymbolLocations(
|
||||
ref.file, ref.symIndex, maxUndefReferences - numDisplayedRefs);
|
||||
|
||||
numRefs += totalLocations;
|
||||
numDisplayedRefs += symbolLocations.size();
|
||||
for (const std::string &s : symbolLocations) {
|
||||
if (i >= maxUndefReferences)
|
||||
break;
|
||||
os << s;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i < numRefs)
|
||||
os << "\n>>> referenced " << numRefs - i << " more times";
|
||||
if (numDisplayedRefs < numRefs)
|
||||
os << "\n>>> referenced " << numRefs - numDisplayedRefs << " more times";
|
||||
errorOrWarn(os.str());
|
||||
}
|
||||
|
||||
|
@ -1036,18 +1036,20 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) {
|
||||
// FIXME: Rather than parsing the whole line table and then copying it over
|
||||
// into LLDB, we should explore using a callback to populate the line table
|
||||
// while we parse to reduce memory usage.
|
||||
std::unique_ptr<LineSequence> sequence =
|
||||
LineTable::CreateLineSequenceContainer();
|
||||
std::vector<std::unique_ptr<LineSequence>> sequences;
|
||||
for (auto &row : line_table->Rows) {
|
||||
LineTable::AppendLineEntryToSequence(
|
||||
sequence.get(), row.Address.Address, row.Line, row.Column, row.File,
|
||||
row.IsStmt, row.BasicBlock, row.PrologueEnd, row.EpilogueBegin,
|
||||
row.EndSequence);
|
||||
if (row.EndSequence) {
|
||||
sequences.push_back(std::move(sequence));
|
||||
sequence = LineTable::CreateLineSequenceContainer();
|
||||
// The Sequences view contains only valid line sequences. Don't iterate over
|
||||
// the Rows directly.
|
||||
for (const llvm::DWARFDebugLine::Sequence &seq : line_table->Sequences) {
|
||||
std::unique_ptr<LineSequence> sequence =
|
||||
LineTable::CreateLineSequenceContainer();
|
||||
for (unsigned idx = seq.FirstRowIndex; idx < seq.LastRowIndex; ++idx) {
|
||||
const llvm::DWARFDebugLine::Row &row = line_table->Rows[idx];
|
||||
LineTable::AppendLineEntryToSequence(
|
||||
sequence.get(), row.Address.Address, row.Line, row.Column, row.File,
|
||||
row.IsStmt, row.BasicBlock, row.PrologueEnd, row.EpilogueBegin,
|
||||
row.EndSequence);
|
||||
}
|
||||
sequences.push_back(std::move(sequence));
|
||||
}
|
||||
|
||||
std::unique_ptr<LineTable> line_table_up =
|
||||
|
@ -782,11 +782,7 @@ class IRBuilderBase {
|
||||
|
||||
/// Create an assume intrinsic call that allows the optimizer to
|
||||
/// assume that the provided condition will be true.
|
||||
///
|
||||
/// The optional argument \p OpBundles specifies operand bundles that are
|
||||
/// added to the call instruction.
|
||||
CallInst *CreateAssumption(Value *Cond,
|
||||
ArrayRef<OperandBundleDef> OpBundles = llvm::None);
|
||||
CallInst *CreateAssumption(Value *Cond);
|
||||
|
||||
/// Create a call to the experimental.gc.statepoint intrinsic to
|
||||
/// start a new statepoint sequence.
|
||||
@ -2506,11 +2502,13 @@ class IRBuilderBase {
|
||||
|
||||
private:
|
||||
/// Helper function that creates an assume intrinsic call that
|
||||
/// represents an alignment assumption on the provided pointer \p PtrValue
|
||||
/// with offset \p OffsetValue and alignment value \p AlignValue.
|
||||
/// represents an alignment assumption on the provided Ptr, Mask, Type
|
||||
/// and Offset. It may be sometimes useful to do some other logic
|
||||
/// based on this alignment check, thus it can be stored into 'TheCheck'.
|
||||
CallInst *CreateAlignmentAssumptionHelper(const DataLayout &DL,
|
||||
Value *PtrValue, Value *AlignValue,
|
||||
Value *OffsetValue);
|
||||
Value *PtrValue, Value *Mask,
|
||||
Type *IntPtrTy, Value *OffsetValue,
|
||||
Value **TheCheck);
|
||||
|
||||
public:
|
||||
/// Create an assume intrinsic call that represents an alignment
|
||||
@ -2519,9 +2517,13 @@ class IRBuilderBase {
|
||||
/// An optional offset can be provided, and if it is provided, the offset
|
||||
/// must be subtracted from the provided pointer to get the pointer with the
|
||||
/// specified alignment.
|
||||
///
|
||||
/// It may be sometimes useful to do some other logic
|
||||
/// based on this alignment check, thus it can be stored into 'TheCheck'.
|
||||
CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue,
|
||||
unsigned Alignment,
|
||||
Value *OffsetValue = nullptr);
|
||||
Value *OffsetValue = nullptr,
|
||||
Value **TheCheck = nullptr);
|
||||
|
||||
/// Create an assume intrinsic call that represents an alignment
|
||||
/// assumption on the provided pointer.
|
||||
@ -2530,11 +2532,15 @@ class IRBuilderBase {
|
||||
/// must be subtracted from the provided pointer to get the pointer with the
|
||||
/// specified alignment.
|
||||
///
|
||||
/// It may be sometimes useful to do some other logic
|
||||
/// based on this alignment check, thus it can be stored into 'TheCheck'.
|
||||
///
|
||||
/// This overload handles the condition where the Alignment is dependent
|
||||
/// on an existing value rather than a static value.
|
||||
CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue,
|
||||
Value *Alignment,
|
||||
Value *OffsetValue = nullptr);
|
||||
Value *OffsetValue = nullptr,
|
||||
Value **TheCheck = nullptr);
|
||||
};
|
||||
|
||||
/// This provides a uniform API for creating instructions and inserting
|
||||
|
@ -0,0 +1,13 @@
|
||||
#ifndef PROC
|
||||
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH)
|
||||
#endif
|
||||
|
||||
PROC(INVALID, {"invalid"}, FK_INVALID, {""})
|
||||
PROC(GENERIC_RV32, {"generic-rv32"}, FK_NONE, {""})
|
||||
PROC(GENERIC_RV64, {"generic-rv64"}, FK_64BIT, {""})
|
||||
PROC(ROCKET_RV32, {"rocket-rv32"}, FK_NONE, {""})
|
||||
PROC(ROCKET_RV64, {"rocket-rv64"}, FK_64BIT, {""})
|
||||
PROC(SIFIVE_E31, {"sifive-e31"}, FK_NONE, {"rv32imac"})
|
||||
PROC(SIFIVE_U54, {"sifive-u54"}, FK_64BIT, {"rv64gc"})
|
||||
|
||||
#undef PROC
|
@ -130,6 +130,32 @@ IsaVersion getIsaVersion(StringRef GPU);
|
||||
|
||||
} // namespace AMDGPU
|
||||
|
||||
namespace RISCV {
|
||||
|
||||
enum CPUKind : unsigned {
|
||||
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) CK_##ENUM,
|
||||
#include "RISCVTargetParser.def"
|
||||
};
|
||||
|
||||
enum FeatureKind : unsigned {
|
||||
FK_INVALID = 0,
|
||||
FK_NONE = 1,
|
||||
FK_STDEXTM = 1 << 2,
|
||||
FK_STDEXTA = 1 << 3,
|
||||
FK_STDEXTF = 1 << 4,
|
||||
FK_STDEXTD = 1 << 5,
|
||||
FK_STDEXTC = 1 << 6,
|
||||
FK_64BIT = 1 << 7,
|
||||
};
|
||||
|
||||
bool checkCPUKind(CPUKind Kind, bool IsRV64);
|
||||
CPUKind parseCPUKind(StringRef CPU);
|
||||
StringRef getMArchFromMcpu(StringRef CPU);
|
||||
void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64);
|
||||
bool getCPUFeaturesExceptStdExt(CPUKind Kind, std::vector<StringRef> &Features);
|
||||
|
||||
} // namespace RISCV
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -37,9 +37,9 @@ struct AlignmentFromAssumptionsPass
|
||||
ScalarEvolution *SE = nullptr;
|
||||
DominatorTree *DT = nullptr;
|
||||
|
||||
bool extractAlignmentInfo(CallInst *I, unsigned Idx, Value *&AAPtr,
|
||||
const SCEV *&AlignSCEV, const SCEV *&OffSCEV);
|
||||
bool processAssumption(CallInst *I, unsigned Idx);
|
||||
bool extractAlignmentInfo(CallInst *I, Value *&AAPtr, const SCEV *&AlignSCEV,
|
||||
const SCEV *&OffSCEV);
|
||||
bool processAssumption(CallInst *I);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -108,17 +108,10 @@ llvm::getKnowledgeFromBundle(CallInst &Assume,
|
||||
Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
|
||||
if (bundleHasArgument(BOI, ABA_WasOn))
|
||||
Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
|
||||
auto GetArgOr1 = [&](unsigned Idx) -> unsigned {
|
||||
if (auto *ConstInt = dyn_cast<ConstantInt>(
|
||||
getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
|
||||
return ConstInt->getZExtValue();
|
||||
return 1;
|
||||
};
|
||||
if (BOI.End - BOI.Begin > ABA_Argument)
|
||||
Result.ArgValue = GetArgOr1(0);
|
||||
if (Result.AttrKind == Attribute::Alignment)
|
||||
if (BOI.End - BOI.Begin > ABA_Argument + 1)
|
||||
Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
|
||||
Result.ArgValue =
|
||||
cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
|
||||
->getZExtValue();
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -342,8 +342,12 @@ Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
|
||||
// pointers legally).
|
||||
if (C->isNullValue() && !DestTy->isX86_MMXTy())
|
||||
return Constant::getNullValue(DestTy);
|
||||
if (C->isAllOnesValue() && !DestTy->isX86_MMXTy() &&
|
||||
!DestTy->isPtrOrPtrVectorTy()) // Don't get ones for ptr types!
|
||||
if (C->isAllOnesValue() &&
|
||||
(DestTy->isIntegerTy() || DestTy->isFloatingPointTy() ||
|
||||
DestTy->isVectorTy()) &&
|
||||
!DestTy->isX86_MMXTy() && !DestTy->isPtrOrPtrVectorTy())
|
||||
// Get ones when the input is trivial, but
|
||||
// only for supported types inside getAllOnesValue.
|
||||
return Constant::getAllOnesValue(DestTy);
|
||||
|
||||
// If the type sizes are the same and a cast is legal, just directly
|
||||
|
@ -4118,15 +4118,9 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
if (TrueVal == FalseVal)
|
||||
return TrueVal;
|
||||
|
||||
// If the true or false value is undef, we can fold to the other value as
|
||||
// long as the other value isn't poison.
|
||||
// select ?, undef, X -> X
|
||||
if (isa<UndefValue>(TrueVal) &&
|
||||
isGuaranteedNotToBeUndefOrPoison(FalseVal, Q.CxtI, Q.DT))
|
||||
if (isa<UndefValue>(TrueVal)) // select ?, undef, X -> X
|
||||
return FalseVal;
|
||||
// select ?, X, undef -> X
|
||||
if (isa<UndefValue>(FalseVal) &&
|
||||
isGuaranteedNotToBeUndefOrPoison(TrueVal, Q.CxtI, Q.DT))
|
||||
if (isa<UndefValue>(FalseVal)) // select ?, X, undef -> X
|
||||
return TrueVal;
|
||||
|
||||
// Deal with partial undef vector constants: select ?, VecC, VecC' --> VecC''
|
||||
@ -4146,11 +4140,9 @@ static Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
// one element is undef, choose the defined element as the safe result.
|
||||
if (TEltC == FEltC)
|
||||
NewC.push_back(TEltC);
|
||||
else if (isa<UndefValue>(TEltC) &&
|
||||
isGuaranteedNotToBeUndefOrPoison(FEltC))
|
||||
else if (isa<UndefValue>(TEltC))
|
||||
NewC.push_back(FEltC);
|
||||
else if (isa<UndefValue>(FEltC) &&
|
||||
isGuaranteedNotToBeUndefOrPoison(TEltC))
|
||||
else if (isa<UndefValue>(FEltC))
|
||||
NewC.push_back(TEltC);
|
||||
else
|
||||
break;
|
||||
|
@ -3317,10 +3317,7 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
|
||||
}
|
||||
|
||||
// Add the total offset from all the GEP indices to the base.
|
||||
auto *GEPExpr = getAddExpr(BaseExpr, TotalOffset, Wrap);
|
||||
assert(BaseExpr->getType() == GEPExpr->getType() &&
|
||||
"GEP should not change type mid-flight.");
|
||||
return GEPExpr;
|
||||
return getAddExpr(BaseExpr, TotalOffset, Wrap);
|
||||
}
|
||||
|
||||
std::tuple<SCEV *, FoldingSetNodeID, void *>
|
||||
|
@ -70,7 +70,6 @@ STATISTIC(NumTwoAddressInstrs, "Number of two-address instructions");
|
||||
STATISTIC(NumCommuted , "Number of instructions commuted to coalesce");
|
||||
STATISTIC(NumAggrCommuted , "Number of instructions aggressively commuted");
|
||||
STATISTIC(NumConvertedTo3Addr, "Number of instructions promoted to 3-address");
|
||||
STATISTIC(Num3AddrSunk, "Number of 3-address instructions sunk");
|
||||
STATISTIC(NumReSchedUps, "Number of instructions re-scheduled up");
|
||||
STATISTIC(NumReSchedDowns, "Number of instructions re-scheduled down");
|
||||
|
||||
@ -109,10 +108,6 @@ class TwoAddressInstructionPass : public MachineFunctionPass {
|
||||
// Set of already processed instructions in the current block.
|
||||
SmallPtrSet<MachineInstr*, 8> Processed;
|
||||
|
||||
// Set of instructions converted to three-address by target and then sunk
|
||||
// down current basic block.
|
||||
SmallPtrSet<MachineInstr*, 8> SunkInstrs;
|
||||
|
||||
// A map from virtual registers to physical registers which are likely targets
|
||||
// to be coalesced to due to copies from physical registers to virtual
|
||||
// registers. e.g. v1024 = move r0.
|
||||
@ -123,9 +118,6 @@ class TwoAddressInstructionPass : public MachineFunctionPass {
|
||||
// registers. e.g. r1 = move v1024.
|
||||
DenseMap<unsigned, unsigned> DstRegMap;
|
||||
|
||||
bool sink3AddrInstruction(MachineInstr *MI, unsigned Reg,
|
||||
MachineBasicBlock::iterator OldPos);
|
||||
|
||||
bool isRevCopyChain(unsigned FromReg, unsigned ToReg, int Maxlen);
|
||||
|
||||
bool noUseAfterLastDef(unsigned Reg, unsigned Dist, unsigned &LastDef);
|
||||
@ -209,136 +201,6 @@ INITIALIZE_PASS_END(TwoAddressInstructionPass, DEBUG_TYPE,
|
||||
|
||||
static bool isPlainlyKilled(MachineInstr *MI, unsigned Reg, LiveIntervals *LIS);
|
||||
|
||||
/// A two-address instruction has been converted to a three-address instruction
|
||||
/// to avoid clobbering a register. Try to sink it past the instruction that
|
||||
/// would kill the above mentioned register to reduce register pressure.
|
||||
bool TwoAddressInstructionPass::
|
||||
sink3AddrInstruction(MachineInstr *MI, unsigned SavedReg,
|
||||
MachineBasicBlock::iterator OldPos) {
|
||||
// FIXME: Shouldn't we be trying to do this before we three-addressify the
|
||||
// instruction? After this transformation is done, we no longer need
|
||||
// the instruction to be in three-address form.
|
||||
|
||||
// Check if it's safe to move this instruction.
|
||||
bool SeenStore = true; // Be conservative.
|
||||
if (!MI->isSafeToMove(AA, SeenStore))
|
||||
return false;
|
||||
|
||||
unsigned DefReg = 0;
|
||||
SmallSet<unsigned, 4> UseRegs;
|
||||
|
||||
for (const MachineOperand &MO : MI->operands()) {
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
Register MOReg = MO.getReg();
|
||||
if (!MOReg)
|
||||
continue;
|
||||
if (MO.isUse() && MOReg != SavedReg)
|
||||
UseRegs.insert(MO.getReg());
|
||||
if (!MO.isDef())
|
||||
continue;
|
||||
if (MO.isImplicit())
|
||||
// Don't try to move it if it implicitly defines a register.
|
||||
return false;
|
||||
if (DefReg)
|
||||
// For now, don't move any instructions that define multiple registers.
|
||||
return false;
|
||||
DefReg = MO.getReg();
|
||||
}
|
||||
|
||||
// Find the instruction that kills SavedReg.
|
||||
MachineInstr *KillMI = nullptr;
|
||||
if (LIS) {
|
||||
LiveInterval &LI = LIS->getInterval(SavedReg);
|
||||
assert(LI.end() != LI.begin() &&
|
||||
"Reg should not have empty live interval.");
|
||||
|
||||
SlotIndex MBBEndIdx = LIS->getMBBEndIdx(MBB).getPrevSlot();
|
||||
LiveInterval::const_iterator I = LI.find(MBBEndIdx);
|
||||
if (I != LI.end() && I->start < MBBEndIdx)
|
||||
return false;
|
||||
|
||||
--I;
|
||||
KillMI = LIS->getInstructionFromIndex(I->end);
|
||||
}
|
||||
if (!KillMI) {
|
||||
for (MachineOperand &UseMO : MRI->use_nodbg_operands(SavedReg)) {
|
||||
if (!UseMO.isKill())
|
||||
continue;
|
||||
KillMI = UseMO.getParent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we find the instruction that kills SavedReg, and it is in an
|
||||
// appropriate location, we can try to sink the current instruction
|
||||
// past it.
|
||||
if (!KillMI || KillMI->getParent() != MBB || KillMI == MI ||
|
||||
MachineBasicBlock::iterator(KillMI) == OldPos || KillMI->isTerminator())
|
||||
return false;
|
||||
|
||||
// If any of the definitions are used by another instruction between the
|
||||
// position and the kill use, then it's not safe to sink it.
|
||||
//
|
||||
// FIXME: This can be sped up if there is an easy way to query whether an
|
||||
// instruction is before or after another instruction. Then we can use
|
||||
// MachineRegisterInfo def / use instead.
|
||||
MachineOperand *KillMO = nullptr;
|
||||
MachineBasicBlock::iterator KillPos = KillMI;
|
||||
++KillPos;
|
||||
|
||||
unsigned NumVisited = 0;
|
||||
for (MachineInstr &OtherMI : make_range(std::next(OldPos), KillPos)) {
|
||||
// Debug instructions cannot be counted against the limit.
|
||||
if (OtherMI.isDebugInstr())
|
||||
continue;
|
||||
if (NumVisited > 30) // FIXME: Arbitrary limit to reduce compile time cost.
|
||||
return false;
|
||||
++NumVisited;
|
||||
for (unsigned i = 0, e = OtherMI.getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = OtherMI.getOperand(i);
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
Register MOReg = MO.getReg();
|
||||
if (!MOReg)
|
||||
continue;
|
||||
if (DefReg == MOReg)
|
||||
return false;
|
||||
|
||||
if (MO.isKill() || (LIS && isPlainlyKilled(&OtherMI, MOReg, LIS))) {
|
||||
if (&OtherMI == KillMI && MOReg == SavedReg)
|
||||
// Save the operand that kills the register. We want to unset the kill
|
||||
// marker if we can sink MI past it.
|
||||
KillMO = &MO;
|
||||
else if (UseRegs.count(MOReg))
|
||||
// One of the uses is killed before the destination.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(KillMO && "Didn't find kill");
|
||||
|
||||
if (!LIS) {
|
||||
// Update kill and LV information.
|
||||
KillMO->setIsKill(false);
|
||||
KillMO = MI->findRegisterUseOperand(SavedReg, false, TRI);
|
||||
KillMO->setIsKill(true);
|
||||
|
||||
if (LV)
|
||||
LV->replaceKillInstruction(SavedReg, *KillMI, *MI);
|
||||
}
|
||||
|
||||
// Move instruction to its destination.
|
||||
MBB->remove(MI);
|
||||
MBB->insert(KillPos, MI);
|
||||
|
||||
if (LIS)
|
||||
LIS->handleMove(*MI);
|
||||
|
||||
++Num3AddrSunk;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return the MachineInstr* if it is the single def of the Reg in current BB.
|
||||
static MachineInstr *getSingleDef(unsigned Reg, MachineBasicBlock *BB,
|
||||
const MachineRegisterInfo *MRI) {
|
||||
@ -740,26 +602,15 @@ TwoAddressInstructionPass::convertInstTo3Addr(MachineBasicBlock::iterator &mi,
|
||||
|
||||
LLVM_DEBUG(dbgs() << "2addr: CONVERTING 2-ADDR: " << *mi);
|
||||
LLVM_DEBUG(dbgs() << "2addr: TO 3-ADDR: " << *NewMI);
|
||||
bool Sunk = false;
|
||||
|
||||
if (LIS)
|
||||
LIS->ReplaceMachineInstrInMaps(*mi, *NewMI);
|
||||
|
||||
if (NewMI->findRegisterUseOperand(RegB, false, TRI))
|
||||
// FIXME: Temporary workaround. If the new instruction doesn't
|
||||
// uses RegB, convertToThreeAddress must have created more
|
||||
// then one instruction.
|
||||
Sunk = sink3AddrInstruction(NewMI, RegB, mi);
|
||||
|
||||
MBB->erase(mi); // Nuke the old inst.
|
||||
|
||||
if (!Sunk) {
|
||||
DistanceMap.insert(std::make_pair(NewMI, Dist));
|
||||
mi = NewMI;
|
||||
nmi = std::next(mi);
|
||||
}
|
||||
else
|
||||
SunkInstrs.insert(NewMI);
|
||||
DistanceMap.insert(std::make_pair(NewMI, Dist));
|
||||
mi = NewMI;
|
||||
nmi = std::next(mi);
|
||||
|
||||
// Update source and destination register maps.
|
||||
SrcRegMap.erase(RegA);
|
||||
@ -1700,13 +1551,11 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &Func) {
|
||||
SrcRegMap.clear();
|
||||
DstRegMap.clear();
|
||||
Processed.clear();
|
||||
SunkInstrs.clear();
|
||||
for (MachineBasicBlock::iterator mi = MBB->begin(), me = MBB->end();
|
||||
mi != me; ) {
|
||||
MachineBasicBlock::iterator nmi = std::next(mi);
|
||||
// Don't revisit an instruction previously converted by target. It may
|
||||
// contain undef register operands (%noreg), which are not handled.
|
||||
if (mi->isDebugInstr() || SunkInstrs.count(&*mi)) {
|
||||
// Skip debug instructions.
|
||||
if (mi->isDebugInstr()) {
|
||||
mi = nmi;
|
||||
continue;
|
||||
}
|
||||
|
@ -779,30 +779,10 @@ Constant *llvm::ConstantFoldSelectInstruction(Constant *Cond,
|
||||
if (isa<UndefValue>(V1)) return V1;
|
||||
return V2;
|
||||
}
|
||||
|
||||
if (isa<UndefValue>(V1)) return V2;
|
||||
if (isa<UndefValue>(V2)) return V1;
|
||||
if (V1 == V2) return V1;
|
||||
|
||||
// If the true or false value is undef, we can fold to the other value as
|
||||
// long as the other value isn't poison.
|
||||
auto NotPoison = [](Constant *C) {
|
||||
// TODO: We can analyze ConstExpr by opcode to determine if there is any
|
||||
// possibility of poison.
|
||||
if (isa<ConstantExpr>(C))
|
||||
return false;
|
||||
|
||||
if (isa<ConstantInt>(C) || isa<GlobalVariable>(C) || isa<ConstantFP>(C) ||
|
||||
isa<ConstantPointerNull>(C) || isa<Function>(C))
|
||||
return true;
|
||||
|
||||
if (C->getType()->isVectorTy())
|
||||
return !C->containsUndefElement() && !C->containsConstantExpression();
|
||||
|
||||
// TODO: Recursively analyze aggregates or other constants.
|
||||
return false;
|
||||
};
|
||||
if (isa<UndefValue>(V1) && NotPoison(V2)) return V2;
|
||||
if (isa<UndefValue>(V2) && NotPoison(V1)) return V1;
|
||||
|
||||
if (ConstantExpr *TrueVal = dyn_cast<ConstantExpr>(V1)) {
|
||||
if (TrueVal->getOpcode() == Instruction::Select)
|
||||
if (TrueVal->getOperand(0) == Cond)
|
||||
|
@ -71,9 +71,8 @@ Value *IRBuilderBase::getCastedInt8PtrValue(Value *Ptr) {
|
||||
static CallInst *createCallHelper(Function *Callee, ArrayRef<Value *> Ops,
|
||||
IRBuilderBase *Builder,
|
||||
const Twine &Name = "",
|
||||
Instruction *FMFSource = nullptr,
|
||||
ArrayRef<OperandBundleDef> OpBundles = {}) {
|
||||
CallInst *CI = Builder->CreateCall(Callee, Ops, OpBundles, Name);
|
||||
Instruction *FMFSource = nullptr) {
|
||||
CallInst *CI = Builder->CreateCall(Callee, Ops, Name);
|
||||
if (FMFSource)
|
||||
CI->copyFastMathFlags(FMFSource);
|
||||
return CI;
|
||||
@ -450,16 +449,14 @@ CallInst *IRBuilderBase::CreateInvariantStart(Value *Ptr, ConstantInt *Size) {
|
||||
return createCallHelper(TheFn, Ops, this);
|
||||
}
|
||||
|
||||
CallInst *
|
||||
IRBuilderBase::CreateAssumption(Value *Cond,
|
||||
ArrayRef<OperandBundleDef> OpBundles) {
|
||||
CallInst *IRBuilderBase::CreateAssumption(Value *Cond) {
|
||||
assert(Cond->getType() == getInt1Ty() &&
|
||||
"an assumption condition must be of type i1");
|
||||
|
||||
Value *Ops[] = { Cond };
|
||||
Module *M = BB->getParent()->getParent();
|
||||
Function *FnAssume = Intrinsic::getDeclaration(M, Intrinsic::assume);
|
||||
return createCallHelper(FnAssume, Ops, this, "", nullptr, OpBundles);
|
||||
return createCallHelper(FnAssume, Ops, this);
|
||||
}
|
||||
|
||||
/// Create a call to a Masked Load intrinsic.
|
||||
@ -1110,37 +1107,63 @@ Value *IRBuilderBase::CreatePreserveStructAccessIndex(
|
||||
return Fn;
|
||||
}
|
||||
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(const DataLayout &DL,
|
||||
Value *PtrValue,
|
||||
Value *AlignValue,
|
||||
Value *OffsetValue) {
|
||||
SmallVector<Value *, 4> Vals({PtrValue, AlignValue});
|
||||
if (OffsetValue)
|
||||
Vals.push_back(OffsetValue);
|
||||
OperandBundleDefT<Value *> AlignOpB("align", Vals);
|
||||
return CreateAssumption(ConstantInt::getTrue(getContext()), {AlignOpB});
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(
|
||||
const DataLayout &DL, Value *PtrValue, Value *Mask, Type *IntPtrTy,
|
||||
Value *OffsetValue, Value **TheCheck) {
|
||||
Value *PtrIntValue = CreatePtrToInt(PtrValue, IntPtrTy, "ptrint");
|
||||
|
||||
if (OffsetValue) {
|
||||
bool IsOffsetZero = false;
|
||||
if (const auto *CI = dyn_cast<ConstantInt>(OffsetValue))
|
||||
IsOffsetZero = CI->isZero();
|
||||
|
||||
if (!IsOffsetZero) {
|
||||
if (OffsetValue->getType() != IntPtrTy)
|
||||
OffsetValue = CreateIntCast(OffsetValue, IntPtrTy, /*isSigned*/ true,
|
||||
"offsetcast");
|
||||
PtrIntValue = CreateSub(PtrIntValue, OffsetValue, "offsetptr");
|
||||
}
|
||||
}
|
||||
|
||||
Value *Zero = ConstantInt::get(IntPtrTy, 0);
|
||||
Value *MaskedPtr = CreateAnd(PtrIntValue, Mask, "maskedptr");
|
||||
Value *InvCond = CreateICmpEQ(MaskedPtr, Zero, "maskcond");
|
||||
if (TheCheck)
|
||||
*TheCheck = InvCond;
|
||||
|
||||
return CreateAssumption(InvCond);
|
||||
}
|
||||
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL,
|
||||
Value *PtrValue,
|
||||
unsigned Alignment,
|
||||
Value *OffsetValue) {
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumption(
|
||||
const DataLayout &DL, Value *PtrValue, unsigned Alignment,
|
||||
Value *OffsetValue, Value **TheCheck) {
|
||||
assert(isa<PointerType>(PtrValue->getType()) &&
|
||||
"trying to create an alignment assumption on a non-pointer?");
|
||||
assert(Alignment != 0 && "Invalid Alignment");
|
||||
auto *PtrTy = cast<PointerType>(PtrValue->getType());
|
||||
Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace());
|
||||
Value *AlignValue = ConstantInt::get(IntPtrTy, Alignment);
|
||||
return CreateAlignmentAssumptionHelper(DL, PtrValue, AlignValue, OffsetValue);
|
||||
|
||||
Value *Mask = ConstantInt::get(IntPtrTy, Alignment - 1);
|
||||
return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy,
|
||||
OffsetValue, TheCheck);
|
||||
}
|
||||
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL,
|
||||
Value *PtrValue,
|
||||
Value *Alignment,
|
||||
Value *OffsetValue) {
|
||||
CallInst *IRBuilderBase::CreateAlignmentAssumption(
|
||||
const DataLayout &DL, Value *PtrValue, Value *Alignment,
|
||||
Value *OffsetValue, Value **TheCheck) {
|
||||
assert(isa<PointerType>(PtrValue->getType()) &&
|
||||
"trying to create an alignment assumption on a non-pointer?");
|
||||
return CreateAlignmentAssumptionHelper(DL, PtrValue, Alignment, OffsetValue);
|
||||
auto *PtrTy = cast<PointerType>(PtrValue->getType());
|
||||
Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace());
|
||||
|
||||
if (Alignment->getType() != IntPtrTy)
|
||||
Alignment = CreateIntCast(Alignment, IntPtrTy, /*isSigned*/ false,
|
||||
"alignmentcast");
|
||||
|
||||
Value *Mask = CreateSub(Alignment, ConstantInt::get(IntPtrTy, 1), "mask");
|
||||
|
||||
return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy,
|
||||
OffsetValue, TheCheck);
|
||||
}
|
||||
|
||||
IRBuilderDefaultInserter::~IRBuilderDefaultInserter() {}
|
||||
|
@ -4449,32 +4449,21 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
|
||||
Assert(Elem.Tag->getKey() == "ignore" ||
|
||||
Attribute::isExistingAttribute(Elem.Tag->getKey()),
|
||||
"tags must be valid attribute names");
|
||||
Assert(Elem.End - Elem.Begin <= 2, "to many arguments");
|
||||
Attribute::AttrKind Kind =
|
||||
Attribute::getAttrKindFromName(Elem.Tag->getKey());
|
||||
unsigned ArgCount = Elem.End - Elem.Begin;
|
||||
if (Kind == Attribute::Alignment) {
|
||||
Assert(ArgCount <= 3 && ArgCount >= 2,
|
||||
"alignment assumptions should have 2 or 3 arguments");
|
||||
Assert(Call.getOperand(Elem.Begin)->getType()->isPointerTy(),
|
||||
"first argument should be a pointer");
|
||||
Assert(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(),
|
||||
"second argument should be an integer");
|
||||
if (ArgCount == 3)
|
||||
Assert(Call.getOperand(Elem.Begin + 2)->getType()->isIntegerTy(),
|
||||
"third argument should be an integer if present");
|
||||
return;
|
||||
}
|
||||
Assert(ArgCount <= 2, "to many arguments");
|
||||
if (Kind == Attribute::None)
|
||||
break;
|
||||
if (Attribute::doesAttrKindHaveArgument(Kind)) {
|
||||
Assert(ArgCount == 2, "this attribute should have 2 arguments");
|
||||
Assert(Elem.End - Elem.Begin == 2,
|
||||
"this attribute should have 2 arguments");
|
||||
Assert(isa<ConstantInt>(Call.getOperand(Elem.Begin + 1)),
|
||||
"the second argument should be a constant integral value");
|
||||
} else if (isFuncOnlyAttr(Kind)) {
|
||||
Assert((ArgCount) == 0, "this attribute has no argument");
|
||||
Assert((Elem.End - Elem.Begin) == 0, "this attribute has no argument");
|
||||
} else if (!isFuncOrArgAttr(Kind)) {
|
||||
Assert((ArgCount) == 1, "this attribute should have one argument");
|
||||
Assert((Elem.End - Elem.Begin) == 1,
|
||||
"this attribute should have one argument");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -812,9 +812,6 @@ class MasmParser : public MCAsmParser {
|
||||
const StructInitializer &Initializer);
|
||||
|
||||
// User-defined types (structs, unions):
|
||||
bool emitStructValue(const StructInfo &Structure,
|
||||
const StructInitializer &Initializer,
|
||||
size_t InitialOffset = 0, size_t InitialField = 0);
|
||||
bool emitStructValues(const StructInfo &Structure);
|
||||
bool addStructField(StringRef Name, const StructInfo &Structure);
|
||||
bool parseDirectiveStructValue(const StructInfo &Structure,
|
||||
|
@ -62,6 +62,8 @@ static bool supportsAArch64(uint64_t Type) {
|
||||
switch (Type) {
|
||||
case ELF::R_AARCH64_ABS32:
|
||||
case ELF::R_AARCH64_ABS64:
|
||||
case ELF::R_AARCH64_PREL32:
|
||||
case ELF::R_AARCH64_PREL64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -74,6 +76,10 @@ static uint64_t resolveAArch64(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
return (S + getELFAddend(R)) & 0xFFFFFFFF;
|
||||
case ELF::R_AARCH64_ABS64:
|
||||
return S + getELFAddend(R);
|
||||
case ELF::R_AARCH64_PREL32:
|
||||
return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF;
|
||||
case ELF::R_AARCH64_PREL64:
|
||||
return S + getELFAddend(R) - R.getOffset();
|
||||
default:
|
||||
llvm_unreachable("Invalid relocation type");
|
||||
}
|
||||
@ -152,6 +158,8 @@ static bool supportsPPC64(uint64_t Type) {
|
||||
switch (Type) {
|
||||
case ELF::R_PPC64_ADDR32:
|
||||
case ELF::R_PPC64_ADDR64:
|
||||
case ELF::R_PPC64_REL32:
|
||||
case ELF::R_PPC64_REL64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -164,6 +172,10 @@ static uint64_t resolvePPC64(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
return (S + getELFAddend(R)) & 0xFFFFFFFF;
|
||||
case ELF::R_PPC64_ADDR64:
|
||||
return S + getELFAddend(R);
|
||||
case ELF::R_PPC64_REL32:
|
||||
return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF;
|
||||
case ELF::R_PPC64_REL64:
|
||||
return S + getELFAddend(R) - R.getOffset();
|
||||
default:
|
||||
llvm_unreachable("Invalid relocation type");
|
||||
}
|
||||
@ -259,12 +271,22 @@ static uint64_t resolveX86(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
}
|
||||
|
||||
static bool supportsPPC32(uint64_t Type) {
|
||||
return Type == ELF::R_PPC_ADDR32;
|
||||
switch (Type) {
|
||||
case ELF::R_PPC_ADDR32:
|
||||
case ELF::R_PPC_REL32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t resolvePPC32(RelocationRef R, uint64_t S, uint64_t A) {
|
||||
if (R.getType() == ELF::R_PPC_ADDR32)
|
||||
switch (R.getType()) {
|
||||
case ELF::R_PPC_ADDR32:
|
||||
return (S + getELFAddend(R)) & 0xFFFFFFFF;
|
||||
case ELF::R_PPC_REL32:
|
||||
return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF;
|
||||
}
|
||||
llvm_unreachable("Invalid relocation type");
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/ARMBuildAttributes.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/ARMBuildAttributes.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace AMDGPU;
|
||||
@ -208,3 +209,64 @@ AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) {
|
||||
default: return {0, 0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace RISCV {
|
||||
|
||||
struct CPUInfo {
|
||||
StringLiteral Name;
|
||||
CPUKind Kind;
|
||||
unsigned Features;
|
||||
StringLiteral DefaultMarch;
|
||||
bool is64Bit() const { return (Features & FK_64BIT); }
|
||||
};
|
||||
|
||||
constexpr CPUInfo RISCVCPUInfo[] = {
|
||||
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) \
|
||||
{NAME, CK_##ENUM, FEATURES, DEFAULT_MARCH},
|
||||
#include "llvm/Support/RISCVTargetParser.def"
|
||||
};
|
||||
|
||||
bool checkCPUKind(CPUKind Kind, bool IsRV64) {
|
||||
if (Kind == CK_INVALID)
|
||||
return false;
|
||||
return RISCVCPUInfo[static_cast<unsigned>(Kind)].is64Bit() == IsRV64;
|
||||
}
|
||||
|
||||
CPUKind parseCPUKind(StringRef CPU) {
|
||||
return llvm::StringSwitch<CPUKind>(CPU)
|
||||
#define PROC(ENUM, NAME, FEATURES, DEFAULT_MARCH) .Case(NAME, CK_##ENUM)
|
||||
#include "llvm/Support/RISCVTargetParser.def"
|
||||
.Default(CK_INVALID);
|
||||
}
|
||||
|
||||
StringRef getMArchFromMcpu(StringRef CPU) {
|
||||
CPUKind Kind = parseCPUKind(CPU);
|
||||
return RISCVCPUInfo[static_cast<unsigned>(Kind)].DefaultMarch;
|
||||
}
|
||||
|
||||
void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
|
||||
for (const auto &C : RISCVCPUInfo) {
|
||||
if (C.Kind != CK_INVALID && IsRV64 == C.is64Bit())
|
||||
Values.emplace_back(C.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Get all features except standard extension feature
|
||||
bool getCPUFeaturesExceptStdExt(CPUKind Kind,
|
||||
std::vector<StringRef> &Features) {
|
||||
unsigned CPUFeatures = RISCVCPUInfo[static_cast<unsigned>(Kind)].Features;
|
||||
|
||||
if (CPUFeatures == FK_INVALID)
|
||||
return false;
|
||||
|
||||
if (CPUFeatures & FK_64BIT)
|
||||
Features.push_back("+64bit");
|
||||
else
|
||||
Features.push_back("-64bit");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace RISCV
|
||||
} // namespace llvm
|
||||
|
@ -1466,11 +1466,10 @@ void PPCFrameLowering::inlineStackProbe(MachineFunction &MF,
|
||||
.addImm(0)
|
||||
.addImm(32 - Log2(MaxAlign))
|
||||
.addImm(31);
|
||||
BuildMI(PrologMBB, {MI}, DL, TII.get(isPPC64 ? PPC::STDUX : PPC::STWUX),
|
||||
BuildMI(PrologMBB, {MI}, DL, TII.get(isPPC64 ? PPC::SUBFC8 : PPC::SUBFC),
|
||||
SPReg)
|
||||
.addReg(FPReg)
|
||||
.addReg(SPReg)
|
||||
.addReg(ScratchReg);
|
||||
.addReg(ScratchReg)
|
||||
.addReg(SPReg);
|
||||
}
|
||||
// Probe residual part.
|
||||
if (NegResidualSize) {
|
||||
|
@ -11950,18 +11950,34 @@ PPCTargetLowering::emitProbedAlloca(MachineInstr &MI,
|
||||
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
|
||||
Register FinalStackPtr = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
Register FramePointer = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
Register ActualNegSizeReg = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
|
||||
// Get the canonical FinalStackPtr like what
|
||||
// PPCRegisterInfo::lowerDynamicAlloc does.
|
||||
BuildMI(*MBB, {MI}, DL,
|
||||
TII->get(isPPC64 ? PPC::PREPARE_PROBED_ALLOCA_64
|
||||
: PPC::PREPARE_PROBED_ALLOCA_32),
|
||||
FramePointer)
|
||||
.addDef(FinalStackPtr)
|
||||
// Since value of NegSizeReg might be realigned in prologepilog, insert a
|
||||
// PREPARE_PROBED_ALLOCA pseudo instruction to get actual FramePointer and
|
||||
// NegSize.
|
||||
unsigned ProbeOpc;
|
||||
if (!MRI.hasOneNonDBGUse(NegSizeReg))
|
||||
ProbeOpc =
|
||||
isPPC64 ? PPC::PREPARE_PROBED_ALLOCA_64 : PPC::PREPARE_PROBED_ALLOCA_32;
|
||||
else
|
||||
// By introducing PREPARE_PROBED_ALLOCA_NEGSIZE_OPT, ActualNegSizeReg
|
||||
// and NegSizeReg will be allocated in the same phyreg to avoid
|
||||
// redundant copy when NegSizeReg has only one use which is current MI and
|
||||
// will be replaced by PREPARE_PROBED_ALLOCA then.
|
||||
ProbeOpc = isPPC64 ? PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64
|
||||
: PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32;
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(ProbeOpc), FramePointer)
|
||||
.addDef(ActualNegSizeReg)
|
||||
.addReg(NegSizeReg)
|
||||
.add(MI.getOperand(2))
|
||||
.add(MI.getOperand(3));
|
||||
|
||||
// Calculate final stack pointer, which equals to SP + ActualNegSize.
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(isPPC64 ? PPC::ADD8 : PPC::ADD4),
|
||||
FinalStackPtr)
|
||||
.addReg(SPReg)
|
||||
.addReg(ActualNegSizeReg);
|
||||
|
||||
// Materialize a scratch register for update.
|
||||
int64_t NegProbeSize = -(int64_t)ProbeSize;
|
||||
assert(isInt<32>(NegProbeSize) && "Unhandled probe size!");
|
||||
@ -11982,7 +11998,7 @@ PPCTargetLowering::emitProbedAlloca(MachineInstr &MI,
|
||||
// Probing leading residual part.
|
||||
Register Div = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(isPPC64 ? PPC::DIVD : PPC::DIVW), Div)
|
||||
.addReg(NegSizeReg)
|
||||
.addReg(ActualNegSizeReg)
|
||||
.addReg(ScratchReg);
|
||||
Register Mul = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(isPPC64 ? PPC::MULLD : PPC::MULLW), Mul)
|
||||
@ -11991,7 +12007,7 @@ PPCTargetLowering::emitProbedAlloca(MachineInstr &MI,
|
||||
Register NegMod = MRI.createVirtualRegister(isPPC64 ? G8RC : GPRC);
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(isPPC64 ? PPC::SUBF8 : PPC::SUBF), NegMod)
|
||||
.addReg(Mul)
|
||||
.addReg(NegSizeReg);
|
||||
.addReg(ActualNegSizeReg);
|
||||
BuildMI(*MBB, {MI}, DL, TII->get(isPPC64 ? PPC::STDUX : PPC::STWUX), SPReg)
|
||||
.addReg(FramePointer)
|
||||
.addReg(SPReg)
|
||||
|
@ -431,9 +431,14 @@ def PROBED_ALLOCA_64 : PPCCustomInserterPseudo<(outs g8rc:$result),
|
||||
(ins g8rc:$negsize, memri:$fpsi), "#PROBED_ALLOCA_64",
|
||||
[(set i64:$result,
|
||||
(PPCprobedalloca i64:$negsize, iaddr:$fpsi))]>;
|
||||
def PREPARE_PROBED_ALLOCA_64 : PPCEmitTimePseudo<(outs g8rc:$fp,
|
||||
g8rc:$sp),
|
||||
def PREPARE_PROBED_ALLOCA_64 : PPCEmitTimePseudo<(outs
|
||||
g8rc:$fp, g8rc:$actual_negsize),
|
||||
(ins g8rc:$negsize, memri:$fpsi), "#PREPARE_PROBED_ALLOCA_64", []>;
|
||||
def PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64 : PPCEmitTimePseudo<(outs
|
||||
g8rc:$fp, g8rc:$actual_negsize),
|
||||
(ins g8rc:$negsize, memri:$fpsi),
|
||||
"#PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64", []>,
|
||||
RegConstraint<"$actual_negsize = $negsize">;
|
||||
def PROBED_STACKALLOC_64 : PPCEmitTimePseudo<(outs g8rc:$scratch, g8rc:$temp),
|
||||
(ins i64imm:$stacksize),
|
||||
"#PROBED_STACKALLOC_64", []>;
|
||||
|
@ -1406,9 +1406,14 @@ def PROBED_ALLOCA_32 : PPCCustomInserterPseudo<(outs gprc:$result),
|
||||
(ins gprc:$negsize, memri:$fpsi), "#PROBED_ALLOCA_32",
|
||||
[(set i32:$result,
|
||||
(PPCprobedalloca i32:$negsize, iaddr:$fpsi))]>;
|
||||
def PREPARE_PROBED_ALLOCA_32 : PPCEmitTimePseudo<(outs gprc:$fp,
|
||||
gprc:$sp),
|
||||
def PREPARE_PROBED_ALLOCA_32 : PPCEmitTimePseudo<(outs
|
||||
gprc:$fp, gprc:$actual_negsize),
|
||||
(ins gprc:$negsize, memri:$fpsi), "#PREPARE_PROBED_ALLOCA_32", []>;
|
||||
def PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32 : PPCEmitTimePseudo<(outs
|
||||
gprc:$fp, gprc:$actual_negsize),
|
||||
(ins gprc:$negsize, memri:$fpsi),
|
||||
"#PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32", []>,
|
||||
RegConstraint<"$actual_negsize = $negsize">;
|
||||
def PROBED_STACKALLOC_32 : PPCEmitTimePseudo<(outs gprc:$scratch, gprc:$temp),
|
||||
(ins i64imm:$stacksize),
|
||||
"#PROBED_STACKALLOC_32", []>;
|
||||
|
@ -624,21 +624,30 @@ void PPCRegisterInfo::lowerPrepareProbedAlloca(
|
||||
bool LP64 = TM.isPPC64();
|
||||
DebugLoc dl = MI.getDebugLoc();
|
||||
Register FramePointer = MI.getOperand(0).getReg();
|
||||
Register FinalStackPtr = MI.getOperand(1).getReg();
|
||||
const Register ActualNegSizeReg = MI.getOperand(1).getReg();
|
||||
bool KillNegSizeReg = MI.getOperand(2).isKill();
|
||||
Register NegSizeReg = MI.getOperand(2).getReg();
|
||||
prepareDynamicAlloca(II, NegSizeReg, KillNegSizeReg, FramePointer);
|
||||
if (LP64) {
|
||||
BuildMI(MBB, II, dl, TII.get(PPC::ADD8), FinalStackPtr)
|
||||
.addReg(PPC::X1)
|
||||
.addReg(NegSizeReg, getKillRegState(KillNegSizeReg));
|
||||
|
||||
} else {
|
||||
BuildMI(MBB, II, dl, TII.get(PPC::ADD4), FinalStackPtr)
|
||||
.addReg(PPC::R1)
|
||||
.addReg(NegSizeReg, getKillRegState(KillNegSizeReg));
|
||||
const MCInstrDesc &CopyInst = TII.get(LP64 ? PPC::OR8 : PPC::OR);
|
||||
// RegAllocator might allocate FramePointer and NegSizeReg in the same phyreg.
|
||||
if (FramePointer == NegSizeReg) {
|
||||
assert(KillNegSizeReg && "FramePointer is a def and NegSizeReg is an use, "
|
||||
"NegSizeReg should be killed");
|
||||
// FramePointer is clobbered earlier than the use of NegSizeReg in
|
||||
// prepareDynamicAlloca, save NegSizeReg in ActualNegSizeReg to avoid
|
||||
// misuse.
|
||||
BuildMI(MBB, II, dl, CopyInst, ActualNegSizeReg)
|
||||
.addReg(NegSizeReg)
|
||||
.addReg(NegSizeReg);
|
||||
NegSizeReg = ActualNegSizeReg;
|
||||
KillNegSizeReg = false;
|
||||
}
|
||||
|
||||
prepareDynamicAlloca(II, NegSizeReg, KillNegSizeReg, FramePointer);
|
||||
// NegSizeReg might be updated in prepareDynamicAlloca if MaxAlign >
|
||||
// TargetAlign.
|
||||
if (NegSizeReg != ActualNegSizeReg)
|
||||
BuildMI(MBB, II, dl, CopyInst, ActualNegSizeReg)
|
||||
.addReg(NegSizeReg)
|
||||
.addReg(NegSizeReg);
|
||||
MBB.erase(II);
|
||||
}
|
||||
|
||||
@ -1084,7 +1093,9 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
|
||||
if (FPSI && FrameIndex == FPSI &&
|
||||
(OpC == PPC::PREPARE_PROBED_ALLOCA_64 ||
|
||||
OpC == PPC::PREPARE_PROBED_ALLOCA_32)) {
|
||||
OpC == PPC::PREPARE_PROBED_ALLOCA_32 ||
|
||||
OpC == PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64 ||
|
||||
OpC == PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32)) {
|
||||
lowerPrepareProbedAlloca(II);
|
||||
return;
|
||||
}
|
||||
|
@ -215,6 +215,16 @@ def : ProcessorModel<"rocket-rv32", Rocket32Model, []>;
|
||||
|
||||
def : ProcessorModel<"rocket-rv64", Rocket64Model, [Feature64Bit]>;
|
||||
|
||||
def : ProcessorModel<"sifive-e31", Rocket32Model, [FeatureStdExtM,
|
||||
FeatureStdExtA,
|
||||
FeatureStdExtC]>;
|
||||
|
||||
def : ProcessorModel<"sifive-u54", Rocket64Model, [Feature64Bit,
|
||||
FeatureStdExtM,
|
||||
FeatureStdExtA,
|
||||
FeatureStdExtF,
|
||||
FeatureStdExtD,
|
||||
FeatureStdExtC]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the RISC-V target.
|
||||
|
@ -463,7 +463,14 @@ struct X86Operand final : public MCParsedAsmOperand {
|
||||
bool isGR32orGR64() const {
|
||||
return Kind == Register &&
|
||||
(X86MCRegisterClasses[X86::GR32RegClassID].contains(getReg()) ||
|
||||
X86MCRegisterClasses[X86::GR64RegClassID].contains(getReg()));
|
||||
X86MCRegisterClasses[X86::GR64RegClassID].contains(getReg()));
|
||||
}
|
||||
|
||||
bool isGR16orGR32orGR64() const {
|
||||
return Kind == Register &&
|
||||
(X86MCRegisterClasses[X86::GR16RegClassID].contains(getReg()) ||
|
||||
X86MCRegisterClasses[X86::GR32RegClassID].contains(getReg()) ||
|
||||
X86MCRegisterClasses[X86::GR64RegClassID].contains(getReg()));
|
||||
}
|
||||
|
||||
bool isVectorReg() const {
|
||||
@ -520,6 +527,15 @@ struct X86Operand final : public MCParsedAsmOperand {
|
||||
Inst.addOperand(MCOperand::createReg(RegNo));
|
||||
}
|
||||
|
||||
void addGR16orGR32orGR64Operands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
MCRegister RegNo = getReg();
|
||||
if (X86MCRegisterClasses[X86::GR32RegClassID].contains(RegNo) ||
|
||||
X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo))
|
||||
RegNo = getX86SubSuperRegister(RegNo, 16);
|
||||
Inst.addOperand(MCOperand::createReg(RegNo));
|
||||
}
|
||||
|
||||
void addAVX512RCOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
addExpr(Inst, getImm());
|
||||
|
@ -6916,25 +6916,16 @@ static bool getTargetShuffleMask(SDNode *N, MVT VT, bool AllowSentinelZero,
|
||||
DecodeZeroMoveLowMask(NumElems, Mask);
|
||||
IsUnary = true;
|
||||
break;
|
||||
case X86ISD::VBROADCAST: {
|
||||
SDValue N0 = N->getOperand(0);
|
||||
// See if we're broadcasting from index 0 of an EXTRACT_SUBVECTOR. If so,
|
||||
// add the pre-extracted value to the Ops vector.
|
||||
if (N0.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
|
||||
N0.getOperand(0).getValueType() == VT &&
|
||||
N0.getConstantOperandVal(1) == 0)
|
||||
Ops.push_back(N0.getOperand(0));
|
||||
|
||||
// We only decode broadcasts of same-sized vectors, unless the broadcast
|
||||
// came from an extract from the original width. If we found one, we
|
||||
// pushed it the Ops vector above.
|
||||
if (N0.getValueType() == VT || !Ops.empty()) {
|
||||
case X86ISD::VBROADCAST:
|
||||
// We only decode broadcasts of same-sized vectors, peeking through to
|
||||
// extracted subvectors is likely to cause hasOneUse issues with
|
||||
// SimplifyDemandedBits etc.
|
||||
if (N->getOperand(0).getValueType() == VT) {
|
||||
DecodeVectorBroadcast(NumElems, Mask);
|
||||
IsUnary = true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case X86ISD::VPERMILPV: {
|
||||
assert(N->getOperand(0).getValueType() == VT && "Unexpected value type");
|
||||
IsUnary = true;
|
||||
@ -44523,6 +44514,8 @@ static SDValue combineFaddFsub(SDNode *N, SelectionDAG &DAG,
|
||||
isHorizontalBinOp(LHS, RHS, DAG, Subtarget, IsFadd))
|
||||
return DAG.getNode(HorizOpcode, SDLoc(N), VT, LHS, RHS);
|
||||
|
||||
// NOTE: isHorizontalBinOp may have changed LHS/RHS variables.
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
@ -47604,6 +47597,30 @@ static SDValue matchPMADDWD_2(SelectionDAG &DAG, SDValue N0, SDValue N1,
|
||||
PMADDBuilder);
|
||||
}
|
||||
|
||||
static SDValue combineAddOrSubToHADDorHSUB(SDNode *N, SelectionDAG &DAG,
|
||||
const X86Subtarget &Subtarget) {
|
||||
EVT VT = N->getValueType(0);
|
||||
SDValue Op0 = N->getOperand(0);
|
||||
SDValue Op1 = N->getOperand(1);
|
||||
bool IsAdd = N->getOpcode() == ISD::ADD;
|
||||
assert((IsAdd || N->getOpcode() == ISD::SUB) && "Wrong opcode");
|
||||
|
||||
if ((VT == MVT::v8i16 || VT == MVT::v4i32 || VT == MVT::v16i16 ||
|
||||
VT == MVT::v8i32) &&
|
||||
Subtarget.hasSSSE3() &&
|
||||
isHorizontalBinOp(Op0, Op1, DAG, Subtarget, IsAdd)) {
|
||||
auto HOpBuilder = [IsAdd](SelectionDAG &DAG, const SDLoc &DL,
|
||||
ArrayRef<SDValue> Ops) {
|
||||
return DAG.getNode(IsAdd ? X86ISD::HADD : X86ISD::HSUB,
|
||||
DL, Ops[0].getValueType(), Ops);
|
||||
};
|
||||
return SplitOpsAndApply(DAG, Subtarget, SDLoc(N), VT, {Op0, Op1},
|
||||
HOpBuilder);
|
||||
}
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
static SDValue combineAdd(SDNode *N, SelectionDAG &DAG,
|
||||
TargetLowering::DAGCombinerInfo &DCI,
|
||||
const X86Subtarget &Subtarget) {
|
||||
@ -47617,17 +47634,8 @@ static SDValue combineAdd(SDNode *N, SelectionDAG &DAG,
|
||||
return MAdd;
|
||||
|
||||
// Try to synthesize horizontal adds from adds of shuffles.
|
||||
if ((VT == MVT::v8i16 || VT == MVT::v4i32 || VT == MVT::v16i16 ||
|
||||
VT == MVT::v8i32) &&
|
||||
Subtarget.hasSSSE3() &&
|
||||
isHorizontalBinOp(Op0, Op1, DAG, Subtarget, true)) {
|
||||
auto HADDBuilder = [](SelectionDAG &DAG, const SDLoc &DL,
|
||||
ArrayRef<SDValue> Ops) {
|
||||
return DAG.getNode(X86ISD::HADD, DL, Ops[0].getValueType(), Ops);
|
||||
};
|
||||
return SplitOpsAndApply(DAG, Subtarget, SDLoc(N), VT, {Op0, Op1},
|
||||
HADDBuilder);
|
||||
}
|
||||
if (SDValue V = combineAddOrSubToHADDorHSUB(N, DAG, Subtarget))
|
||||
return V;
|
||||
|
||||
// If vectors of i1 are legal, turn (add (zext (vXi1 X)), Y) into
|
||||
// (sub Y, (sext (vXi1 X))).
|
||||
@ -47800,18 +47808,8 @@ static SDValue combineSub(SDNode *N, SelectionDAG &DAG,
|
||||
}
|
||||
|
||||
// Try to synthesize horizontal subs from subs of shuffles.
|
||||
EVT VT = N->getValueType(0);
|
||||
if ((VT == MVT::v8i16 || VT == MVT::v4i32 || VT == MVT::v16i16 ||
|
||||
VT == MVT::v8i32) &&
|
||||
Subtarget.hasSSSE3() &&
|
||||
isHorizontalBinOp(Op0, Op1, DAG, Subtarget, false)) {
|
||||
auto HSUBBuilder = [](SelectionDAG &DAG, const SDLoc &DL,
|
||||
ArrayRef<SDValue> Ops) {
|
||||
return DAG.getNode(X86ISD::HSUB, DL, Ops[0].getValueType(), Ops);
|
||||
};
|
||||
return SplitOpsAndApply(DAG, Subtarget, SDLoc(N), VT, {Op0, Op1},
|
||||
HSUBBuilder);
|
||||
}
|
||||
if (SDValue V = combineAddOrSubToHADDorHSUB(N, DAG, Subtarget))
|
||||
return V;
|
||||
|
||||
// Try to create PSUBUS if SUB's argument is max/min
|
||||
if (SDValue V = combineSubToSubus(N, DAG, Subtarget))
|
||||
|
@ -640,10 +640,17 @@ class ImmSExtAsmOperandClass : AsmOperandClass {
|
||||
def X86GR32orGR64AsmOperand : AsmOperandClass {
|
||||
let Name = "GR32orGR64";
|
||||
}
|
||||
|
||||
def GR32orGR64 : RegisterOperand<GR32> {
|
||||
let ParserMatchClass = X86GR32orGR64AsmOperand;
|
||||
}
|
||||
|
||||
def X86GR16orGR32orGR64AsmOperand : AsmOperandClass {
|
||||
let Name = "GR16orGR32orGR64";
|
||||
}
|
||||
def GR16orGR32orGR64 : RegisterOperand<GR16> {
|
||||
let ParserMatchClass = X86GR16orGR32orGR64AsmOperand;
|
||||
}
|
||||
|
||||
def AVX512RCOperand : AsmOperandClass {
|
||||
let Name = "AVX512RC";
|
||||
}
|
||||
|
@ -207,45 +207,41 @@ let mayLoad = 1 in
|
||||
def LAR16rm : I<0x02, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
|
||||
"lar{w}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize16, NotMemoryFoldable;
|
||||
def LAR16rr : I<0x02, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
|
||||
def LAR16rr : I<0x02, MRMSrcReg, (outs GR16:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lar{w}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize16, NotMemoryFoldable;
|
||||
|
||||
// i16mem operand in LAR32rm and GR32 operand in LAR32rr is not a typo.
|
||||
let mayLoad = 1 in
|
||||
def LAR32rm : I<0x02, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
|
||||
"lar{l}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize32, NotMemoryFoldable;
|
||||
def LAR32rr : I<0x02, MRMSrcReg, (outs GR32:$dst), (ins GR32:$src),
|
||||
def LAR32rr : I<0x02, MRMSrcReg, (outs GR32:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lar{l}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize32, NotMemoryFoldable;
|
||||
// i16mem operand in LAR64rm and GR32 operand in LAR64rr is not a typo.
|
||||
let mayLoad = 1 in
|
||||
def LAR64rm : RI<0x02, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
|
||||
"lar{q}\t{$src, $dst|$dst, $src}", []>, TB, NotMemoryFoldable;
|
||||
def LAR64rr : RI<0x02, MRMSrcReg, (outs GR64:$dst), (ins GR32:$src),
|
||||
def LAR64rr : RI<0x02, MRMSrcReg, (outs GR64:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lar{q}\t{$src, $dst|$dst, $src}", []>, TB, NotMemoryFoldable;
|
||||
|
||||
// i16mem operand in LSL32rm and GR32 operand in LSL32rr is not a typo.
|
||||
let mayLoad = 1 in
|
||||
def LSL16rm : I<0x03, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
|
||||
"lsl{w}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize16, NotMemoryFoldable;
|
||||
def LSL16rr : I<0x03, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
|
||||
def LSL16rr : I<0x03, MRMSrcReg, (outs GR16:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lsl{w}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize16, NotMemoryFoldable;
|
||||
// i16mem operand in LSL64rm and GR32 operand in LSL64rr is not a typo.
|
||||
let mayLoad = 1 in
|
||||
def LSL32rm : I<0x03, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
|
||||
"lsl{l}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize32, NotMemoryFoldable;
|
||||
def LSL32rr : I<0x03, MRMSrcReg, (outs GR32:$dst), (ins GR32:$src),
|
||||
def LSL32rr : I<0x03, MRMSrcReg, (outs GR32:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lsl{l}\t{$src, $dst|$dst, $src}", []>, TB,
|
||||
OpSize32, NotMemoryFoldable;
|
||||
let mayLoad = 1 in
|
||||
def LSL64rm : RI<0x03, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
|
||||
"lsl{q}\t{$src, $dst|$dst, $src}", []>, TB, NotMemoryFoldable;
|
||||
def LSL64rr : RI<0x03, MRMSrcReg, (outs GR64:$dst), (ins GR32:$src),
|
||||
def LSL64rr : RI<0x03, MRMSrcReg, (outs GR64:$dst), (ins GR16orGR32orGR64:$src),
|
||||
"lsl{q}\t{$src, $dst|$dst, $src}", []>, TB, NotMemoryFoldable;
|
||||
|
||||
def INVLPG : I<0x01, MRM7m, (outs), (ins i8mem:$addr), "invlpg\t$addr", []>, TB;
|
||||
|
@ -1148,11 +1148,12 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
|
||||
assert((IsAnd || Logic.getOpcode() == Instruction::Or) && "Wrong logic op");
|
||||
|
||||
// Match an equality compare with a non-poison constant as Cmp0.
|
||||
// Also, give up if the compare can be constant-folded to avoid looping.
|
||||
ICmpInst::Predicate Pred0;
|
||||
Value *X;
|
||||
Constant *C;
|
||||
if (!match(Cmp0, m_ICmp(Pred0, m_Value(X), m_Constant(C))) ||
|
||||
!isGuaranteedNotToBeUndefOrPoison(C))
|
||||
!isGuaranteedNotToBeUndefOrPoison(C) || isa<Constant>(X))
|
||||
return nullptr;
|
||||
if ((IsAnd && Pred0 != ICmpInst::ICMP_EQ) ||
|
||||
(!IsAnd && Pred0 != ICmpInst::ICMP_NE))
|
||||
|
@ -4220,16 +4220,11 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||
break;
|
||||
case Intrinsic::assume: {
|
||||
Value *IIOperand = II->getArgOperand(0);
|
||||
SmallVector<OperandBundleDef, 4> OpBundles;
|
||||
II->getOperandBundlesAsDefs(OpBundles);
|
||||
bool HasOpBundles = !OpBundles.empty();
|
||||
// Remove an assume if it is followed by an identical assume.
|
||||
// TODO: Do we need this? Unless there are conflicting assumptions, the
|
||||
// computeKnownBits(IIOperand) below here eliminates redundant assumes.
|
||||
Instruction *Next = II->getNextNonDebugInstruction();
|
||||
if (HasOpBundles &&
|
||||
match(Next, m_Intrinsic<Intrinsic::assume>(m_Specific(IIOperand))) &&
|
||||
!cast<IntrinsicInst>(Next)->hasOperandBundles())
|
||||
if (match(Next, m_Intrinsic<Intrinsic::assume>(m_Specific(IIOperand))))
|
||||
return eraseInstFromFunction(CI);
|
||||
|
||||
// Canonicalize assume(a && b) -> assume(a); assume(b);
|
||||
@ -4239,15 +4234,14 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||
Value *AssumeIntrinsic = II->getCalledOperand();
|
||||
Value *A, *B;
|
||||
if (match(IIOperand, m_And(m_Value(A), m_Value(B)))) {
|
||||
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, A, OpBundles,
|
||||
II->getName());
|
||||
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, A, II->getName());
|
||||
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, B, II->getName());
|
||||
return eraseInstFromFunction(*II);
|
||||
}
|
||||
// assume(!(a || b)) -> assume(!a); assume(!b);
|
||||
if (match(IIOperand, m_Not(m_Or(m_Value(A), m_Value(B))))) {
|
||||
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic,
|
||||
Builder.CreateNot(A), OpBundles, II->getName());
|
||||
Builder.CreateNot(A), II->getName());
|
||||
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic,
|
||||
Builder.CreateNot(B), II->getName());
|
||||
return eraseInstFromFunction(*II);
|
||||
@ -4263,8 +4257,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
|
||||
isValidAssumeForContext(II, LHS, &DT)) {
|
||||
MDNode *MD = MDNode::get(II->getContext(), None);
|
||||
LHS->setMetadata(LLVMContext::MD_nonnull, MD);
|
||||
if (!HasOpBundles)
|
||||
return eraseInstFromFunction(*II);
|
||||
return eraseInstFromFunction(*II);
|
||||
|
||||
// TODO: apply nonnull return attributes to calls and invokes
|
||||
// TODO: apply range metadata for range check patterns?
|
||||
|
@ -653,7 +653,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
|
||||
"New instruction already inserted into a basic block!");
|
||||
BasicBlock *BB = Old.getParent();
|
||||
BB->getInstList().insert(Old.getIterator(), New); // Insert inst
|
||||
Worklist.push(New);
|
||||
Worklist.add(New);
|
||||
return New;
|
||||
}
|
||||
|
||||
|
@ -2469,6 +2469,10 @@ static Instruction *foldSelectToPhiImpl(SelectInst &Sel, BasicBlock *BB,
|
||||
} else
|
||||
return nullptr;
|
||||
|
||||
// Make sure the branches are actually different.
|
||||
if (TrueSucc == FalseSucc)
|
||||
return nullptr;
|
||||
|
||||
// We want to replace select %cond, %a, %b with a phi that takes value %a
|
||||
// for all incoming edges that are dominated by condition `%cond == true`,
|
||||
// and value %b for edges dominated by condition `%cond == false`. If %a
|
||||
|
@ -15,7 +15,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#define AA_NAME "alignment-from-assumptions"
|
||||
#define DEBUG_TYPE AA_NAME
|
||||
@ -204,33 +203,103 @@ static Align getNewAlignment(const SCEV *AASCEV, const SCEV *AlignSCEV,
|
||||
}
|
||||
|
||||
bool AlignmentFromAssumptionsPass::extractAlignmentInfo(CallInst *I,
|
||||
unsigned Idx,
|
||||
Value *&AAPtr,
|
||||
const SCEV *&AlignSCEV,
|
||||
const SCEV *&OffSCEV) {
|
||||
Type *Int64Ty = Type::getInt64Ty(I->getContext());
|
||||
OperandBundleUse AlignOB = I->getOperandBundleAt(Idx);
|
||||
if (AlignOB.getTagName() != "align")
|
||||
// An alignment assume must be a statement about the least-significant
|
||||
// bits of the pointer being zero, possibly with some offset.
|
||||
ICmpInst *ICI = dyn_cast<ICmpInst>(I->getArgOperand(0));
|
||||
if (!ICI)
|
||||
return false;
|
||||
assert(AlignOB.Inputs.size() >= 2);
|
||||
AAPtr = AlignOB.Inputs[0].get();
|
||||
// TODO: Consider accumulating the offset to the base.
|
||||
AAPtr = AAPtr->stripPointerCastsSameRepresentation();
|
||||
AlignSCEV = SE->getSCEV(AlignOB.Inputs[1].get());
|
||||
AlignSCEV = SE->getTruncateOrZeroExtend(AlignSCEV, Int64Ty);
|
||||
if (AlignOB.Inputs.size() == 3)
|
||||
OffSCEV = SE->getSCEV(AlignOB.Inputs[2].get());
|
||||
else
|
||||
|
||||
// This must be an expression of the form: x & m == 0.
|
||||
if (ICI->getPredicate() != ICmpInst::ICMP_EQ)
|
||||
return false;
|
||||
|
||||
// Swap things around so that the RHS is 0.
|
||||
Value *CmpLHS = ICI->getOperand(0);
|
||||
Value *CmpRHS = ICI->getOperand(1);
|
||||
const SCEV *CmpLHSSCEV = SE->getSCEV(CmpLHS);
|
||||
const SCEV *CmpRHSSCEV = SE->getSCEV(CmpRHS);
|
||||
if (CmpLHSSCEV->isZero())
|
||||
std::swap(CmpLHS, CmpRHS);
|
||||
else if (!CmpRHSSCEV->isZero())
|
||||
return false;
|
||||
|
||||
BinaryOperator *CmpBO = dyn_cast<BinaryOperator>(CmpLHS);
|
||||
if (!CmpBO || CmpBO->getOpcode() != Instruction::And)
|
||||
return false;
|
||||
|
||||
// Swap things around so that the right operand of the and is a constant
|
||||
// (the mask); we cannot deal with variable masks.
|
||||
Value *AndLHS = CmpBO->getOperand(0);
|
||||
Value *AndRHS = CmpBO->getOperand(1);
|
||||
const SCEV *AndLHSSCEV = SE->getSCEV(AndLHS);
|
||||
const SCEV *AndRHSSCEV = SE->getSCEV(AndRHS);
|
||||
if (isa<SCEVConstant>(AndLHSSCEV)) {
|
||||
std::swap(AndLHS, AndRHS);
|
||||
std::swap(AndLHSSCEV, AndRHSSCEV);
|
||||
}
|
||||
|
||||
const SCEVConstant *MaskSCEV = dyn_cast<SCEVConstant>(AndRHSSCEV);
|
||||
if (!MaskSCEV)
|
||||
return false;
|
||||
|
||||
// The mask must have some trailing ones (otherwise the condition is
|
||||
// trivial and tells us nothing about the alignment of the left operand).
|
||||
unsigned TrailingOnes = MaskSCEV->getAPInt().countTrailingOnes();
|
||||
if (!TrailingOnes)
|
||||
return false;
|
||||
|
||||
// Cap the alignment at the maximum with which LLVM can deal (and make sure
|
||||
// we don't overflow the shift).
|
||||
uint64_t Alignment;
|
||||
TrailingOnes = std::min(TrailingOnes,
|
||||
unsigned(sizeof(unsigned) * CHAR_BIT - 1));
|
||||
Alignment = std::min(1u << TrailingOnes, +Value::MaximumAlignment);
|
||||
|
||||
Type *Int64Ty = Type::getInt64Ty(I->getParent()->getParent()->getContext());
|
||||
AlignSCEV = SE->getConstant(Int64Ty, Alignment);
|
||||
|
||||
// The LHS might be a ptrtoint instruction, or it might be the pointer
|
||||
// with an offset.
|
||||
AAPtr = nullptr;
|
||||
OffSCEV = nullptr;
|
||||
if (PtrToIntInst *PToI = dyn_cast<PtrToIntInst>(AndLHS)) {
|
||||
AAPtr = PToI->getPointerOperand();
|
||||
OffSCEV = SE->getZero(Int64Ty);
|
||||
OffSCEV = SE->getTruncateOrZeroExtend(OffSCEV, Int64Ty);
|
||||
} else if (const SCEVAddExpr* AndLHSAddSCEV =
|
||||
dyn_cast<SCEVAddExpr>(AndLHSSCEV)) {
|
||||
// Try to find the ptrtoint; subtract it and the rest is the offset.
|
||||
for (SCEVAddExpr::op_iterator J = AndLHSAddSCEV->op_begin(),
|
||||
JE = AndLHSAddSCEV->op_end(); J != JE; ++J)
|
||||
if (const SCEVUnknown *OpUnk = dyn_cast<SCEVUnknown>(*J))
|
||||
if (PtrToIntInst *PToI = dyn_cast<PtrToIntInst>(OpUnk->getValue())) {
|
||||
AAPtr = PToI->getPointerOperand();
|
||||
OffSCEV = SE->getMinusSCEV(AndLHSAddSCEV, *J);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AAPtr)
|
||||
return false;
|
||||
|
||||
// Sign extend the offset to 64 bits (so that it is like all of the other
|
||||
// expressions).
|
||||
unsigned OffSCEVBits = OffSCEV->getType()->getPrimitiveSizeInBits();
|
||||
if (OffSCEVBits < 64)
|
||||
OffSCEV = SE->getSignExtendExpr(OffSCEV, Int64Ty);
|
||||
else if (OffSCEVBits > 64)
|
||||
return false;
|
||||
|
||||
AAPtr = AAPtr->stripPointerCasts();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
|
||||
unsigned Idx) {
|
||||
bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall) {
|
||||
Value *AAPtr;
|
||||
const SCEV *AlignSCEV, *OffSCEV;
|
||||
if (!extractAlignmentInfo(ACall, Idx, AAPtr, AlignSCEV, OffSCEV))
|
||||
if (!extractAlignmentInfo(ACall, AAPtr, AlignSCEV, OffSCEV))
|
||||
return false;
|
||||
|
||||
// Skip ConstantPointerNull and UndefValue. Assumptions on these shouldn't
|
||||
@ -248,14 +317,13 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
|
||||
continue;
|
||||
|
||||
if (Instruction *K = dyn_cast<Instruction>(J))
|
||||
if (isValidAssumeForContext(ACall, K, DT))
|
||||
WorkList.push_back(K);
|
||||
}
|
||||
|
||||
while (!WorkList.empty()) {
|
||||
Instruction *J = WorkList.pop_back_val();
|
||||
if (LoadInst *LI = dyn_cast<LoadInst>(J)) {
|
||||
if (!isValidAssumeForContext(ACall, J, DT))
|
||||
continue;
|
||||
Align NewAlignment = getNewAlignment(AASCEV, AlignSCEV, OffSCEV,
|
||||
LI->getPointerOperand(), SE);
|
||||
if (NewAlignment > LI->getAlign()) {
|
||||
@ -263,8 +331,6 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
|
||||
++NumLoadAlignChanged;
|
||||
}
|
||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(J)) {
|
||||
if (!isValidAssumeForContext(ACall, J, DT))
|
||||
continue;
|
||||
Align NewAlignment = getNewAlignment(AASCEV, AlignSCEV, OffSCEV,
|
||||
SI->getPointerOperand(), SE);
|
||||
if (NewAlignment > SI->getAlign()) {
|
||||
@ -272,8 +338,6 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
|
||||
++NumStoreAlignChanged;
|
||||
}
|
||||
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(J)) {
|
||||
if (!isValidAssumeForContext(ACall, J, DT))
|
||||
continue;
|
||||
Align NewDestAlignment =
|
||||
getNewAlignment(AASCEV, AlignSCEV, OffSCEV, MI->getDest(), SE);
|
||||
|
||||
@ -305,7 +369,7 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall,
|
||||
Visited.insert(J);
|
||||
for (User *UJ : J->users()) {
|
||||
Instruction *K = cast<Instruction>(UJ);
|
||||
if (!Visited.count(K))
|
||||
if (!Visited.count(K) && isValidAssumeForContext(ACall, K, DT))
|
||||
WorkList.push_back(K);
|
||||
}
|
||||
}
|
||||
@ -332,11 +396,8 @@ bool AlignmentFromAssumptionsPass::runImpl(Function &F, AssumptionCache &AC,
|
||||
|
||||
bool Changed = false;
|
||||
for (auto &AssumeVH : AC.assumptions())
|
||||
if (AssumeVH) {
|
||||
CallInst *Call = cast<CallInst>(AssumeVH);
|
||||
for (unsigned Idx = 0; Idx < Call->getNumOperandBundles(); Idx++)
|
||||
Changed |= processAssumption(Call, Idx);
|
||||
}
|
||||
if (AssumeVH)
|
||||
Changed |= processAssumption(cast<CallInst>(AssumeVH));
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
@ -874,6 +874,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
|
||||
TYPE("i16imm", TYPE_IMM)
|
||||
TYPE("i16i8imm", TYPE_IMM)
|
||||
TYPE("GR16", TYPE_R16)
|
||||
TYPE("GR16orGR32orGR64", TYPE_R16)
|
||||
TYPE("i32mem", TYPE_M)
|
||||
TYPE("i32imm", TYPE_IMM)
|
||||
TYPE("i32i8imm", TYPE_IMM)
|
||||
@ -1035,6 +1036,7 @@ RecognizableInstr::rmRegisterEncodingFromString(const std::string &s,
|
||||
ENCODING("RST", ENCODING_FP)
|
||||
ENCODING("RSTi", ENCODING_FP)
|
||||
ENCODING("GR16", ENCODING_RM)
|
||||
ENCODING("GR16orGR32orGR64",ENCODING_RM)
|
||||
ENCODING("GR32", ENCODING_RM)
|
||||
ENCODING("GR32orGR64", ENCODING_RM)
|
||||
ENCODING("GR64", ENCODING_RM)
|
||||
@ -1072,6 +1074,7 @@ OperandEncoding
|
||||
RecognizableInstr::roRegisterEncodingFromString(const std::string &s,
|
||||
uint8_t OpSize) {
|
||||
ENCODING("GR16", ENCODING_REG)
|
||||
ENCODING("GR16orGR32orGR64",ENCODING_REG)
|
||||
ENCODING("GR32", ENCODING_REG)
|
||||
ENCODING("GR32orGR64", ENCODING_REG)
|
||||
ENCODING("GR64", ENCODING_REG)
|
||||
|
Loading…
Reference in New Issue
Block a user