Vendor import of llvm release_50 branch r319231:

https://llvm.org/svn/llvm-project/llvm/branches/release_50@319231
This commit is contained in:
Dimitry Andric 2017-12-02 12:46:23 +00:00
parent 0bc1bd0d39
commit edad5bcb76
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/llvm/dist/; revision=326460
svn path=/vendor/llvm/llvm-release_50-r319231/; revision=326461; tag=vendor/llvm/llvm-release_50-r319231
123 changed files with 6681 additions and 378 deletions

View file

@ -26,7 +26,7 @@ if(NOT DEFINED LLVM_VERSION_MINOR)
set(LLVM_VERSION_MINOR 0)
endif()
if(NOT DEFINED LLVM_VERSION_PATCH)
set(LLVM_VERSION_PATCH 0)
set(LLVM_VERSION_PATCH 1)
endif()
if(NOT DEFINED LLVM_VERSION_SUFFIX)
set(LLVM_VERSION_SUFFIX "")
@ -208,10 +208,6 @@ include(VersionFromVCS)
option(LLVM_APPEND_VC_REV
"Embed the version control system revision id in LLVM" ON)
if( LLVM_APPEND_VC_REV )
add_version_info_from_vcs(PACKAGE_VERSION)
endif()
set(PACKAGE_NAME LLVM)
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "http://llvm.org/bugs/")

View file

@ -248,9 +248,10 @@ LLVM-specific variables
**LLVM_APPEND_VC_REV**:BOOL
Embed version control revision info (svn revision number or Git revision id).
This is used among other things in the LLVM version string (stored in the
PACKAGE_VERSION macro). For this to work cmake must be invoked before the
build. Defaults to ON.
The version info is provided by the ``LLVM_REVISION`` macro in
``llvm/include/llvm/Support/VCSRevision.h``. Developers using git who don't
need revision info can disable this option to avoid re-linking most binaries
after a branch switch. Defaults to ON.
**LLVM_ENABLE_THREADS**:BOOL
Build with threads support, if available. Defaults to ON.

View file

@ -652,6 +652,12 @@ class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
auto GTI = gep_type_begin(PointeeType, Operands);
Type *TargetType;
// Handle the case where the GEP instruction has a single operand,
// the basis, therefore TargetType is a nullptr.
if (Operands.empty())
return !BaseGV ? TTI::TCC_Free : TTI::TCC_Basic;
for (auto I = Operands.begin(); I != Operands.end(); ++I, ++GTI) {
TargetType = GTI.getIndexedType();
// We assume that the cost of Scalar GEP with constant index and the

View file

@ -807,6 +807,14 @@ class MachineRegisterInfo {
return getReservedRegs().test(PhysReg);
}
/// Returns true when the given register unit is considered reserved.
///
/// Register units are considered reserved when for at least one of their
/// root registers, the root register and all super registers are reserved.
/// This currently iterates the register hierarchy and may be slower than
/// expected.
bool isReservedRegUnit(unsigned Unit) const;
/// isAllocatable - Returns true when PhysReg belongs to an allocatable
/// register class and it hasn't been reserved.
///

View file

@ -51,6 +51,8 @@ namespace llvm {
/// module is modified.
bool UpgradeModuleFlags(Module &M);
void UpgradeSectionAttributes(Module &M);
/// If the given TBAA tag uses the scalar TBAA format, create a new node
/// corresponding to the upgrade to the struct-path aware TBAA format.
/// Otherwise return the \p TBAANode itself.

View file

@ -94,6 +94,15 @@ class formatv_object_base {
Adapters.reserve(ParamCount);
}
formatv_object_base(formatv_object_base const &rhs) = delete;
formatv_object_base(formatv_object_base &&rhs)
: Fmt(std::move(rhs.Fmt)),
Adapters(), // Adapters are initialized by formatv_object
Replacements(std::move(rhs.Replacements)) {
Adapters.reserve(rhs.Adapters.size());
};
void format(raw_ostream &S) const {
for (auto &R : Replacements) {
if (R.Type == ReplacementType::Empty)
@ -149,6 +158,14 @@ template <typename Tuple> class formatv_object : public formatv_object_base {
Parameters(std::move(Params)) {
Adapters = apply_tuple(create_adapters(), Parameters);
}
formatv_object(formatv_object const &rhs) = delete;
formatv_object(formatv_object &&rhs)
: formatv_object_base(std::move(rhs)),
Parameters(std::move(rhs.Parameters)) {
Adapters = apply_tuple(create_adapters(), Parameters);
}
};
// \brief Format text given a format string and replacement parameters.

View file

@ -240,6 +240,7 @@ bool LLParser::ValidateEndOfModule() {
UpgradeDebugInfo(*M);
UpgradeModuleFlags(*M);
UpgradeSectionAttributes(*M);
if (!Slots)
return false;

View file

@ -264,7 +264,7 @@ Expected<bool> hasObjCCategoryInModule(BitstreamCursor &Stream) {
if (convertToString(Record, 0, S))
return error("Invalid record");
// Check for the i386 and other (x86_64, ARM) conventions
if (S.find("__DATA, __objc_catlist") != std::string::npos ||
if (S.find("__DATA,__objc_catlist") != std::string::npos ||
S.find("__OBJC,__category") != std::string::npos)
return true;
break;

View file

@ -621,6 +621,7 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
DIE *ContextDIE;
DwarfCompileUnit *ContextCU = this;
if (includeMinimalInlineScopes())
ContextDIE = &getUnitDie();
@ -631,18 +632,23 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
else if (auto *SPDecl = SP->getDeclaration()) {
ContextDIE = &getUnitDie();
getOrCreateSubprogramDIE(SPDecl);
} else
} else {
ContextDIE = getOrCreateContextDIE(resolve(SP->getScope()));
// The scope may be shared with a subprogram that has already been
// constructed in another CU, in which case we need to construct this
// subprogram in the same CU.
ContextCU = DD->lookupCU(ContextDIE->getUnitDie());
}
// Passing null as the associated node because the abstract definition
// shouldn't be found by lookup.
AbsDef = &createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr);
applySubprogramAttributesToDefinition(SP, *AbsDef);
AbsDef = &ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr);
ContextCU->applySubprogramAttributesToDefinition(SP, *AbsDef);
if (!includeMinimalInlineScopes())
addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined);
if (DIE *ObjectPointer = createAndAddScopeChildren(Scope, *AbsDef))
addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
if (!ContextCU->includeMinimalInlineScopes())
ContextCU->addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined);
if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, *AbsDef))
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
}
DIE *DwarfCompileUnit::constructImportedEntityDIE(

View file

@ -283,7 +283,7 @@ class DwarfDebug : public DebugHandlerBase {
// 0, referencing the comp_dir of all the type units that use it.
MCDwarfDwoLineTable SplitTypeUnitFileTable;
/// @}
/// True iff there are multiple CUs in this module.
bool SingleCU;
bool IsDarwin;
@ -562,6 +562,9 @@ class DwarfDebug : public DebugHandlerBase {
bool isLexicalScopeDIENull(LexicalScope *Scope);
bool hasDwarfPubSections(bool includeMinimalInlineScopes) const;
/// Find the matching DwarfCompileUnit for the given CU DIE.
DwarfCompileUnit *lookupCU(const DIE *Die) { return CUDieMap.lookup(Die); }
};
} // End of namespace llvm

View file

@ -131,13 +131,12 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI,
// Intersection between the bits we already emitted and the bits
// covered by this subregister.
SmallBitVector Intersection(RegSize, false);
Intersection.set(Offset, Offset + Size);
Intersection ^= Coverage;
SmallBitVector CurSubReg(RegSize, false);
CurSubReg.set(Offset, Offset + Size);
// If this sub-register has a DWARF number and we haven't covered
// its range, emit a DWARF piece for it.
if (Reg >= 0 && Intersection.any()) {
if (Reg >= 0 && CurSubReg.test(Coverage)) {
// Emit a piece for any gap in the coverage.
if (Offset > CurPos)
DwarfRegs.push_back({-1, Offset - CurPos, nullptr});

View file

@ -269,8 +269,9 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) {
// may share super-registers. That's OK because createDeadDefs() is
// idempotent. It is very rare for a register unit to have multiple roots, so
// uniquing super-registers is probably not worthwhile.
bool IsReserved = true;
bool IsReserved = false;
for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) {
bool IsRootReserved = true;
for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true);
Super.isValid(); ++Super) {
unsigned Reg = *Super;
@ -279,9 +280,12 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) {
// A register unit is considered reserved if all its roots and all their
// super registers are reserved.
if (!MRI->isReserved(Reg))
IsReserved = false;
IsRootReserved = false;
}
IsReserved |= IsRootReserved;
}
assert(IsReserved == MRI->isReservedRegUnit(Unit) &&
"reserved computation mismatch");
// Now extend LR to reach all uses.
// Ignore uses of reserved registers. We only track defs of those.
@ -924,7 +928,7 @@ class LiveIntervals::HMEditor {
// kill flags. This is wasteful. Eventually, LiveVariables will strip all kill
// flags, and postRA passes will use a live register utility instead.
LiveRange *getRegUnitLI(unsigned Unit) {
if (UpdateFlags)
if (UpdateFlags && !MRI.isReservedRegUnit(Unit))
return &LIS.getRegUnit(Unit);
return LIS.getCachedRegUnit(Unit);
}

View file

@ -601,3 +601,21 @@ void MachineRegisterInfo::setCalleeSavedRegs(ArrayRef<MCPhysReg> CSRs) {
UpdatedCSRs.push_back(0);
IsUpdatedCSRsInitialized = true;
}
bool MachineRegisterInfo::isReservedRegUnit(unsigned Unit) const {
const TargetRegisterInfo *TRI = getTargetRegisterInfo();
for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) {
bool IsRootReserved = true;
for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true);
Super.isValid(); ++Super) {
unsigned Reg = *Super;
if (!isReserved(Reg)) {
IsRootReserved = false;
break;
}
}
if (IsRootReserved)
return true;
}
return false;
}

View file

@ -1316,6 +1316,8 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
// Check the cached regunit intervals.
if (TargetRegisterInfo::isPhysicalRegister(Reg) && !isReserved(Reg)) {
for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) {
if (MRI->isReservedRegUnit(*Units))
continue;
if (const LiveRange *LR = LiveInts->getCachedRegUnit(*Units))
checkLivenessAtUse(MO, MONum, UseIdx, *LR, *Units);
}

View file

@ -2271,6 +2271,24 @@ bool llvm::UpgradeModuleFlags(Module &M) {
}
}
}
// Upgrade Objective-C Image Info Section. Removed the whitespce in the
// section name so that llvm-lto will not complain about mismatching
// module flags that is functionally the same.
if (ID->getString() == "Objective-C Image Info Section") {
if (auto *Value = dyn_cast_or_null<MDString>(Op->getOperand(2))) {
SmallVector<StringRef, 4> ValueComp;
Value->getString().split(ValueComp, " ");
if (ValueComp.size() != 1) {
std::string NewValue;
for (auto &S : ValueComp)
NewValue += S.str();
Metadata *Ops[3] = {Op->getOperand(0), Op->getOperand(1),
MDString::get(M.getContext(), NewValue)};
ModFlags->setOperand(I, MDNode::get(M.getContext(), Ops));
Changed = true;
}
}
}
}
// "Objective-C Class Properties" is recently added for Objective-C. We
@ -2287,6 +2305,35 @@ bool llvm::UpgradeModuleFlags(Module &M) {
return Changed;
}
void llvm::UpgradeSectionAttributes(Module &M) {
auto TrimSpaces = [](StringRef Section) -> std::string {
SmallVector<StringRef, 5> Components;
Section.split(Components, ',');
SmallString<32> Buffer;
raw_svector_ostream OS(Buffer);
for (auto Component : Components)
OS << ',' << Component.trim();
return OS.str().substr(1);
};
for (auto &GV : M.globals()) {
if (!GV.hasSection())
continue;
StringRef Section = GV.getSection();
if (!Section.startswith("__DATA, __objc_catlist"))
continue;
// __DATA, __objc_catlist, regular, no_dead_strip
// __DATA,__objc_catlist,regular,no_dead_strip
GV.setSection(TrimSpaces(Section));
}
}
static bool isOldLoopArgument(Metadata *MD) {
auto *T = dyn_cast_or_null<MDTuple>(MD);
if (!T)

View file

@ -2199,6 +2199,9 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
Unknown = true;
continue;
}
if (!isa<ConstantInt>(Idxs[i - 1]))
// FIXME: add the support of cosntant vector index.
continue;
if (InRangeIndex && i == *InRangeIndex + 1) {
// If an index is marked inrange, we cannot apply this canonicalization to
// the following index, as that will cause the inrange index to point to

View file

@ -640,6 +640,10 @@ GlobalValue *IRLinker::copyGlobalValueProto(const GlobalValue *SGV,
} else {
if (ForDefinition)
NewGV = copyGlobalAliasProto(cast<GlobalAlias>(SGV));
else if (SGV->getValueType()->isFunctionTy())
NewGV =
Function::Create(cast<FunctionType>(TypeMap.get(SGV->getValueType())),
GlobalValue::ExternalLinkage, SGV->getName(), &DstM);
else
NewGV = new GlobalVariable(
DstM, TypeMap.get(SGV->getValueType()),

View file

@ -329,8 +329,18 @@ bool ModuleLinker::shouldLinkFromSource(bool &LinkFromSrc,
bool ModuleLinker::linkIfNeeded(GlobalValue &GV) {
GlobalValue *DGV = getLinkedToGlobal(&GV);
if (shouldLinkOnlyNeeded() && !(DGV && DGV->isDeclaration()))
return false;
if (shouldLinkOnlyNeeded()) {
// Always import variables with appending linkage.
if (!GV.hasAppendingLinkage()) {
// Don't import globals unless they are referenced by the destination
// module.
if (!DGV)
return false;
// Don't import globals that are already defined in the destination module
if (!DGV->isDeclaration())
return false;
}
}
if (DGV && !GV.hasLocalLinkage() && !GV.hasAppendingLinkage()) {
auto *DGVar = dyn_cast<GlobalVariable>(DGV);

View file

@ -208,6 +208,7 @@ StringRef sys::detail::getHostCPUNameForARM(
.Case("0x06f", "krait") // APQ8064
.Case("0x201", "kryo")
.Case("0x205", "kryo")
.Case("0xc00", "falkor")
.Default("generic");
return "generic";

View file

@ -220,27 +220,27 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
default:
return None;
case AArch64::LD1i8:
case AArch64::LD1i16:
case AArch64::LD1i32:
case AArch64::LD1i64:
case AArch64::LD2i8:
case AArch64::LD2i16:
case AArch64::LD2i32:
case AArch64::LD2i64:
case AArch64::LD3i8:
case AArch64::LD3i16:
case AArch64::LD3i32:
case AArch64::LD4i8:
case AArch64::LD4i16:
case AArch64::LD4i32:
DestRegIdx = 0;
BaseRegIdx = 3;
OffsetIdx = -1;
IsPrePost = false;
break;
case AArch64::LD1i8:
case AArch64::LD1i16:
case AArch64::LD1i32:
case AArch64::LD2i8:
case AArch64::LD2i16:
case AArch64::LD2i32:
case AArch64::LD3i8:
case AArch64::LD3i16:
case AArch64::LD3i32:
case AArch64::LD3i64:
case AArch64::LD4i8:
case AArch64::LD4i16:
case AArch64::LD4i32:
case AArch64::LD4i64:
DestRegIdx = -1;
BaseRegIdx = 3;
@ -264,23 +264,16 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
case AArch64::LD1Rv4s:
case AArch64::LD1Rv8h:
case AArch64::LD1Rv16b:
case AArch64::LD1Twov1d:
case AArch64::LD1Twov2s:
case AArch64::LD1Twov4h:
case AArch64::LD1Twov8b:
case AArch64::LD2Twov2s:
case AArch64::LD2Twov4s:
case AArch64::LD2Twov8b:
case AArch64::LD2Rv1d:
case AArch64::LD2Rv2s:
case AArch64::LD2Rv4s:
case AArch64::LD2Rv8b:
DestRegIdx = 0;
BaseRegIdx = 1;
OffsetIdx = -1;
IsPrePost = false;
break;
case AArch64::LD1Twov1d:
case AArch64::LD1Twov2s:
case AArch64::LD1Twov4h:
case AArch64::LD1Twov8b:
case AArch64::LD1Twov2d:
case AArch64::LD1Twov4s:
case AArch64::LD1Twov8h:
@ -301,10 +294,17 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
case AArch64::LD1Fourv4s:
case AArch64::LD1Fourv8h:
case AArch64::LD1Fourv16b:
case AArch64::LD2Twov2s:
case AArch64::LD2Twov4s:
case AArch64::LD2Twov8b:
case AArch64::LD2Twov2d:
case AArch64::LD2Twov4h:
case AArch64::LD2Twov8h:
case AArch64::LD2Twov16b:
case AArch64::LD2Rv1d:
case AArch64::LD2Rv2s:
case AArch64::LD2Rv4s:
case AArch64::LD2Rv8b:
case AArch64::LD2Rv2d:
case AArch64::LD2Rv4h:
case AArch64::LD2Rv8h:
@ -345,32 +345,32 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
IsPrePost = false;
break;
case AArch64::LD1i8_POST:
case AArch64::LD1i16_POST:
case AArch64::LD1i32_POST:
case AArch64::LD1i64_POST:
case AArch64::LD2i8_POST:
case AArch64::LD2i16_POST:
case AArch64::LD2i32_POST:
case AArch64::LD2i64_POST:
case AArch64::LD3i8_POST:
case AArch64::LD3i16_POST:
case AArch64::LD3i32_POST:
case AArch64::LD4i8_POST:
case AArch64::LD4i16_POST:
case AArch64::LD4i32_POST:
DestRegIdx = 1;
BaseRegIdx = 4;
OffsetIdx = 5;
IsPrePost = false;
IsPrePost = true;
break;
case AArch64::LD1i8_POST:
case AArch64::LD1i16_POST:
case AArch64::LD1i32_POST:
case AArch64::LD2i8_POST:
case AArch64::LD2i16_POST:
case AArch64::LD2i32_POST:
case AArch64::LD3i8_POST:
case AArch64::LD3i16_POST:
case AArch64::LD3i32_POST:
case AArch64::LD3i64_POST:
case AArch64::LD4i8_POST:
case AArch64::LD4i16_POST:
case AArch64::LD4i32_POST:
case AArch64::LD4i64_POST:
DestRegIdx = -1;
BaseRegIdx = 4;
OffsetIdx = 5;
IsPrePost = false;
IsPrePost = true;
break;
case AArch64::LD1Onev1d_POST:
@ -389,23 +389,16 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
case AArch64::LD1Rv4s_POST:
case AArch64::LD1Rv8h_POST:
case AArch64::LD1Rv16b_POST:
DestRegIdx = 1;
BaseRegIdx = 2;
OffsetIdx = 3;
IsPrePost = true;
break;
case AArch64::LD1Twov1d_POST:
case AArch64::LD1Twov2s_POST:
case AArch64::LD1Twov4h_POST:
case AArch64::LD1Twov8b_POST:
case AArch64::LD2Twov2s_POST:
case AArch64::LD2Twov4s_POST:
case AArch64::LD2Twov8b_POST:
case AArch64::LD2Rv1d_POST:
case AArch64::LD2Rv2s_POST:
case AArch64::LD2Rv4s_POST:
case AArch64::LD2Rv8b_POST:
DestRegIdx = 1;
BaseRegIdx = 2;
OffsetIdx = 3;
IsPrePost = false;
break;
case AArch64::LD1Twov2d_POST:
case AArch64::LD1Twov4s_POST:
case AArch64::LD1Twov8h_POST:
@ -426,10 +419,17 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
case AArch64::LD1Fourv4s_POST:
case AArch64::LD1Fourv8h_POST:
case AArch64::LD1Fourv16b_POST:
case AArch64::LD2Twov2s_POST:
case AArch64::LD2Twov4s_POST:
case AArch64::LD2Twov8b_POST:
case AArch64::LD2Twov2d_POST:
case AArch64::LD2Twov4h_POST:
case AArch64::LD2Twov8h_POST:
case AArch64::LD2Twov16b_POST:
case AArch64::LD2Rv1d_POST:
case AArch64::LD2Rv2s_POST:
case AArch64::LD2Rv4s_POST:
case AArch64::LD2Rv8b_POST:
case AArch64::LD2Rv2d_POST:
case AArch64::LD2Rv4h_POST:
case AArch64::LD2Rv8h_POST:
@ -467,7 +467,7 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
DestRegIdx = -1;
BaseRegIdx = 2;
OffsetIdx = 3;
IsPrePost = false;
IsPrePost = true;
break;
case AArch64::LDRBBroW:
@ -572,8 +572,12 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
IsPrePost = true;
break;
case AArch64::LDPDi:
case AArch64::LDNPDi:
case AArch64::LDNPQi:
case AArch64::LDNPSi:
case AArch64::LDPQi:
case AArch64::LDPDi:
case AArch64::LDPSi:
DestRegIdx = -1;
BaseRegIdx = 2;
OffsetIdx = 3;
@ -581,7 +585,6 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
break;
case AArch64::LDPSWi:
case AArch64::LDPSi:
case AArch64::LDPWi:
case AArch64::LDPXi:
DestRegIdx = 0;
@ -592,18 +595,18 @@ static Optional<LoadInfo> getLoadInfo(const MachineInstr &MI) {
case AArch64::LDPQpost:
case AArch64::LDPQpre:
case AArch64::LDPDpost:
case AArch64::LDPDpre:
case AArch64::LDPSpost:
case AArch64::LDPSpre:
DestRegIdx = -1;
BaseRegIdx = 3;
OffsetIdx = 4;
IsPrePost = true;
break;
case AArch64::LDPDpost:
case AArch64::LDPDpre:
case AArch64::LDPSWpost:
case AArch64::LDPSWpre:
case AArch64::LDPSpost:
case AArch64::LDPSpre:
case AArch64::LDPWpost:
case AArch64::LDPWpre:
case AArch64::LDPXpost:
@ -687,9 +690,14 @@ void FalkorHWPFFix::runOnLoop(MachineLoop &L, MachineFunction &Fn) {
if (!TII->isStridedAccess(MI))
continue;
LoadInfo LdI = *getLoadInfo(MI);
unsigned OldTag = *getTag(TRI, MI, LdI);
auto &OldCollisions = TagMap[OldTag];
Optional<LoadInfo> OptLdI = getLoadInfo(MI);
if (!OptLdI)
continue;
LoadInfo LdI = *OptLdI;
Optional<unsigned> OptOldTag = getTag(TRI, MI, LdI);
if (!OptOldTag)
continue;
auto &OldCollisions = TagMap[*OptOldTag];
if (OldCollisions.size() <= 1)
continue;

View file

@ -9347,11 +9347,20 @@ static SDValue replaceZeroVectorStore(SelectionDAG &DAG, StoreSDNode &St) {
return SDValue();
}
// Use WZR/XZR here to prevent DAGCombiner::MergeConsecutiveStores from
// undoing this transformation.
SDValue SplatVal = VT.getVectorElementType().getSizeInBits() == 32
? DAG.getRegister(AArch64::WZR, MVT::i32)
: DAG.getRegister(AArch64::XZR, MVT::i64);
// Use a CopyFromReg WZR/XZR here to prevent
// DAGCombiner::MergeConsecutiveStores from undoing this transformation.
SDLoc DL(&St);
unsigned ZeroReg;
EVT ZeroVT;
if (VT.getVectorElementType().getSizeInBits() == 32) {
ZeroReg = AArch64::WZR;
ZeroVT = MVT::i32;
} else {
ZeroReg = AArch64::XZR;
ZeroVT = MVT::i64;
}
SDValue SplatVal =
DAG.getCopyFromReg(DAG.getEntryNode(), DL, ZeroReg, ZeroVT);
return splitStoreSplat(DAG, St, SplatVal, NumVecElts);
}

View file

@ -940,6 +940,12 @@ bool AArch64InstrInfo::areMemAccessesTriviallyDisjoint(
bool AArch64InstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
unsigned &SrcReg2, int &CmpMask,
int &CmpValue) const {
// The first operand can be a frame index where we'd normally expect a
// register.
assert(MI.getNumOperands() >= 2 && "All AArch64 cmps should have 2 operands");
if (!MI.getOperand(1).isReg())
return false;
switch (MI.getOpcode()) {
default:
break;

View file

@ -441,8 +441,7 @@ def MSRpstateImm1 : MSRpstateImm0_1;
def MSRpstateImm4 : MSRpstateImm0_15;
// The thread pointer (on Linux, at least, where this has been implemented) is
// TPIDR_EL0. Add pseudo op so we can mark it as not having any side effects.
let hasSideEffects = 0 in
// TPIDR_EL0.
def MOVbaseTLS : Pseudo<(outs GPR64:$dst), (ins),
[(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>;

View file

@ -167,6 +167,9 @@ AArch64RedundantCopyElimination::knownRegValInBlock(
// CMP is an alias for SUBS with a dead destination register.
case AArch64::SUBSWri:
case AArch64::SUBSXri: {
// Sometimes the first operand is a FrameIndex. Bail if tht happens.
if (!PredI.getOperand(1).isReg())
return None;
MCPhysReg SrcReg = PredI.getOperand(1).getReg();
// Must not be a symbolic immediate.

View file

@ -218,12 +218,17 @@ void GCNHazardRecognizer::RecedeCycle() {
int GCNHazardRecognizer::getWaitStatesSince(
function_ref<bool(MachineInstr *)> IsHazard) {
int WaitStates = -1;
int WaitStates = 0;
for (MachineInstr *MI : EmittedInstrs) {
if (MI) {
if (IsHazard(MI))
return WaitStates;
unsigned Opcode = MI->getOpcode();
if (Opcode == AMDGPU::DBG_VALUE || Opcode == AMDGPU::IMPLICIT_DEF)
continue;
}
++WaitStates;
if (!MI || !IsHazard(MI))
continue;
return WaitStates;
}
return std::numeric_limits<int>::max();
}

View file

@ -1276,6 +1276,7 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
// Add 's' bit operand (always reg0 for this)
.addReg(0));
assert(Subtarget->hasV4TOps());
EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::BX)
.addReg(MI->getOperand(0).getReg()));
return;
@ -1896,6 +1897,7 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addImm(ARMCC::AL)
.addReg(0));
assert(Subtarget->hasV4TOps());
EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::BX)
.addReg(ScratchReg)
// Predicate.

View file

@ -251,7 +251,9 @@ bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val, unsigned VReg) const {
assert(!Val == !VReg && "Return value without a vreg");
auto Ret = MIRBuilder.buildInstrNoInsert(ARM::BX_RET).add(predOps(ARMCC::AL));
auto const &ST = MIRBuilder.getMF().getSubtarget<ARMSubtarget>();
unsigned Opcode = ST.getReturnOpcode();
auto Ret = MIRBuilder.buildInstrNoInsert(Opcode).add(predOps(ARMCC::AL));
if (!lowerReturnVal(MIRBuilder, Val, VReg, Ret))
return false;

View file

@ -1030,8 +1030,11 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
if (STI->isThumb())
MIB.add(predOps(ARMCC::AL));
} else if (RetOpcode == ARM::TCRETURNri) {
unsigned Opcode =
STI->isThumb() ? ARM::tTAILJMPr
: (STI->hasV4TOps() ? ARM::TAILJMPr : ARM::TAILJMPr4);
BuildMI(MBB, MBBI, dl,
TII.get(STI->isThumb() ? ARM::tTAILJMPr : ARM::TAILJMPr))
TII.get(Opcode))
.addReg(JumpTarget.getReg(), RegState::Kill);
}

View file

@ -1332,6 +1332,8 @@ bool ARMFastISel::SelectIndirectBr(const Instruction *I) {
if (AddrReg == 0) return false;
unsigned Opc = isThumb2 ? ARM::tBRIND : ARM::BX;
assert(isThumb2 || Subtarget->hasV4TOps());
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(Opc)).addReg(AddrReg));
@ -2168,9 +2170,8 @@ bool ARMFastISel::SelectRet(const Instruction *I) {
RetRegs.push_back(VA.getLocReg());
}
unsigned RetOpc = isThumb2 ? ARM::tBX_RET : ARM::BX_RET;
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(RetOpc));
TII.get(Subtarget->getReturnOpcode()));
AddOptionalDefs(MIB);
for (unsigned R : RetRegs)
MIB.addReg(R, RegState::Implicit);

View file

@ -479,7 +479,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
if (DPRCSSize > 0) {
// Since vpush register list cannot have gaps, there may be multiple vpush
// instructions in the prologue.
while (MBBI->getOpcode() == ARM::VSTMDDB_UPD) {
while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::VSTMDDB_UPD) {
DefCFAOffsetCandidates.addInst(MBBI, sizeOfSPAdjustment(*MBBI));
LastPush = MBBI++;
}
@ -2397,9 +2397,8 @@ void ARMFrameLowering::adjustForSegmentedStacks(
BuildMI(AllocMBB, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// bx lr - Return from this function.
Opcode = Thumb ? ARM::tBX_RET : ARM::BX_RET;
BuildMI(AllocMBB, DL, TII.get(Opcode)).add(predOps(ARMCC::AL));
// Return from this function.
BuildMI(AllocMBB, DL, TII.get(ST->getReturnOpcode())).add(predOps(ARMCC::AL));
// Restore SR0 and SR1 in case of __morestack() was not called.
// pop {SR0, SR1}

View file

@ -2425,7 +2425,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in {
def TAILJMPr : ARMPseudoExpand<(outs), (ins tcGPR:$dst),
4, IIC_Br, [],
(BX GPR:$dst)>, Sched<[WriteBr]>,
Requires<[IsARM]>;
Requires<[IsARM, HasV4T]>;
}
// Secure Monitor Call is a system instruction.
@ -5589,6 +5589,12 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in
(MOVr PC, GPR:$dst, (ops 14, zero_reg), zero_reg)>,
Requires<[IsARM, NoV4T]>, Sched<[WriteBr]>;
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in
def TAILJMPr4 : ARMPseudoExpand<(outs), (ins GPR:$dst),
4, IIC_Br, [],
(MOVr PC, GPR:$dst, (ops 14, zero_reg), zero_reg)>,
Requires<[IsARM, NoV4T]>, Sched<[WriteBr]>;
// Large immediate handling.
// 32-bit immediate using two piece mod_imms or movw + movt.

View file

@ -1909,6 +1909,7 @@ bool ARMLoadStoreOpt::CombineMovBx(MachineBasicBlock &MBB) {
for (auto Use : Prev->uses())
if (Use.isKill()) {
assert(STI->hasV4TOps());
BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(ARM::tBX))
.addReg(Use.getReg(), RegState::Kill)
.add(predOps(ARMCC::AL))

View file

@ -729,6 +729,17 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
/// True if fast-isel is used.
bool useFastISel() const;
/// Returns the correct return opcode for the current feature set.
/// Use BX if available to allow mixing thumb/arm code, but fall back
/// to plain mov pc,lr on ARMv4.
unsigned getReturnOpcode() const {
if (isThumb())
return ARM::tBX_RET;
if (hasV4TOps())
return ARM::BX_RET;
return ARM::MOVPCLR;
}
};
} // end namespace llvm

View file

@ -142,9 +142,9 @@ std::string ARM_MC::ParseARMTriple(const Triple &TT, StringRef CPU) {
if (isThumb) {
if (ARMArchFeature.empty())
ARMArchFeature = "+thumb-mode";
ARMArchFeature = "+thumb-mode,+v4t";
else
ARMArchFeature += ",+thumb-mode";
ARMArchFeature += ",+thumb-mode,+v4t";
}
if (TT.isOSNaCl()) {

View file

@ -583,8 +583,8 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
unsigned TmpReg = 0; // 0 for no temporary register
unsigned SrcReg = MI.getOperand(1).getReg();
bool SrcIsKill = MI.getOperand(1).isKill();
OpLo = AVR::LDRdPtr;
OpHi = AVR::LDDRdPtrQ;
OpLo = AVR::LDRdPtrPi;
OpHi = AVR::LDRdPtr;
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
// Use a temporary register if src and dst registers are the same.
@ -597,6 +597,7 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
// Load low byte.
auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(CurDstLoReg, RegState::Define)
.addReg(SrcReg, RegState::Define)
.addReg(SrcReg);
// Push low byte onto stack if necessary.
@ -606,8 +607,7 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {
// Load high byte.
auto MIBHI = buildMI(MBB, MBBI, OpHi)
.addReg(CurDstHiReg, RegState::Define)
.addReg(SrcReg, getKillRegState(SrcIsKill))
.addImm(1);
.addReg(SrcReg, getKillRegState(SrcIsKill));
if (TmpReg) {
// Move the high byte into the final destination.
@ -699,7 +699,9 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
OpHi = AVR::LDDRdPtrQ;
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
assert(Imm <= 63 && "Offset is out of range");
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
// allowed for the instruction, 62 is the limit here.
assert(Imm <= 62 && "Offset is out of range");
// Use a temporary register if src and dst registers are the same.
if (DstReg == SrcReg)
@ -741,7 +743,50 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
template <>
bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
llvm_unreachable("wide LPM is unimplemented");
MachineInstr &MI = *MBBI;
unsigned OpLo, OpHi, DstLoReg, DstHiReg;
unsigned DstReg = MI.getOperand(0).getReg();
unsigned TmpReg = 0; // 0 for no temporary register
unsigned SrcReg = MI.getOperand(1).getReg();
bool SrcIsKill = MI.getOperand(1).isKill();
OpLo = AVR::LPMRdZPi;
OpHi = AVR::LPMRdZ;
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
// Use a temporary register if src and dst registers are the same.
if (DstReg == SrcReg)
TmpReg = scavengeGPR8(MI);
unsigned CurDstLoReg = (DstReg == SrcReg) ? TmpReg : DstLoReg;
unsigned CurDstHiReg = (DstReg == SrcReg) ? TmpReg : DstHiReg;
// Load low byte.
auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(CurDstLoReg, RegState::Define)
.addReg(SrcReg);
// Push low byte onto stack if necessary.
if (TmpReg)
buildMI(MBB, MBBI, AVR::PUSHRr).addReg(TmpReg);
// Load high byte.
auto MIBHI = buildMI(MBB, MBBI, OpHi)
.addReg(CurDstHiReg, RegState::Define)
.addReg(SrcReg, getKillRegState(SrcIsKill));
if (TmpReg) {
// Move the high byte into the final destination.
buildMI(MBB, MBBI, AVR::MOVRdRr).addReg(DstHiReg).addReg(TmpReg);
// Move the low byte from the scratch space into the final destination.
buildMI(MBB, MBBI, AVR::POPRd).addReg(DstLoReg);
}
MIBLO->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
MIBHI->setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
MI.eraseFromParent();
return true;
}
template <>
@ -1074,7 +1119,9 @@ bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
OpHi = AVR::STDPtrQRr;
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
assert(Imm <= 63 && "Offset is out of range");
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
// allowed for the instruction, 62 is the limit here.
assert(Imm <= 62 && "Offset is out of range");
auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(DstReg)
@ -1104,7 +1151,9 @@ bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
OpHi = AVR::INRdA;
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
assert(Imm <= 63 && "Address is out of range");
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
// allowed for the instruction, 62 is the limit here.
assert(Imm <= 62 && "Address is out of range");
auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
@ -1132,7 +1181,9 @@ bool AVRExpandPseudo::expand<AVR::OUTWARr>(Block &MBB, BlockIt MBBI) {
OpHi = AVR::OUTARr;
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
assert(Imm <= 63 && "Address is out of range");
// Since we add 1 to the Imm value for the high byte below, and 63 is the highest Imm value
// allowed for the instruction, 62 is the limit here.
assert(Imm <= 62 && "Address is out of range");
// 16 bit I/O writes need the high byte first
auto MIBHI = buildMI(MBB, MBBI, OpHi)

View file

@ -1469,8 +1469,10 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
}
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction::iterator I = BB->getParent()->begin();
++I;
MachineFunction::iterator I;
for (I = F->begin(); I != F->end() && &(*I) != BB; ++I);
if (I != F->end()) ++I;
// Create loop block.
MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);

View file

@ -75,6 +75,11 @@ class AVRTargetLowering : public TargetLowering {
MVT getScalarShiftAmountTy(const DataLayout &, EVT LHSTy) const override {
return MVT::i8;
}
MVT::SimpleValueType getCmpLibcallReturnType() const override {
return MVT::i8;
}
const char *getTargetNodeName(unsigned Opcode) const override;
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;

View file

@ -537,8 +537,7 @@ bool AVRInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
llvm_unreachable("unexpected opcode!");
case AVR::JMPk:
case AVR::CALLk:
assert(BrOffset >= 0 && "offset must be absolute address");
return isUIntN(16, BrOffset);
return true;
case AVR::RCALLk:
case AVR::RJMPk:
return isIntN(13, BrOffset);
@ -556,5 +555,20 @@ bool AVRInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
}
}
unsigned AVRInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
MachineBasicBlock &NewDestBB,
const DebugLoc &DL,
int64_t BrOffset,
RegScavenger *RS) const {
// This method inserts a *direct* branch (JMP), despite its name.
// LLVM calls this method to fixup unconditional branches; it never calls
// insertBranch or some hypothetical "insertDirectBranch".
// See lib/CodeGen/RegisterRelaxation.cpp for details.
// We end up here when a jump is too long for a RJMP instruction.
auto &MI = *BuildMI(&MBB, DL, get(AVR::JMPk)).addMBB(&NewDestBB);
return getInstSizeInBytes(MI);
}
} // end of namespace llvm

View file

@ -107,6 +107,12 @@ class AVRInstrInfo : public AVRGenInstrInfo {
bool isBranchOffsetInRange(unsigned BranchOpc,
int64_t BrOffset) const override;
unsigned insertIndirectBranch(MachineBasicBlock &MBB,
MachineBasicBlock &NewDestBB,
const DebugLoc &DL,
int64_t BrOffset,
RegScavenger *RS) const override;
private:
const AVRRegisterInfo RI;
};

View file

@ -1152,10 +1152,10 @@ isReMaterializable = 1 in
//
// Expands to:
// ld Rd, P+
// ld Rd+1, P+
// ld Rd+1, P
let Constraints = "@earlyclobber $reg" in
def LDWRdPtr : Pseudo<(outs DREGS:$reg),
(ins PTRDISPREGS:$ptrreg),
(ins PTRREGS:$ptrreg),
"ldw\t$reg, $ptrreg",
[(set i16:$reg, (load i16:$ptrreg))]>,
Requires<[HasSRAM]>;
@ -1164,7 +1164,7 @@ isReMaterializable = 1 in
// Indirect loads (with postincrement or predecrement).
let mayLoad = 1,
hasSideEffects = 0,
Constraints = "$ptrreg = $base_wb,@earlyclobber $reg,@earlyclobber $base_wb" in
Constraints = "$ptrreg = $base_wb,@earlyclobber $reg" in
{
def LDRdPtrPi : FSTLD<0,
0b01,
@ -1238,35 +1238,55 @@ isReMaterializable = 1 in
Requires<[HasSRAM]>;
}
class AtomicLoad<PatFrag Op, RegisterClass DRC> :
Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr), "atomic_op",
class AtomicLoad<PatFrag Op, RegisterClass DRC,
RegisterClass PTRRC> :
Pseudo<(outs DRC:$rd), (ins PTRRC:$rr), "atomic_op",
[(set DRC:$rd, (Op i16:$rr))]>;
class AtomicStore<PatFrag Op, RegisterClass DRC> :
Pseudo<(outs), (ins PTRDISPREGS:$rd, DRC:$rr), "atomic_op",
class AtomicStore<PatFrag Op, RegisterClass DRC,
RegisterClass PTRRC> :
Pseudo<(outs), (ins PTRRC:$rd, DRC:$rr), "atomic_op",
[(Op i16:$rd, DRC:$rr)]>;
class AtomicLoadOp<PatFrag Op, RegisterClass DRC> :
Pseudo<(outs DRC:$rd), (ins PTRREGS:$rr, DRC:$operand),
class AtomicLoadOp<PatFrag Op, RegisterClass DRC,
RegisterClass PTRRC> :
Pseudo<(outs DRC:$rd), (ins PTRRC:$rr, DRC:$operand),
"atomic_op",
[(set DRC:$rd, (Op i16:$rr, DRC:$operand))]>;
def AtomicLoad8 : AtomicLoad<atomic_load_8, GPR8>;
def AtomicLoad16 : AtomicLoad<atomic_load_16, DREGS>;
// FIXME: I think 16-bit atomic binary ops need to mark
// r0 as clobbered.
def AtomicStore8 : AtomicStore<atomic_store_8, GPR8>;
def AtomicStore16 : AtomicStore<atomic_store_16, DREGS>;
// Atomic instructions
// ===================
//
// These are all expanded by AVRExpandPseudoInsts
//
// 8-bit operations can use any pointer register because
// they are expanded directly into an LD/ST instruction.
//
// 16-bit operations use 16-bit load/store postincrement instructions,
// which require PTRDISPREGS.
def AtomicLoadAdd8 : AtomicLoadOp<atomic_load_add_8, GPR8>;
def AtomicLoadAdd16 : AtomicLoadOp<atomic_load_add_16, DREGS>;
def AtomicLoadSub8 : AtomicLoadOp<atomic_load_sub_8, GPR8>;
def AtomicLoadSub16 : AtomicLoadOp<atomic_load_sub_16, DREGS>;
def AtomicLoadAnd8 : AtomicLoadOp<atomic_load_and_8, GPR8>;
def AtomicLoadAnd16 : AtomicLoadOp<atomic_load_and_16, DREGS>;
def AtomicLoadOr8 : AtomicLoadOp<atomic_load_or_8, GPR8>;
def AtomicLoadOr16 : AtomicLoadOp<atomic_load_or_16, DREGS>;
def AtomicLoadXor8 : AtomicLoadOp<atomic_load_xor_8, GPR8>;
def AtomicLoadXor16 : AtomicLoadOp<atomic_load_xor_16, DREGS>;
def AtomicLoad8 : AtomicLoad<atomic_load_8, GPR8, PTRREGS>;
def AtomicLoad16 : AtomicLoad<atomic_load_16, DREGS, PTRDISPREGS>;
def AtomicStore8 : AtomicStore<atomic_store_8, GPR8, PTRREGS>;
def AtomicStore16 : AtomicStore<atomic_store_16, DREGS, PTRDISPREGS>;
class AtomicLoadOp8<PatFrag Op> : AtomicLoadOp<Op, GPR8, PTRREGS>;
class AtomicLoadOp16<PatFrag Op> : AtomicLoadOp<Op, DREGS, PTRDISPREGS>;
def AtomicLoadAdd8 : AtomicLoadOp8<atomic_load_add_8>;
def AtomicLoadAdd16 : AtomicLoadOp16<atomic_load_add_16>;
def AtomicLoadSub8 : AtomicLoadOp8<atomic_load_sub_8>;
def AtomicLoadSub16 : AtomicLoadOp16<atomic_load_sub_16>;
def AtomicLoadAnd8 : AtomicLoadOp8<atomic_load_and_8>;
def AtomicLoadAnd16 : AtomicLoadOp16<atomic_load_and_16>;
def AtomicLoadOr8 : AtomicLoadOp8<atomic_load_or_8>;
def AtomicLoadOr16 : AtomicLoadOp16<atomic_load_or_16>;
def AtomicLoadXor8 : AtomicLoadOp8<atomic_load_xor_8>;
def AtomicLoadXor16 : AtomicLoadOp16<atomic_load_xor_16>;
def AtomicFence : Pseudo<(outs), (ins), "atomic_fence",
[(atomic_fence imm, imm)]>;
@ -1397,6 +1417,7 @@ def STDWPtrQRr : Pseudo<(outs),
// Load program memory operations.
let canFoldAsLoad = 1,
isReMaterializable = 1,
mayLoad = 1,
hasSideEffects = 0 in
{
let Defs = [R0],
@ -1417,8 +1438,7 @@ hasSideEffects = 0 in
Requires<[HasLPMX]>;
// Load program memory, while postincrementing the Z register.
let mayLoad = 1,
Defs = [R31R30] in
let Defs = [R31R30] in
{
def LPMRdZPi : FLPMX<0,
1,

View file

@ -203,7 +203,7 @@ void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
// If the offset is too big we have to adjust and restore the frame pointer
// to materialize a valid load/store with displacement.
//:TODO: consider using only one adiw/sbiw chain for more than one frame index
if (Offset > 63) {
if (Offset > 62) {
unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK;
int AddOffset = Offset - 63 + 1;

View file

@ -25,7 +25,7 @@
namespace llvm {
static const char *AVRDataLayout = "e-p:16:16:16-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-n8";
static const char *AVRDataLayout = "e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8";
/// Processes a CPU name.
static StringRef getCPU(StringRef CPU) {

View file

@ -13,6 +13,8 @@
#include "AVRTargetStreamer.h"
#include "llvm/MC/MCContext.h"
namespace llvm {
AVRTargetStreamer::AVRTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
@ -20,5 +22,23 @@ AVRTargetStreamer::AVRTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
AVRTargetAsmStreamer::AVRTargetAsmStreamer(MCStreamer &S)
: AVRTargetStreamer(S) {}
void AVRTargetStreamer::finish() {
MCStreamer &OS = getStreamer();
MCContext &Context = OS.getContext();
MCSymbol *DoCopyData = Context.getOrCreateSymbol("__do_copy_data");
MCSymbol *DoClearBss = Context.getOrCreateSymbol("__do_clear_bss");
// FIXME: We can disable __do_copy_data if there are no static RAM variables.
OS.emitRawComment(" Declaring this symbol tells the CRT that it should");
OS.emitRawComment("copy all variables from program memory to RAM on startup");
OS.EmitSymbolAttribute(DoCopyData, MCSA_Global);
OS.emitRawComment(" Declaring this symbol tells the CRT that it should");
OS.emitRawComment("clear the zeroed data section on startup");
OS.EmitSymbolAttribute(DoClearBss, MCSA_Global);
}
} // end namespace llvm

View file

@ -19,6 +19,8 @@ class MCStreamer;
class AVRTargetStreamer : public MCTargetStreamer {
public:
explicit AVRTargetStreamer(MCStreamer &S);
void finish() override;
};
/// A target streamer for textual AVR assembly code.

View file

@ -304,6 +304,9 @@ class MipsAsmParser : public MCTargetAsmParser {
bool expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
bool expandMXTRAlias(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI);
bool reportParseError(Twine ErrorMsg);
bool reportParseError(SMLoc Loc, Twine ErrorMsg);
@ -2511,6 +2514,16 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return expandSeq(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::SEQIMacro:
return expandSeqI(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
case Mips::MFTC0: case Mips::MTTC0:
case Mips::MFTGPR: case Mips::MTTGPR:
case Mips::MFTLO: case Mips::MTTLO:
case Mips::MFTHI: case Mips::MTTHI:
case Mips::MFTACX: case Mips::MTTACX:
case Mips::MFTDSP: case Mips::MTTDSP:
case Mips::MFTC1: case Mips::MTTC1:
case Mips::MFTHC1: case Mips::MTTHC1:
case Mips::CFTC1: case Mips::CTTC1:
return expandMXTRAlias(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;
}
}
@ -4882,6 +4895,212 @@ bool MipsAsmParser::expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
return false;
}
// Map the DSP accumulator and control register to the corresponding gpr
// operand. Unlike the other alias, the m(f|t)t(lo|hi|acx) instructions
// do not map the DSP registers contigously to gpr registers.
static unsigned getRegisterForMxtrDSP(MCInst &Inst, bool IsMFDSP) {
switch (Inst.getOpcode()) {
case Mips::MFTLO:
case Mips::MTTLO:
switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) {
case Mips::AC0:
return Mips::ZERO;
case Mips::AC1:
return Mips::A0;
case Mips::AC2:
return Mips::T0;
case Mips::AC3:
return Mips::T4;
default:
llvm_unreachable("Unknown register for 'mttr' alias!");
}
case Mips::MFTHI:
case Mips::MTTHI:
switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) {
case Mips::AC0:
return Mips::AT;
case Mips::AC1:
return Mips::A1;
case Mips::AC2:
return Mips::T1;
case Mips::AC3:
return Mips::T5;
default:
llvm_unreachable("Unknown register for 'mttr' alias!");
}
case Mips::MFTACX:
case Mips::MTTACX:
switch (Inst.getOperand(IsMFDSP ? 1 : 0).getReg()) {
case Mips::AC0:
return Mips::V0;
case Mips::AC1:
return Mips::A2;
case Mips::AC2:
return Mips::T2;
case Mips::AC3:
return Mips::T6;
default:
llvm_unreachable("Unknown register for 'mttr' alias!");
}
case Mips::MFTDSP:
case Mips::MTTDSP:
return Mips::S0;
default:
llvm_unreachable("Unknown instruction for 'mttr' dsp alias!");
}
}
// Map the floating point register operand to the corresponding register
// operand.
static unsigned getRegisterForMxtrFP(MCInst &Inst, bool IsMFTC1) {
switch (Inst.getOperand(IsMFTC1 ? 1 : 0).getReg()) {
case Mips::F0: return Mips::ZERO;
case Mips::F1: return Mips::AT;
case Mips::F2: return Mips::V0;
case Mips::F3: return Mips::V1;
case Mips::F4: return Mips::A0;
case Mips::F5: return Mips::A1;
case Mips::F6: return Mips::A2;
case Mips::F7: return Mips::A3;
case Mips::F8: return Mips::T0;
case Mips::F9: return Mips::T1;
case Mips::F10: return Mips::T2;
case Mips::F11: return Mips::T3;
case Mips::F12: return Mips::T4;
case Mips::F13: return Mips::T5;
case Mips::F14: return Mips::T6;
case Mips::F15: return Mips::T7;
case Mips::F16: return Mips::S0;
case Mips::F17: return Mips::S1;
case Mips::F18: return Mips::S2;
case Mips::F19: return Mips::S3;
case Mips::F20: return Mips::S4;
case Mips::F21: return Mips::S5;
case Mips::F22: return Mips::S6;
case Mips::F23: return Mips::S7;
case Mips::F24: return Mips::T8;
case Mips::F25: return Mips::T9;
case Mips::F26: return Mips::K0;
case Mips::F27: return Mips::K1;
case Mips::F28: return Mips::GP;
case Mips::F29: return Mips::SP;
case Mips::F30: return Mips::FP;
case Mips::F31: return Mips::RA;
default: llvm_unreachable("Unknown register for mttc1 alias!");
}
}
// Map the coprocessor operand the corresponding gpr register operand.
static unsigned getRegisterForMxtrC0(MCInst &Inst, bool IsMFTC0) {
switch (Inst.getOperand(IsMFTC0 ? 1 : 0).getReg()) {
case Mips::COP00: return Mips::ZERO;
case Mips::COP01: return Mips::AT;
case Mips::COP02: return Mips::V0;
case Mips::COP03: return Mips::V1;
case Mips::COP04: return Mips::A0;
case Mips::COP05: return Mips::A1;
case Mips::COP06: return Mips::A2;
case Mips::COP07: return Mips::A3;
case Mips::COP08: return Mips::T0;
case Mips::COP09: return Mips::T1;
case Mips::COP010: return Mips::T2;
case Mips::COP011: return Mips::T3;
case Mips::COP012: return Mips::T4;
case Mips::COP013: return Mips::T5;
case Mips::COP014: return Mips::T6;
case Mips::COP015: return Mips::T7;
case Mips::COP016: return Mips::S0;
case Mips::COP017: return Mips::S1;
case Mips::COP018: return Mips::S2;
case Mips::COP019: return Mips::S3;
case Mips::COP020: return Mips::S4;
case Mips::COP021: return Mips::S5;
case Mips::COP022: return Mips::S6;
case Mips::COP023: return Mips::S7;
case Mips::COP024: return Mips::T8;
case Mips::COP025: return Mips::T9;
case Mips::COP026: return Mips::K0;
case Mips::COP027: return Mips::K1;
case Mips::COP028: return Mips::GP;
case Mips::COP029: return Mips::SP;
case Mips::COP030: return Mips::FP;
case Mips::COP031: return Mips::RA;
default: llvm_unreachable("Unknown register for mttc0 alias!");
}
}
/// Expand an alias of 'mftr' or 'mttr' into the full instruction, by producing
/// an mftr or mttr with the correctly mapped gpr register, u, sel and h bits.
bool MipsAsmParser::expandMXTRAlias(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
const MCSubtargetInfo *STI) {
MipsTargetStreamer &TOut = getTargetStreamer();
unsigned rd = 0;
unsigned u = 1;
unsigned sel = 0;
unsigned h = 0;
bool IsMFTR = false;
switch (Inst.getOpcode()) {
case Mips::MFTC0:
IsMFTR = true;
LLVM_FALLTHROUGH;
case Mips::MTTC0:
u = 0;
rd = getRegisterForMxtrC0(Inst, IsMFTR);
sel = Inst.getOperand(2).getImm();
break;
case Mips::MFTGPR:
IsMFTR = true;
LLVM_FALLTHROUGH;
case Mips::MTTGPR:
rd = Inst.getOperand(IsMFTR ? 1 : 0).getReg();
break;
case Mips::MFTLO:
case Mips::MFTHI:
case Mips::MFTACX:
case Mips::MFTDSP:
IsMFTR = true;
LLVM_FALLTHROUGH;
case Mips::MTTLO:
case Mips::MTTHI:
case Mips::MTTACX:
case Mips::MTTDSP:
rd = getRegisterForMxtrDSP(Inst, IsMFTR);
sel = 1;
break;
case Mips::MFTHC1:
h = 1;
LLVM_FALLTHROUGH;
case Mips::MFTC1:
IsMFTR = true;
rd = getRegisterForMxtrFP(Inst, IsMFTR);
sel = 2;
break;
case Mips::MTTHC1:
h = 1;
LLVM_FALLTHROUGH;
case Mips::MTTC1:
rd = getRegisterForMxtrFP(Inst, IsMFTR);
sel = 2;
break;
case Mips::CFTC1:
IsMFTR = true;
LLVM_FALLTHROUGH;
case Mips::CTTC1:
rd = getRegisterForMxtrFP(Inst, IsMFTR);
sel = 3;
break;
}
unsigned Op0 = IsMFTR ? Inst.getOperand(0).getReg() : rd;
unsigned Op1 =
IsMFTR ? rd
: (Inst.getOpcode() != Mips::MTTDSP ? Inst.getOperand(1).getReg()
: Inst.getOperand(0).getReg());
TOut.emitRRIII(IsMFTR ? Mips::MFTR : Mips::MTTR, Op0, Op1, u, sel, h, IDLoc,
STI);
return false;
}
unsigned
MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst,
const OperandVector &Operands) {
@ -5793,14 +6012,21 @@ OperandMatchResultTy
MipsAsmParser::parseInvNum(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
const MCExpr *IdVal;
// If the first token is '$' we may have register operand.
if (Parser.getTok().is(AsmToken::Dollar))
return MatchOperand_NoMatch;
// If the first token is '$' we may have register operand. We have to reject
// cases where it is not a register. Complicating the matter is that
// register names are not reserved across all ABIs.
// Peek past the dollar to see if it's a register name for this ABI.
SMLoc S = Parser.getTok().getLoc();
if (Parser.getTok().is(AsmToken::Dollar)) {
return matchCPURegisterName(Parser.getLexer().peekTok().getString()) == -1
? MatchOperand_ParseFail
: MatchOperand_NoMatch;
}
if (getParser().parseExpression(IdVal))
return MatchOperand_ParseFail;
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal);
assert(MCE && "Unexpected MCExpr type.");
if (!MCE)
return MatchOperand_NoMatch;
int64_t Val = MCE->getValue();
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Operands.push_back(MipsOperand::CreateImm(

View file

@ -246,8 +246,6 @@ void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
break;
case MEK_CALL_HI16:
case MEK_CALL_LO16:
case MEK_DTPREL_HI:
case MEK_DTPREL_LO:
case MEK_GOT:
case MEK_GOT_CALL:
case MEK_GOT_DISP:
@ -263,14 +261,16 @@ void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
case MEK_NEG:
case MEK_PCREL_HI16:
case MEK_PCREL_LO16:
case MEK_TLSLDM:
// If we do have nested target-specific expressions, they will be in
// a consecutive chain.
if (const MipsMCExpr *E = dyn_cast<const MipsMCExpr>(getSubExpr()))
E->fixELFSymbolsInTLSFixups(Asm);
break;
case MEK_GOTTPREL:
case MEK_DTPREL_HI:
case MEK_DTPREL_LO:
case MEK_TLSLDM:
case MEK_TLSGD:
case MEK_GOTTPREL:
case MEK_TPREL_HI:
case MEK_TPREL_LO:
fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);

View file

@ -193,6 +193,21 @@ void MipsTargetStreamer::emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1,
emitRRX(Opcode, Reg0, Reg1, MCOperand::createImm(Imm), IDLoc, STI);
}
void MipsTargetStreamer::emitRRIII(unsigned Opcode, unsigned Reg0,
unsigned Reg1, int16_t Imm0, int16_t Imm1,
int16_t Imm2, SMLoc IDLoc,
const MCSubtargetInfo *STI) {
MCInst TmpInst;
TmpInst.setOpcode(Opcode);
TmpInst.addOperand(MCOperand::createReg(Reg0));
TmpInst.addOperand(MCOperand::createReg(Reg1));
TmpInst.addOperand(MCOperand::createImm(Imm0));
TmpInst.addOperand(MCOperand::createImm(Imm1));
TmpInst.addOperand(MCOperand::createImm(Imm2));
TmpInst.setLoc(IDLoc);
getStreamer().EmitInstruction(TmpInst, *STI);
}
void MipsTargetStreamer::emitAddu(unsigned DstReg, unsigned SrcReg,
unsigned TrgReg, bool Is64Bit,
const MCSubtargetInfo *STI) {

View file

@ -415,6 +415,13 @@ class BITREV_MM_DESC : ABSQ_S_PH_MM_R2_DESC_BASE<"bitrev", int_mips_bitrev,
class BPOSGE32_MM_DESC : BPOSGE32_DESC_BASE<"bposge32", brtarget_mm,
NoItinerary>;
let DecoderNamespace = "MicroMipsDSP", Arch = "mmdsp",
AdditionalPredicates = [HasDSP, InMicroMips] in {
def LWDSP_MM : Load<"lw", DSPROpnd, null_frag, II_LW>, DspMMRel,
LW_FM_MM<0x3f>;
def SWDSP_MM : Store<"sw", DSPROpnd, null_frag, II_SW>, DspMMRel,
LW_FM_MM<0x3e>;
}
// Instruction defs.
// microMIPS DSP Rev 1
def ADDQ_PH_MM : DspMMRel, ADDQ_PH_MM_ENC, ADDQ_PH_DESC;

View file

@ -1284,6 +1284,12 @@ let isPseudo = 1, isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
def STORE_CCOND_DSP : Store<"store_ccond_dsp", DSPCC>;
}
let DecoderNamespace = "MipsDSP", Arch = "dsp",
AdditionalPredicates = [HasDSP] in {
def LWDSP : Load<"lw", DSPROpnd, null_frag, II_LW>, DspMMRel, LW_FM<0x23>;
def SWDSP : Store<"sw", DSPROpnd, null_frag, II_SW>, DspMMRel, LW_FM<0x2b>;
}
// Pseudo CMP and PICK instructions.
class PseudoCMP<Instruction RealInst> :
PseudoDSP<(outs DSPCC:$cmp), (ins DSPROpnd:$rs, DSPROpnd:$rt), []>,

View file

@ -107,38 +107,31 @@ bool MipsFrameLowering::hasBP(const MachineFunction &MF) const {
return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF);
}
// Estimate the size of the stack, including the incoming arguments. We need to
// account for register spills, local objects, reserved call frame and incoming
// arguments. This is required to determine the largest possible positive offset
// from $sp so that it can be determined if an emergency spill slot for stack
// addresses is required.
uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
int64_t Offset = 0;
int64_t Size = 0;
// Iterate over fixed sized objects.
// Iterate over fixed sized objects which are incoming arguments.
for (int I = MFI.getObjectIndexBegin(); I != 0; ++I)
Offset = std::max(Offset, -MFI.getObjectOffset(I));
if (MFI.getObjectOffset(I) > 0)
Size += MFI.getObjectSize(I);
// Conservatively assume all callee-saved registers will be saved.
for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) {
unsigned Size = TRI.getSpillSize(*TRI.getMinimalPhysRegClass(*R));
Offset = alignTo(Offset + Size, Size);
unsigned RegSize = TRI.getSpillSize(*TRI.getMinimalPhysRegClass(*R));
Size = alignTo(Size + RegSize, RegSize);
}
unsigned MaxAlign = MFI.getMaxAlignment();
// Check that MaxAlign is not zero if there is a stack object that is not a
// callee-saved spill.
assert(!MFI.getObjectIndexEnd() || MaxAlign);
// Iterate over other objects.
for (unsigned I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I)
Offset = alignTo(Offset + MFI.getObjectSize(I), MaxAlign);
// Call frame.
if (MFI.adjustsStack() && hasReservedCallFrame(MF))
Offset = alignTo(Offset + MFI.getMaxCallFrameSize(),
std::max(MaxAlign, getStackAlignment()));
return alignTo(Offset, getStackAlignment());
// Get the size of the rest of the frame objects and any possible reserved
// call frame, accounting for alignment.
return Size + MFI.estimateStackSize(MF);
}
// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions

View file

@ -35,6 +35,8 @@ class FIELD5<bits<5> Val> {
def FIELD5_1_DMT_EMT : FIELD5<0b00001>;
def FIELD5_2_DMT_EMT : FIELD5<0b01111>;
def FIELD5_1_2_DVPE_EVPE : FIELD5<0b00000>;
def FIELD5_MFTR : FIELD5<0b01000>;
def FIELD5_MTTR : FIELD5<0b01100>;
class COP0_MFMC0_MT<FIELD5 Op1, FIELD5 Op2, OPCODE1 sc> : MipsMTInst {
bits<32> Inst;
@ -50,6 +52,25 @@ class COP0_MFMC0_MT<FIELD5 Op1, FIELD5 Op2, OPCODE1 sc> : MipsMTInst {
let Inst{2-0} = 0b001;
}
class COP0_MFTTR_MT<FIELD5 Op> : MipsMTInst {
bits<32> Inst;
bits<5> rt;
bits<5> rd;
bits<1> u;
bits<1> h;
bits<3> sel;
let Inst{31-26} = 0b010000; // COP0
let Inst{25-21} = Op.Value; // MFMC0
let Inst{20-16} = rt;
let Inst{15-11} = rd;
let Inst{10-6} = 0b00000; // rx - currently unsupported.
let Inst{5} = u;
let Inst{4} = h;
let Inst{3} = 0b0;
let Inst{2-0} = sel;
}
class SPECIAL3_MT_FORK : MipsMTInst {
bits<32> Inst;

View file

@ -6,6 +6,13 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the MIPS MT ASE as defined by MD00378 1.12.
//
// TODO: Add support for the microMIPS encodings for the MT ASE and add the
// instruction mappings.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// MIPS MT Instruction Encodings
@ -27,6 +34,10 @@ class FORK_ENC : SPECIAL3_MT_FORK;
class YIELD_ENC : SPECIAL3_MT_YIELD;
class MFTR_ENC : COP0_MFTTR_MT<FIELD5_MFTR>;
class MTTR_ENC : COP0_MFTTR_MT<FIELD5_MTTR>;
//===----------------------------------------------------------------------===//
// MIPS MT Instruction Descriptions
//===----------------------------------------------------------------------===//
@ -39,6 +50,22 @@ class MT_1R_DESC_BASE<string instr_asm, InstrItinClass Itin = NoItinerary> {
InstrItinClass Itinerary = Itin;
}
class MFTR_DESC {
dag OutOperandList = (outs GPR32Opnd:$rd);
dag InOperandList = (ins GPR32Opnd:$rt, uimm1:$u, uimm3:$sel, uimm1:$h);
string AsmString = "mftr\t$rd, $rt, $u, $sel, $h";
list<dag> Pattern = [];
InstrItinClass Itinerary = II_MFTR;
}
class MTTR_DESC {
dag OutOperandList = (outs GPR32Opnd:$rd);
dag InOperandList = (ins GPR32Opnd:$rt, uimm1:$u, uimm3:$sel, uimm1:$h);
string AsmString = "mttr\t$rt, $rd, $u, $sel, $h";
list<dag> Pattern = [];
InstrItinClass Itinerary = II_MTTR;
}
class FORK_DESC {
dag OutOperandList = (outs GPR32Opnd:$rs, GPR32Opnd:$rd);
dag InOperandList = (ins GPR32Opnd:$rt);
@ -79,8 +106,73 @@ let hasSideEffects = 1, isNotDuplicable = 1,
def FORK : FORK_ENC, FORK_DESC, ASE_MT;
def YIELD : YIELD_ENC, YIELD_DESC, ASE_MT;
def MFTR : MFTR_ENC, MFTR_DESC, ASE_MT;
def MTTR : MTTR_ENC, MTTR_DESC, ASE_MT;
}
//===----------------------------------------------------------------------===//
// MIPS MT Pseudo Instructions - used to support mtfr & mttr aliases.
//===----------------------------------------------------------------------===//
def MFTC0 : MipsAsmPseudoInst<(outs GPR32Opnd:$rd), (ins COP0Opnd:$rt,
uimm3:$sel),
"mftc0 $rd, $rt, $sel">, ASE_MT;
def MFTGPR : MipsAsmPseudoInst<(outs GPR32Opnd:$rd), (ins GPR32Opnd:$rt,
uimm3:$sel),
"mftgpr $rd, $rt">, ASE_MT;
def MFTLO : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins ACC64DSPOpnd:$ac),
"mftlo $rt, $ac">, ASE_MT;
def MFTHI : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins ACC64DSPOpnd:$ac),
"mfthi $rt, $ac">, ASE_MT;
def MFTACX : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins ACC64DSPOpnd:$ac),
"mftacx $rt, $ac">, ASE_MT;
def MFTDSP : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins),
"mftdsp $rt">, ASE_MT;
def MFTC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32Opnd:$ft),
"mftc1 $rt, $ft">, ASE_MT;
def MFTHC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGR32Opnd:$ft),
"mfthc1 $rt, $ft">, ASE_MT;
def CFTC1 : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins FGRCCOpnd:$ft),
"cftc1 $rt, $ft">, ASE_MT;
def MTTC0 : MipsAsmPseudoInst<(outs COP0Opnd:$rd), (ins GPR32Opnd:$rt,
uimm3:$sel),
"mttc0 $rt, $rd, $sel">, ASE_MT;
def MTTGPR : MipsAsmPseudoInst<(outs GPR32Opnd:$rt), (ins GPR32Opnd:$rd),
"mttgpr $rd, $rt">, ASE_MT;
def MTTLO : MipsAsmPseudoInst<(outs ACC64DSPOpnd:$ac), (ins GPR32Opnd:$rt),
"mttlo $rt, $ac">, ASE_MT;
def MTTHI : MipsAsmPseudoInst<(outs ACC64DSPOpnd:$ac), (ins GPR32Opnd:$rt),
"mtthi $rt, $ac">, ASE_MT;
def MTTACX : MipsAsmPseudoInst<(outs ACC64DSPOpnd:$ac), (ins GPR32Opnd:$rt),
"mttacx $rt, $ac">, ASE_MT;
def MTTDSP : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rt),
"mttdsp $rt">, ASE_MT;
def MTTC1 : MipsAsmPseudoInst<(outs FGR32Opnd:$ft), (ins GPR32Opnd:$rt),
"mttc1 $rt, $ft">, ASE_MT;
def MTTHC1 : MipsAsmPseudoInst<(outs FGR32Opnd:$ft), (ins GPR32Opnd:$rt),
"mtthc1 $rt, $ft">, ASE_MT;
def CTTC1 : MipsAsmPseudoInst<(outs FGRCCOpnd:$ft), (ins GPR32Opnd:$rt),
"cttc1 $rt, $ft">, ASE_MT;
//===----------------------------------------------------------------------===//
// MIPS MT Instruction Definitions
//===----------------------------------------------------------------------===//
@ -95,4 +187,22 @@ let AdditionalPredicates = [NotInMicroMips] in {
def : MipsInstAlias<"evpe", (EVPE ZERO), 1>, ASE_MT;
def : MipsInstAlias<"yield $rs", (YIELD ZERO, GPR32Opnd:$rs), 1>, ASE_MT;
def : MipsInstAlias<"mftc0 $rd, $rt", (MFTC0 GPR32Opnd:$rd, COP0Opnd:$rt, 0),
1>, ASE_MT;
def : MipsInstAlias<"mftlo $rt", (MFTLO GPR32Opnd:$rt, AC0), 1>, ASE_MT;
def : MipsInstAlias<"mfthi $rt", (MFTHI GPR32Opnd:$rt, AC0), 1>, ASE_MT;
def : MipsInstAlias<"mftacx $rt", (MFTACX GPR32Opnd:$rt, AC0), 1>, ASE_MT;
def : MipsInstAlias<"mttc0 $rd, $rt", (MTTC0 COP0Opnd:$rt, GPR32Opnd:$rd, 0),
1>, ASE_MT;
def : MipsInstAlias<"mttlo $rt", (MTTLO AC0, GPR32Opnd:$rt), 1>, ASE_MT;
def : MipsInstAlias<"mtthi $rt", (MTTHI AC0, GPR32Opnd:$rt), 1>, ASE_MT;
def : MipsInstAlias<"mttacx $rt", (MTTACX AC0, GPR32Opnd:$rt), 1>, ASE_MT;
}

View file

@ -894,10 +894,12 @@ void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
}
// Set scavenging frame index if necessary.
uint64_t MaxSPOffset = MF.getInfo<MipsFunctionInfo>()->getIncomingArgSize() +
estimateStackSize(MF);
uint64_t MaxSPOffset = estimateStackSize(MF);
if (isInt<16>(MaxSPOffset))
// MSA has a minimum offset of 10 bits signed. If there is a variable
// sized object on the stack, the estimation cannot account for it.
if (isIntN(STI.hasMSA() ? 10 : 16, MaxSPOffset) &&
!MF.getFrameInfo().hasVarSizedObjects())
return;
const TargetRegisterClass &RC =

View file

@ -226,6 +226,8 @@ storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
Opc = Mips::SW;
else if (Mips::HI64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::SWDSP;
// Hi, Lo are normally caller save but they are callee save
// for interrupt handling.
@ -302,6 +304,8 @@ loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
Opc = Mips::LW;
else if (Mips::LO64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::LWDSP;
assert(Opc && "Register class not handled!");

View file

@ -226,6 +226,7 @@ def II_MFC1 : InstrItinClass;
def II_MFHC1 : InstrItinClass;
def II_MFC2 : InstrItinClass;
def II_MFHI_MFLO : InstrItinClass; // mfhi and mflo
def II_MFTR : InstrItinClass;
def II_MOD : InstrItinClass;
def II_MODU : InstrItinClass;
def II_MOVE : InstrItinClass;
@ -255,6 +256,7 @@ def II_MTC1 : InstrItinClass;
def II_MTHC1 : InstrItinClass;
def II_MTC2 : InstrItinClass;
def II_MTHI_MTLO : InstrItinClass; // mthi and mtlo
def II_MTTR : InstrItinClass;
def II_MUL : InstrItinClass;
def II_MUH : InstrItinClass;
def II_MUHU : InstrItinClass;
@ -664,12 +666,14 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
InstrItinData<II_MFHC0 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFTR , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC0 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTHC0 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTC2 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MFHC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTHC1 , [InstrStage<2, [ALU]>]>,
InstrItinData<II_MTTR , [InstrStage<2, [ALU]>]>,
InstrItinData<II_CACHE , [InstrStage<1, [ALU]>]>,
InstrItinData<II_PREF , [InstrStage<1, [ALU]>]>,
InstrItinData<II_CACHEE , [InstrStage<1, [ALU]>]>,

View file

@ -268,9 +268,11 @@ def : ItinRW<[GenericWriteLoad], [II_LWLE, II_LWRE]>;
// MIPS MT instructions
// ====================
def : ItinRW<[GenericWriteMove], [II_DMT, II_DVPE, II_EMT, II_EVPE]>;
def : ItinRW<[GenericWriteMove], [II_DMT, II_DVPE, II_EMT, II_EVPE, II_MFTR,
II_MTTR]>;
def : ItinRW<[GenericReadWriteCOP0Long], [II_YIELD]>;
def : ItinRW<[GenericWriteCOP0Short], [II_FORK]>;
// MIPS32R6 and MIPS16e

View file

@ -119,6 +119,9 @@ class MipsTargetStreamer : public MCTargetStreamer {
SMLoc IDLoc, const MCSubtargetInfo *STI);
void emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm,
SMLoc IDLoc, const MCSubtargetInfo *STI);
void emitRRIII(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm0,
int16_t Imm1, int16_t Imm2, SMLoc IDLoc,
const MCSubtargetInfo *STI);
void emitAddu(unsigned DstReg, unsigned SrcReg, unsigned TrgReg, bool Is64Bit,
const MCSubtargetInfo *STI);
void emitDSLL(unsigned DstReg, unsigned SrcReg, int16_t ShiftAmount,

View file

@ -7026,6 +7026,18 @@ X86TargetLowering::LowerBUILD_VECTORvXi1(SDValue Op, SelectionDAG &DAG) const {
return DAG.getTargetConstant(1, dl, VT);
if (ISD::isBuildVectorOfConstantSDNodes(Op.getNode())) {
if (VT == MVT::v64i1 && !Subtarget.is64Bit()) {
// Split the pieces.
SDValue Lower =
DAG.getBuildVector(MVT::v32i1, dl, Op.getNode()->ops().slice(0, 32));
SDValue Upper =
DAG.getBuildVector(MVT::v32i1, dl, Op.getNode()->ops().slice(32, 32));
// We have to manually lower both halves so getNode doesn't try to
// reassemble the build_vector.
Lower = LowerBUILD_VECTORvXi1(Lower, DAG);
Upper = LowerBUILD_VECTORvXi1(Upper, DAG);
return DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v64i1, Lower, Upper);
}
SDValue Imm = ConvertI1VectorToInteger(Op, DAG);
if (Imm.getValueSizeInBits() == VT.getSizeInBits())
return DAG.getBitcast(VT, Imm);
@ -34733,6 +34745,11 @@ static SDValue combineVectorSizedSetCCEquality(SDNode *SetCC, SelectionDAG &DAG,
if (!OpVT.isScalarInteger() || OpSize < 128 || isNullConstant(Y))
return SDValue();
// Bail out if we know that this is not really just an oversized integer.
if (peekThroughBitcasts(X).getValueType() == MVT::f128 ||
peekThroughBitcasts(Y).getValueType() == MVT::f128)
return SDValue();
// TODO: Use PXOR + PTEST for SSE4.1 or later?
// TODO: Add support for AVX-512.
EVT VT = SetCC->getValueType(0);

View file

@ -1,13 +1,15 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
; RUN: verify-uselistorder < %s
!llvm.module.flags = !{!0, !1, !2}
!llvm.module.flags = !{!0, !1, !2, !3}
!0 = !{i32 1, !"PIC Level", i32 1}
!1 = !{i32 1, !"PIE Level", i32 1}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
; CHECK: !0 = !{i32 7, !"PIC Level", i32 1}
; CHECK: !1 = !{i32 7, !"PIE Level", i32 1}
; CHECK: !2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
; CHECK: !3 = !{i32 4, !"Objective-C Class Properties", i32 0}
; CHECK: !3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
; CHECK: !4 = !{i32 4, !"Objective-C Class Properties", i32 0}

View file

@ -0,0 +1,31 @@
; RUN: llvm-as %s -o - | llvm-dis - | FileCheck %s
%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }
%struct._objc_cache = type opaque
%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* }
%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }
%struct._objc_method = type { i8*, i8*, i8* }
%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }
%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* }
%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }
%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 }
%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
%struct._prop_t = type { i8*, i8* }
%struct._category_t = type { i8*, %struct._class_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._prop_list_t*, %struct._prop_list_t*, i32 }
@OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Robot\00", section "__TEXT,__objc_classname,cstring_literals", align 1
@"OBJC_CLASS_$_I" = external global %struct._class_t
@"\01l_OBJC_$_CATEGORY_I_$_Robot" = private global %struct._category_t { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), %struct._class_t* @"OBJC_CLASS_$_I", %struct.__method_list_t* null, %struct.__method_list_t* null, %struct._objc_protocol_list* null, %struct._prop_list_t* null, %struct._prop_list_t* null, i32 64 }, section "__DATA, __objc_const", align 8
@"OBJC_LABEL_CATEGORY_$" = private global [1 x i8*] [i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_I_$_Robot" to i8*)], section "__DATA, __objc_catlist, regular, no_dead_strip", align 8
@llvm.compiler.used = appending global [3 x i8*] [i8* bitcast (%struct._category_t* @"\01l_OBJC_$_CATEGORY_I_$_Robot" to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* bitcast ([1 x i8*]* @"OBJC_LABEL_CATEGORY_$" to i8*)], section "llvm.metadata"
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!0 = !{i32 1, !"Objective-C Version", i32 2}
!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
!5 = !{i32 1, !"PIC Level", i32 2}
; CHECK: @"OBJC_LABEL_CATEGORY_$" = {{.*}}, section "__DATA,__objc_catlist,regular,no_dead_strip"

View file

@ -12,9 +12,9 @@ entry:
define void @t2() nounwind ssp {
entry:
; CHECK-LABEL: t2:
; CHECK: stp xzr, xzr, [sp, #16]
; CHECK: strh wzr, [sp, #32]
; CHECK: stp xzr, xzr, [sp, #8]
; CHECK: str xzr, [sp, #24]
; CHECK: str xzr, [sp, #8]
%buf = alloca [26 x i8], align 1
%0 = getelementptr inbounds [26 x i8], [26 x i8]* %buf, i32 0, i32 0
call void @llvm.memset.p0i8.i32(i8* %0, i8 0, i32 26, i32 1, i1 false)

View file

@ -0,0 +1,19 @@
; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s
; CHECK: test_frameindex_cmp:
; CHECK: cmn sp, #{{[0-9]+}}
define void @test_frameindex_cmp() {
%stack = alloca i8
%stack.int = ptrtoint i8* %stack to i64
%cmp = icmp ne i64 %stack.int, 0
br i1 %cmp, label %bb1, label %bb2
bb1:
call void @bar()
ret void
bb2:
ret void
}
declare void @bar()

View file

@ -1,12 +1,7 @@
# RUN: llc -mtriple=aarch64-linux-gnu -mcpu=falkor -run-pass falkor-hwpf-fix-late -o - %s | FileCheck %s
--- |
@g = external global i32
define void @hwpf1() { ret void }
define void @hwpf2() { ret void }
...
---
# Verify that the tag collision between the loads is resolved.
# Verify that the tag collision between the loads is resolved for various load opcodes.
# CHECK-LABEL: name: hwpf1
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDRWui %[[BASE]], 0
@ -17,7 +12,7 @@ body: |
bb.0:
liveins: %w0, %x1
%w2 = LDRWui %x1, 0 :: ("aarch64-strided-access" load 4 from @g)
%w2 = LDRWui %x1, 0 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 1
%w0 = SUBWri %w0, 1, 0
@ -28,19 +23,147 @@ body: |
RET_ReallyLR
...
---
# Verify that the tag collision between the loads is resolved and written back for post increment addressing.
# CHECK-LABEL: name: hwpf2
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDRWpost %[[BASE]], 0
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x1, 1
# CHECK: LD1i64 %q2, 0, %[[BASE]]
# CHECK: LDRWui %x1, 0
name: hwpf2
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %q2
%q2 = LD1i64 %q2, 0, %x1 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 0
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpf3
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1i8 %q2, 0, %[[BASE]]
# CHECK: LDRWui %x1, 0
name: hwpf3
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %q2
%q2 = LD1i8 %q2, 0, %x1 :: ("aarch64-strided-access" load 4)
%w0 = LDRWui %x1, 0
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpf4
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1Onev1d %[[BASE]]
# CHECK: LDRWui %x1, 0
name: hwpf4
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1
%x1, %w2 = LDRWpost %x1, 0 :: ("aarch64-strided-access" load 4 from @g)
%d2 = LD1Onev1d %x1 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 0
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpf5
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1Twov1d %[[BASE]]
# CHECK: LDRWui %x1, 0
name: hwpf5
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1
%d2_d3 = LD1Twov1d %x1 :: ("aarch64-strided-access" load 4)
%w0 = LDRWui %x1, 0
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpf6
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDPQi %[[BASE]]
# CHECK: LDRWui %x1, 3
name: hwpf6
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1
%q2, %q3 = LDPQi %x1, 3 :: ("aarch64-strided-access" load 4)
%w0 = LDRWui %x1, 3
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpf7
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDPXi %[[BASE]]
# CHECK: LDRWui %x1, 2
name: hwpf7
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1
%x2, %x3 = LDPXi %x1, 3 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 2
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# Verify that the tag collision between the loads is resolved and written back
# for post increment addressing for various load opcodes.
# CHECK-LABEL: name: hwpfinc1
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDRWpost %[[BASE]], 0
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x1, 1
name: hwpfinc1
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1
%x1, %w2 = LDRWpost %x1, 0 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 1
%w0 = SUBWri %w0, 1, 0
@ -50,3 +173,160 @@ body: |
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc2
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1i64_POST %q2, 0, %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x1, 1
name: hwpfinc2
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %q2
%x1, %q2 = LD1i64_POST %q2, 0, %x1, %x1 :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 132
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc3
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1i8_POST %q2, 0, %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x1, 132
name: hwpfinc3
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %q2
%x1, %q2 = LD1i8_POST %q2, 0, %x1, %x1 :: ("aarch64-strided-access" load 4)
%w0 = LDRWui %x1, 132
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc4
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD1Rv1d_POST %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x1, 252
name: hwpfinc4
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %q2
%x1, %d2 = LD1Rv1d_POST %x1, %xzr :: ("aarch64-strided-access" load 4)
%w2 = LDRWui %x1, 252
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc5
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LD3Threev2s_POST %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWroX %x17, %x0
name: hwpfinc5
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %x17, %q2
%x1, %d2_d3_d4 = LD3Threev2s_POST %x1, %x0 :: ("aarch64-strided-access" load 4)
%w0 = LDRWroX %x17, %x0, 0, 0
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc6
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDPDpost %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x17, 2
name: hwpfinc6
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %x17, %q2
%x1, %d2, %d3 = LDPDpost %x1, 3 :: ("aarch64-strided-access" load 4)
%w16 = LDRWui %x17, 2
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# CHECK-LABEL: name: hwpfinc7
# CHECK: %[[BASE:[a-z0-9]+]] = ORRXrs %xzr, %x1, 0
# CHECK: LDPXpost %[[BASE]]
# CHECK: %x1 = ORRXrs %xzr, %[[BASE]], 0
# CHECK: LDRWui %x17, 2
name: hwpfinc7
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %x17, %q2
%x1, %x2, %x3 = LDPXpost %x1, 3 :: ("aarch64-strided-access" load 4)
%w18 = LDRWui %x17, 2
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...
---
# Check that we handle case of strided load with no HW prefetcher tag correctly.
# CHECK-LABEL: name: hwpf_notagbug
# CHECK-NOT: ORRXrs %xzr
# CHECK: LDARW %x1
# CHECK-NOT: ORRXrs %xzr
# CHECK: LDRWui %x1
name: hwpf_notagbug
tracksRegLiveness: true
body: |
bb.0:
liveins: %w0, %x1, %x17
%w1 = LDARW %x1 :: ("aarch64-strided-access" load 4)
%w1 = LDRWui %x1, 0 :: ("aarch64-strided-access" load 4)
%w17 = LDRWui %x17, 0 :: ("aarch64-strided-access" load 4)
%w0 = SUBWri %w0, 1, 0
%wzr = SUBSWri %w0, 0, 0, implicit-def %nzcv
Bcc 9, %bb.0, implicit %nzcv
bb.1:
RET_ReallyLR
...

View file

@ -21,9 +21,11 @@ define fastcc void @func_stack0() {
call fastcc void @func_stack8([8 x i32] undef, i32 42)
; CHECK: bl func_stack8
; CHECK-NOT: sub sp, sp,
; CHECK-NOT: [sp, #{{[-0-9]+}}]!
; CHECK-NOT: [sp], #{{[-0-9]+}}
; CHECK-TAIL: bl func_stack8
; CHECK-TAIL: sub sp, sp, #16
; CHECK-TAIL: stp xzr, xzr, [sp, #-16]!
call fastcc void @func_stack32([8 x i32] undef, i128 0, i128 9)
@ -72,10 +74,12 @@ define fastcc void @func_stack8([8 x i32], i32 %stacked) {
call fastcc void @func_stack8([8 x i32] undef, i32 42)
; CHECK: bl func_stack8
; CHECK-NOT: sub sp, sp,
; CHECK-NOT: [sp, #{{[-0-9]+}}]!
; CHECK-NOT: [sp], #{{[-0-9]+}}
; CHECK-TAIL: bl func_stack8
; CHECK-TAIL: sub sp, sp, #16
; CHECK-TAIL: stp xzr, xzr, [sp, #-16]!
call fastcc void @func_stack32([8 x i32] undef, i128 0, i128 9)
@ -116,9 +120,11 @@ define fastcc void @func_stack32([8 x i32], i128 %stacked0, i128 %stacked1) {
call fastcc void @func_stack8([8 x i32] undef, i32 42)
; CHECK: bl func_stack8
; CHECK-NOT: sub sp, sp,
; CHECK-NOT: [sp, #{{[-0-9]+}}]!
; CHECK-NOT: [sp], #{{[-0-9]+}}
; CHECK-TAIL: bl func_stack8
; CHECK-TAIL: sub sp, sp, #16
; CHECK-TAIL: stp xzr, xzr, [sp, #-16]!
call fastcc void @func_stack32([8 x i32] undef, i128 0, i128 9)

View file

@ -1667,4 +1667,17 @@ entry:
ret void
}
; Check for bug 34674 where invalid add of xzr was being generated.
; CHECK-LABEL: bug34674:
; CHECK: // %entry
; CHECK-NEXT: mov [[ZREG:x[0-9]+]], xzr
; CHECK-DAG: stp [[ZREG]], [[ZREG]], [x0]
; CHECK-DAG: add x{{[0-9]+}}, [[ZREG]], #1
define i64 @bug34674(<2 x i64>* %p) {
entry:
store <2 x i64> zeroinitializer, <2 x i64>* %p
%p2 = bitcast <2 x i64>* %p to i64*
%ld = load i64, i64* %p2
%add = add i64 %ld, 1
ret i64 %add
}

View file

@ -1,60 +0,0 @@
; RUN: llc -mtriple=aarch64-linux-gnu -verify-machineinstrs -o - %s | FileCheck %s
@x = thread_local local_unnamed_addr global i32 0, align 4
@y = thread_local local_unnamed_addr global i32 0, align 4
; Machine LICM should hoist the mrs into the loop preheader.
; CHECK-LABEL: @test1
; CHECK: BB#1:
; CHECK: mrs x[[BASE:[0-9]+]], TPIDR_EL0
; CHECK: add x[[REG1:[0-9]+]], x[[BASE]], :tprel_hi12:x
; CHECK: add x[[REG2:[0-9]+]], x[[REG1]], :tprel_lo12_nc:x
;
; CHECK: .LBB0_2:
; CHECK: ldr w0, [x[[REG2]]]
; CHECK: bl bar
; CHECK: subs w[[REG3:[0-9]+]], w{{[0-9]+}}, #1
; CHECK: b.ne .LBB0_2
define void @test1(i32 %n) local_unnamed_addr {
entry:
%cmp3 = icmp sgt i32 %n, 0
br i1 %cmp3, label %bb1, label %bb2
bb1:
br label %for.body
for.body:
%i.04 = phi i32 [ %inc, %for.body ], [ 0, %bb1 ]
%0 = load i32, i32* @x, align 4
tail call void @bar(i32 %0) #2
%inc = add nuw nsw i32 %i.04, 1
%exitcond = icmp eq i32 %inc, %n
br i1 %exitcond, label %bb2, label %for.body
bb2:
ret void
}
; Machine CSE should combine the the mrs between the load of %x and %y.
; CHECK-LABEL: @test2
; CHECK: mrs x{{[0-9]+}}, TPIDR_EL0
; CHECK-NOT: mrs x{{[0-9]+}}, TPIDR_EL0
; CHECK: ret
define void @test2(i32 %c) local_unnamed_addr #0 {
entry:
%0 = load i32, i32* @x, align 4
tail call void @bar(i32 %0) #2
%cmp = icmp eq i32 %c, 0
br i1 %cmp, label %if.end, label %if.then
if.then:
%1 = load i32, i32* @y, align 4
tail call void @bar(i32 %1) #2
br label %if.end
if.end:
ret void
}
declare void @bar(i32) local_unnamed_addr

View file

@ -0,0 +1,31 @@
# RUN: llc -march=amdgcn -mcpu=tonga -verify-machineinstrs -run-pass post-RA-hazard-rec %s -o - | FileCheck -check-prefix=GCN -check-prefix=VI %s
# RUN: llc -march=amdgcn -mcpu=gfx900 -verify-machineinstrs -run-pass post-RA-hazard-rec %s -o - | FileCheck -check-prefix=GCN -check-prefix=GFX9 %s
# GCN: bb.0.entry:
# GCN: %m0 = S_MOV_B32
# GFX9: S_NOP 0
# VI-NOT: S_NOP_0
# GCN: V_INTERP_P1_F32
---
name: hazard_implicit_def
alignment: 0
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '%sgpr7', virtual-reg: '' }
- { reg: '%vgpr4', virtual-reg: '' }
body: |
bb.0.entry:
liveins: %sgpr7, %vgpr4
%m0 = S_MOV_B32 killed %sgpr7
%vgpr5 = IMPLICIT_DEF
%vgpr0 = V_INTERP_P1_F32 killed %vgpr4, 0, 0, implicit %m0, implicit %exec
SI_RETURN_TO_EPILOG killed %vgpr5, killed %vgpr0
...

View file

@ -1,5 +1,5 @@
; RUN: llc -mtriple arm-unknown -mattr=+vfp2 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LITTLE
; RUN: llc -mtriple armeb-unknown -mattr=+vfp2 -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=BIG
; RUN: llc -mtriple arm-unknown -mattr=+vfp2,+v4t -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=LITTLE
; RUN: llc -mtriple armeb-unknown -mattr=+vfp2,+v4t -global-isel -stop-after=irtranslator -verify-machineinstrs %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=BIG
define void @test_void_return() {
; CHECK-LABEL: name: test_void_return

View file

@ -5,9 +5,24 @@
; RUN: llc < %s -mtriple=armv4-unknown-eabi | FileCheck %s -check-prefix=ARM
; RUN: llc < %s -mtriple=armv4t-unknown-eabi | FileCheck %s -check-prefix=THUMB
define i32 @test(i32 %a) nounwind readnone {
define i32 @test_return(i32 %a) nounwind readnone {
entry:
; ARM-LABEL: test_return
; ARM: mov pc
; THUMB-LABEL: test_return
; THUMB: bx
ret i32 %a
}
@helper = global i32 ()* null, align 4
define i32 @test_indirect() #0 {
entry:
; ARM-LABEL: test_indirect
; ARM: mov pc
; THUMB-LABEL: test_indirect
; THUMB: bx
%0 = load i32 ()*, i32 ()** @helper, align 4
%call = tail call i32 %0()
ret i32 %call
}

View file

@ -1,5 +1,5 @@
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -verify-machineinstrs -filetype=asm | FileCheck %s -check-prefix=ARM-linux
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -filetype=obj
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -mattr=+v4t -verify-machineinstrs -filetype=asm | FileCheck %s -check-prefix=ARM-linux
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -mattr=+v4t -filetype=obj
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!9, !10}

View file

@ -0,0 +1,49 @@
; RUN: llc -o - %s | FileCheck %s
; Make sure we do not try to compute liveness for FPSCR which in this case
; is read before being written to (this is fine because becase FPSCR is
; reserved).
target triple = "thumbv7s-apple-ios"
%struct.wibble = type { double }
@global = common global i32 0, align 4
@global.1 = common global i32 0, align 4
; CHECK-LABEL: eggs:
; CHECK: sub sp, #8
; VMRS instruction comes before any other instruction writing FPSCR:
; CHECK-NEXT: vmrs r0, fpscr
; ...
; CHECK: add sp, #8
; CHECK: bx lr
define i32 @eggs(double* nocapture readnone %arg) {
bb:
%tmp = alloca %struct.wibble, align 4
%tmp1 = bitcast %struct.wibble* %tmp to i8*
%tmp2 = tail call i32 @llvm.flt.rounds()
%tmp3 = ptrtoint %struct.wibble* %tmp to i32
%tmp4 = sitofp i32 %tmp3 to double
%tmp5 = fmul double %tmp4, 0x0123456789ABCDEF
%tmp6 = fptosi double %tmp5 to i32
%tmp7 = fcmp une double %tmp5, 0.000000e+00
%tmp8 = sitofp i32 %tmp6 to double
%tmp9 = fcmp une double %tmp5, %tmp8
%tmp10 = and i1 %tmp7, %tmp9
%tmp11 = sext i1 %tmp10 to i32
%tmp12 = add nsw i32 %tmp11, %tmp6
store i32 %tmp12, i32* @global, align 4
%tmp13 = icmp ne i32 %tmp12, 0
%tmp14 = icmp ne i32 %tmp2, 0
%tmp15 = and i1 %tmp14, %tmp13
br i1 %tmp15, label %bb16, label %bb18
bb16: ; preds = %bb
%tmp17 = load i32, i32* @global.1, align 4
br label %bb18
bb18: ; preds = %bb16, %bb
ret i32 undef
}
declare i32 @llvm.flt.rounds()
declare i32 @zot(...)

View file

@ -0,0 +1,27 @@
; RUN: llc -o - %s | FileCheck %s
target triple = "armv7"
; CHECK-LABEL: func:
; CHECK: push {r11, lr}
; CHECK: vpush {d8}
; CEHCK: b .LBB0_2
define arm_aapcscc double @func() {
br label %tailrecurse
tailrecurse:
%v0 = load i16, i16* undef, align 8
%cond36.i = icmp eq i16 %v0, 3
br i1 %cond36.i, label %sw.bb.i, label %sw.epilog.i
sw.bb.i:
%v1 = load double, double* undef, align 8
%call21.i = tail call arm_aapcscc double @func()
%mul.i = fmul double %v1, %call21.i
ret double %mul.i
sw.epilog.i:
tail call arm_aapcscc void @_ZNK10shared_ptrdeEv()
br label %tailrecurse
}
declare arm_aapcscc void @_ZNK10shared_ptrdeEv() local_unnamed_addr

View file

@ -1,7 +1,7 @@
; RUN: llc < %s -mtriple=arm-linux-androideabi -verify-machineinstrs | FileCheck %s -check-prefix=ARM-android
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -verify-machineinstrs | FileCheck %s -check-prefix=ARM-linux
; RUN: llc < %s -mtriple=arm-linux-androideabi -filetype=obj
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -filetype=obj
; RUN: llc < %s -mtriple=arm-linux-androideabi -mattr=+v4t -verify-machineinstrs | FileCheck %s -check-prefix=ARM-android
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -mattr=+v4t -verify-machineinstrs | FileCheck %s -check-prefix=ARM-linux
; RUN: llc < %s -mtriple=arm-linux-androideabi -mattr=+v4t -filetype=obj
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -mattr=+v4t -filetype=obj
; Just to prevent the alloca from being optimized away
declare void @dummy_use(i32*, i32)

View file

@ -1,5 +1,5 @@
; RUN: llc < %s -mtriple=arm-linux-androideabi -verify-machineinstrs | FileCheck %s -check-prefix=ARM-android
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -verify-machineinstrs | FileCheck %s -check-prefix=ARM-linux
; RUN: llc < %s -mtriple=arm-linux-androideabi -mattr=+v4t -verify-machineinstrs | FileCheck %s -check-prefix=ARM-android
; RUN: llc < %s -mtriple=arm-linux-unknown-gnueabi -mattr=+v4t -verify-machineinstrs | FileCheck %s -check-prefix=ARM-linux
; We used to crash with filetype=obj
; RUN: llc < %s -mtriple=arm-linux-androideabi -filetype=obj

View file

@ -0,0 +1,23 @@
; RUN: llc < %s -march=avr | FileCheck %s
; At one point, the 16-vit atomic load/store operations we defined in TableGen
; to use 'PTRREGS', but the pseudo expander would generate LDDW/STDW instructions.
;
; This would sometimes cause codegen to fail because LDDW requires 'PTRDISPREGS', and
; so if we attempted to generate an atomic operation on the X register, it would hit
; an assertion;
%AtomicI16 = type { %UnsafeCell, [0 x i8] }
%UnsafeCell = type { i16, [0 x i8] }
; CHECK-LABEL: foo
define i8 @foo(%AtomicI16*) {
start:
; We should not be generating atomics that use the X register, they will fail when emitting MC.
; CHECK-NOT: X
%1 = getelementptr inbounds %AtomicI16, %AtomicI16* %0, i16 0, i32 0, i32 0
%2 = load atomic i16, i16* %1 seq_cst, align 2
ret i8 0
}

View file

@ -3,8 +3,8 @@
; CHECK-LABEL: atomic_load16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR:r[0-9]+]], [[RD:(X|Y|Z)]]+
; CHECK-NEXT: out 63, r0
define i16 @atomic_load16(i16* %foo) {
%val = load atomic i16, i16* %foo unordered, align 2
@ -29,8 +29,8 @@ define i16 @atomic_load_cmp_swap16(i16* %foo) {
; CHECK-LABEL: atomic_load_add16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]
; CHECK-NEXT: add [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: adc [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
@ -44,8 +44,8 @@ define i16 @atomic_load_add16(i16* %foo) {
; CHECK-LABEL: atomic_load_sub16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]
; CHECK-NEXT: sub [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: sbc [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
@ -59,8 +59,8 @@ define i16 @atomic_load_sub16(i16* %foo) {
; CHECK-LABEL: atomic_load_and16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]
; CHECK-NEXT: and [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: and [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
@ -74,8 +74,8 @@ define i16 @atomic_load_and16(i16* %foo) {
; CHECK-LABEL: atomic_load_or16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]
; CHECK-NEXT: or [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: or [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]
@ -89,8 +89,8 @@ define i16 @atomic_load_or16(i16* %foo) {
; CHECK-LABEL: atomic_load_xor16
; CHECK: in r0, 63
; CHECK-NEXT: cli
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]
; CHECK-NEXT: ldd [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR1:r[0-9]+]], [[RD1:(X|Y|Z)]]+
; CHECK-NEXT: ld [[RR2:r[0-9]+]], [[RD2:(X|Y|Z)]]
; CHECK-NEXT: eor [[RR1]], [[TMP:r[0-9]+]]
; CHECK-NEXT: eor [[RR2]], [[TMP:r[0-9]+]]
; CHECK-NEXT: st [[RD1]], [[RR1]]

File diff suppressed because it is too large Load diff

View file

@ -31,8 +31,8 @@ define i8 @calli8_reg() {
define i8 @calli8_stack() {
; CHECK-LABEL: calli8_stack:
; CHECK: ldi [[REG1:r[0-9]+]], 10
; CHECK: push [[REG1]]
; CHECK: ldi [[REG1]], 11
; CHECK: ldi [[REG2:r[0-9]+]], 11
; CHECK: push [[REG2]]
; CHECK: push [[REG1]]
; CHECK: call foo8_3
%result1 = call i8 @foo8_3(i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11)
@ -142,7 +142,7 @@ define void @testcallprologue() {
; CHECK-LABEL: testcallprologue:
; CHECK: push r28
; CHECK: push r29
; CHECK: sbiw r28, 28
; CHECK: sbiw r28, 27
; CHECK: ldi [[REG1:r[0-9]+]], 88
; CHECK: std Y+9, [[REG1]]
; CHECK: ldi [[REG1:r[0-9]+]], 11

View file

@ -0,0 +1,5 @@
; RUN: llc < %s -march=avr | FileCheck %s
; CHECK: .globl __do_clear_bss
@zeroed = internal constant [3 x i8] zeroinitializer

View file

@ -0,0 +1,5 @@
; RUN: llc < %s -march=avr | FileCheck %s
; CHECK: .globl __do_copy_data
@str = internal global [3 x i8] c"foo"

View file

@ -33,12 +33,12 @@ define i8 @global8_load() {
define void @array8_store() {
; CHECK-LABEL: array8_store:
; CHECK: ldi [[REG1:r[0-9]+]], 3
; CHECK: sts char.array+2, [[REG1]]
; CHECK: ldi [[REG3:r[0-9]+]], 1
; CHECK: ldi [[REG2:r[0-9]+]], 2
; CHECK: sts char.array+1, [[REG2]]
; CHECK: ldi [[REG1:r[0-9]+]], 1
; CHECK: sts char.array, [[REG1]]
; CHECK: ldi [[REG:r[0-9]+]], 3
; CHECK: sts char.array+2, [[REG]]
; CHECK: sts char.array, [[REG3]]
store i8 1, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 0)
store i8 2, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 1)
store i8 3, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @char.array, i32 0, i64 2)

View file

@ -9,8 +9,8 @@ define i8 @load8(i8* %x) {
define i16 @load16(i16* %x) {
; CHECK-LABEL: load16:
; CHECK: ld r24, {{[YZ]}}
; CHECK: ldd r25, {{[YZ]}}+1
; CHECK: ld r24, {{[XYZ]}}+
; CHECK: ld r25, {{[XYZ]}}
%1 = load i16, i16* %x
ret i16 %1
}
@ -45,11 +45,11 @@ define i16 @load16disp(i16* %x) {
define i16 @load16nodisp(i16* %x) {
; CHECK-LABEL: load16nodisp:
; CHECK: movw r30, r24
; CHECK: subi r30, 192
; CHECK: sbci r31, 255
; CHECK: ld r24, {{[YZ]}}
; CHECK: ldd r25, {{[YZ]}}+1
; CHECK: movw r26, r24
; CHECK: subi r26, 192
; CHECK: sbci r27, 255
; CHECK: ld r24, {{[XYZ]}}+
; CHECK: ld r25, {{[XYZ]}}
%1 = getelementptr inbounds i16, i16* %x, i64 32
%2 = load i16, i16* %1
ret i16 %2

View file

@ -18,9 +18,9 @@ body: |
; CHECK-LABEL: test_ldwrdptr
; CHECK: ld [[SCRATCH:r[0-9]+]], Z
; CHECK: ld [[SCRATCH:r[0-9]+]], Z+
; CHECK-NEXT: push [[SCRATCH]]
; CHECK-NEXT: ldd [[SCRATCH]], Z+1
; CHECK-NEXT: ld [[SCRATCH]], Z
; CHECK-NEXT: mov r31, [[SCRATCH]]
; CHECK-NEXT: pop r30

View file

@ -17,8 +17,8 @@ body: |
; CHECK-LABEL: test_ldwrdptr
; CHECK: %r0 = LDRdPtr %r31r30
; CHECK-NEXT: early-clobber %r1 = LDDRdPtrQ %r31r30, 1
; CHECK: %r0, %r31r30 = LDRdPtrPi %r31r30
; CHECK-NEXT: %r1 = LDRdPtr %r31r30
%r1r0 = LDWRdPtr %r31r30
...

View file

@ -17,8 +17,8 @@ body: |
; CHECK-LABEL: test_ldwrdptrpd
; CHECK: early-clobber %r1, early-clobber %r31r30 = LDRdPtrPd killed %r31r30
; CHECK-NEXT: early-clobber %r0, early-clobber %r31r30 = LDRdPtrPd killed %r31r30
; CHECK: early-clobber %r1, %r31r30 = LDRdPtrPd killed %r31r30
; CHECK-NEXT: early-clobber %r0, %r31r30 = LDRdPtrPd killed %r31r30
%r1r0, %r31r30 = LDWRdPtrPd %r31r30
...

View file

@ -17,8 +17,8 @@ body: |
; CHECK-LABEL: test_ldwrdptrpi
; CHECK: early-clobber %r0, early-clobber %r31r30 = LDRdPtrPi killed %r31r30
; CHECK-NEXT: early-clobber %r1, early-clobber %r31r30 = LDRdPtrPi killed %r31r30
; CHECK: early-clobber %r0, %r31r30 = LDRdPtrPi killed %r31r30
; CHECK-NEXT: early-clobber %r1, %r31r30 = LDRdPtrPi killed %r31r30
%r1r0, %r31r30 = LDWRdPtrPi %r31r30
...

View file

@ -0,0 +1,18 @@
; RUN: llc -O0 < %s -march=avr | FileCheck %s
define i32 @std_ldd_overflow() {
%src = alloca [4 x i8]
%dst = alloca [4 x i8]
%buf = alloca [28 x i16]
%1 = bitcast [4 x i8]* %src to i32*
store i32 0, i32 *%1
%2 = bitcast [4 x i8]* %dst to i8*
%3 = bitcast [4 x i8]* %src to i8*
call void @llvm.memcpy.p0i8.p0i8.i16(i8* %2, i8* %3, i16 4, i32 1, i1 false)
; CHECK-NOT: std {{[XYZ]}}+64, {{r[0-9]+}}
; CHECK-NOT: ldd {{r[0-9]+}}, {{[XYZ]}}+64
ret i32 0
}
declare void @llvm.memcpy.p0i8.p0i8.i16(i8* nocapture writeonly, i8* nocapture readonly, i16, i32, i1)

View file

@ -27,8 +27,8 @@ define i16 @varargs1(i8* nocapture %x, ...) {
define i16 @varargs2(i8* nocapture %x, ...) {
; CHECK-LABEL: varargs2:
; CHECK: ld r24, Z
; CHECK: ldd r25, Z+1
; CHECK: ldd r24, [[REG:X|Y|Z]]+{{[0-9]+}}
; CHECK: ldd r25, [[REG]]+{{[0-9]+}}
%ap = alloca i8*
%ap1 = bitcast i8** %ap to i8*
call void @llvm.va_start(i8* %ap1)

View file

@ -0,0 +1,52 @@
; RUN: llc -march=mips -mattr=+dsp < %s -asm-show-inst -O0 | FileCheck %s \
; RUN: --check-prefixes=ASM,ALL
; RUN: llc -march=mips -mattr=+dsp,+micromips < %s -O0 -filetype=obj | \
; RUN: llvm-objdump -d - | FileCheck %s --check-prefixes=MM-OBJ,ALL
; Test that spill and reloads use the dsp "variant" instructions. We use -O0
; to use the simple register allocator.
; To test the micromips output, we have to take a round trip through the
; object file encoder/decoder as the instruction mapping tables are used to
; support micromips.
; FIXME: We should be able to get rid of those instructions with the variable
; value registers.
; ALL-LABEL: spill_reload:
define <4 x i8> @spill_reload(<4 x i8> %a, <4 x i8> %b, i32 %g) {
entry:
%c = tail call <4 x i8> @llvm.mips.addu.qb(<4 x i8> %a, <4 x i8> %b)
%cond = icmp eq i32 %g, 0
br i1 %cond, label %true, label %end
; ASM: SWDSP
; ASM: SWDSP
; ASM: SWDSP
; MM-OBJ: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MM-OBJ: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MM-OBJ: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MM-OBJ: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
true:
ret <4 x i8> %c
; ASM: LWDSP
; MM-OBJ: lw ${{[0-9]+}}, {{[0-9]+}}($sp)
end:
%d = tail call <4 x i8> @llvm.mips.addu.qb(<4 x i8> %c, <4 x i8> %a)
ret <4 x i8> %d
; ASM: LWDSP
; ASM: LWDSP
; MM-OBJ: lw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MM-OBJ: lw ${{[0-9]+}}, {{[0-9]+}}($sp)
}
declare <4 x i8> @llvm.mips.addu.qb(<4 x i8>, <4 x i8>) nounwind

View file

@ -0,0 +1,212 @@
# RUN: llc %s -start-after=shrink-wrap -march=mips64 -mcpu=mips64r6 -mattr=+fp64,+msa -o /dev/null
# Test that estimated size of the stack leads to the creation of an emergency
# spill when MSA is in use. Previously, this test case would fail during
# register scavenging due to the lack of a spill slot.
--- |
define inreg { i64, i64 } @test(i64 inreg %a.coerce0, i64 inreg %a.coerce1, i64 inreg %b.coerce0, i64 inreg %b.coerce1, i32 signext %c) #0 {
entry:
%retval = alloca <16 x i8>, align 16
%a = alloca <16 x i8>, align 16
%b = alloca <16 x i8>, align 16
%a.addr = alloca <16 x i8>, align 16
%b.addr = alloca <16 x i8>, align 16
%c.addr = alloca i32, align 4
%g = alloca <16 x i8>*, align 8
%d = alloca i8*, align 8
%0 = bitcast <16 x i8>* %a to { i64, i64 }*
%1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 0
store i64 %a.coerce0, i64* %1, align 16
%2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %0, i32 0, i32 1
store i64 %a.coerce1, i64* %2, align 8
%a1 = load <16 x i8>, <16 x i8>* %a, align 16
%3 = bitcast <16 x i8>* %b to { i64, i64 }*
%4 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 0
store i64 %b.coerce0, i64* %4, align 16
%5 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %3, i32 0, i32 1
store i64 %b.coerce1, i64* %5, align 8
%b2 = load <16 x i8>, <16 x i8>* %b, align 16
store <16 x i8> %a1, <16 x i8>* %a.addr, align 16
store <16 x i8> %b2, <16 x i8>* %b.addr, align 16
store i32 %c, i32* %c.addr, align 4
%6 = alloca i8, i64 6400, align 16
%7 = bitcast i8* %6 to <16 x i8>*
store <16 x i8>* %7, <16 x i8>** %g, align 8
%8 = load <16 x i8>*, <16 x i8>** %g, align 8
call void @h(<16 x i8>* %b.addr, <16 x i8>* %8)
%9 = load <16 x i8>*, <16 x i8>** %g, align 8
%10 = bitcast <16 x i8>* %9 to i8*
store i8* %10, i8** %d, align 8
%11 = load <16 x i8>, <16 x i8>* %a.addr, align 16
%12 = load i8*, i8** %d, align 8
%arrayidx = getelementptr inbounds i8, i8* %12, i64 0
%13 = load i8, i8* %arrayidx, align 1
%conv = sext i8 %13 to i32
%14 = call <16 x i8> @llvm.mips.fill.b(i32 %conv)
%add = add <16 x i8> %11, %14
%15 = load i8*, i8** %d, align 8
%arrayidx3 = getelementptr inbounds i8, i8* %15, i64 1
%16 = load i8, i8* %arrayidx3, align 1
%conv4 = sext i8 %16 to i32
%17 = call <16 x i8> @llvm.mips.fill.b(i32 %conv4)
%add5 = add <16 x i8> %add, %17
%18 = load <16 x i8>, <16 x i8>* %b.addr, align 16
%add6 = add <16 x i8> %18, %add5
store <16 x i8> %add6, <16 x i8>* %b.addr, align 16
%19 = load <16 x i8>, <16 x i8>* %b.addr, align 16
store <16 x i8> %19, <16 x i8>* %retval, align 16
%20 = bitcast <16 x i8>* %retval to { i64, i64 }*
%21 = load { i64, i64 }, { i64, i64 }* %20, align 16
ret { i64, i64 } %21
}
declare void @h(<16 x i8>*, <16 x i8>*)
declare <16 x i8> @llvm.mips.fill.b(i32)
declare void @llvm.stackprotector(i8*, i8**)
...
---
name: test
alignment: 3
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '%a0_64', virtual-reg: '' }
- { reg: '%a1_64', virtual-reg: '' }
- { reg: '%a2_64', virtual-reg: '' }
- { reg: '%a3_64', virtual-reg: '' }
- { reg: '%t0_64', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 0
offsetAdjustment: 0
maxAlignment: 16
adjustsStack: false
hasCalls: true
stackProtector: ''
maxCallFrameSize: 4294967295
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
stack:
- { id: 0, name: retval, type: default, offset: 0, size: 16, alignment: 16,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 1, name: a, type: default, offset: 0, size: 16, alignment: 16,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 2, name: b, type: default, offset: 0, size: 16, alignment: 16,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 3, name: a.addr, type: default, offset: 0, size: 16, alignment: 16,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 4, name: b.addr, type: default, offset: 0, size: 16, alignment: 16,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 5, name: c.addr, type: default, offset: 0, size: 4, alignment: 4,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 6, name: g, type: default, offset: 0, size: 8, alignment: 8,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 7, name: d, type: default, offset: 0, size: 8, alignment: 8,
callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
- { id: 8, name: '', type: default, offset: 0, size: 6400,
alignment: 16, callee-saved-register: '', di-variable: '', di-expression: '', di-location: '' }
constants:
body: |
bb.0.entry:
liveins: %a0_64, %a1_64, %a2_64, %a3_64, %t0_64
SD killed %a0_64, %stack.1.a, 0 :: (store 8 into %ir.1, align 16)
SD killed %a1_64, %stack.1.a, 8 :: (store 8 into %ir.2)
%w0 = LD_B %stack.1.a, 0 :: (dereferenceable load 16 from %ir.a)
SD killed %a2_64, %stack.2.b, 0 :: (store 8 into %ir.4, align 16)
SD killed %a3_64, %stack.2.b, 8 :: (store 8 into %ir.5)
%w1 = LD_B %stack.2.b, 0 :: (dereferenceable load 16 from %ir.b)
ST_B killed %w0, %stack.3.a.addr, 0 :: (store 16 into %ir.a.addr)
ST_B killed %w1, %stack.4.b.addr, 0 :: (store 16 into %ir.b.addr)
SW %t0, %stack.5.c.addr, 0, implicit killed %t0_64 :: (store 4 into %ir.c.addr)
%at_64 = LEA_ADDiu64 %stack.8, 0
SD killed %at_64, %stack.6.g, 0 :: (store 8 into %ir.g)
%a1_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
ADJCALLSTACKDOWN 0, 0, implicit-def dead %sp, implicit %sp
%a0_64 = LEA_ADDiu64 %stack.4.b.addr, 0
JAL @h, csr_n64, implicit-def dead %ra, implicit %a0_64, implicit %a1_64, implicit-def %sp
ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
%at_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%v0_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%v1_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%a0_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%a1_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%a2_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%a3_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t0_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t1_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t2_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t3_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t4_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t5_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t6_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t7_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s0_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s1_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s2_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s3_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s4_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s5_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s6_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%s7_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t8_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%t9_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%ra_64 = LD %stack.6.g, 0 :: (dereferenceable load 8 from %ir.g)
%w0 = LD_B %stack.3.a.addr, 0 :: (dereferenceable load 16 from %ir.a.addr)
SD %at_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %v0_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %v1_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %a0_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %a1_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %a2_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %a3_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t0_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t1_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t2_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t3_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t4_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t5_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t6_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t7_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s0_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s1_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s2_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s3_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s4_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s5_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s6_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %s7_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t8_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %t9_64, %stack.7.d, 0 :: (store 8 into %ir.d)
SD %ra_64, %stack.7.d, 0 :: (store 8 into %ir.d)
%at_64 = LD %stack.7.d, 0 :: (dereferenceable load 8 from %ir.d)
%v0 = LB %at_64, 0 :: (load 1 from %ir.arrayidx)
%w1 = FILL_B killed %v0
%w0 = ADDV_B killed %w0, killed %w1
%at = LB killed %at_64, 1 :: (load 1 from %ir.arrayidx3)
%w1 = FILL_B killed %at
%w0 = ADDV_B killed %w0, killed %w1
%w1 = LD_B %stack.4.b.addr, 0 :: (dereferenceable load 16 from %ir.b.addr)
%w0 = ADDV_B killed %w1, killed %w0
ST_B killed %w0, %stack.4.b.addr, 0 :: (store 16 into %ir.b.addr)
%w0 = LD_B %stack.4.b.addr, 0 :: (dereferenceable load 16 from %ir.b.addr)
ST_B killed %w0, %stack.0.retval, 0 :: (store 16 into %ir.retval)
%v0_64 = LD %stack.0.retval, 0 :: (dereferenceable load 8 from %ir.20, align 16)
%v1_64 = LD %stack.0.retval, 8 :: (dereferenceable load 8 from %ir.20 + 8, align 16)
RetRA implicit %v0_64, implicit %v1_64
...

View file

@ -18,7 +18,8 @@ define void @loadstore_v16i8_just_under_simm10() nounwind {
; MIPS32-AE: loadstore_v16i8_just_under_simm10:
%1 = alloca <16 x i8>
%2 = alloca [496 x i8] ; Push the frame right up to 512 bytes
%2 = alloca [492 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 512 bytes
%3 = load volatile <16 x i8>, <16 x i8>* %1
; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 496($sp)
@ -33,7 +34,8 @@ define void @loadstore_v16i8_just_over_simm10() nounwind {
; MIPS32-AE: loadstore_v16i8_just_over_simm10:
%1 = alloca <16 x i8>
%2 = alloca [497 x i8] ; Push the frame just over 512 bytes
%2 = alloca [497 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 512 bytes
%3 = load volatile <16 x i8>, <16 x i8>* %1
; MIPS32-AE: addiu [[BASE:\$([0-9]+|gp)]], $sp, 512
@ -50,7 +52,8 @@ define void @loadstore_v16i8_just_under_simm16() nounwind {
; MIPS32-AE: loadstore_v16i8_just_under_simm16:
%1 = alloca <16 x i8>
%2 = alloca [32752 x i8] ; Push the frame right up to 32768 bytes
%2 = alloca [32752 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 32768 bytes
%3 = load volatile <16 x i8>, <16 x i8>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -69,7 +72,8 @@ define void @loadstore_v16i8_just_over_simm16() nounwind {
; MIPS32-AE: loadstore_v16i8_just_over_simm16:
%1 = alloca <16 x i8>
%2 = alloca [32753 x i8] ; Push the frame just over 32768 bytes
%2 = alloca [32753 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 32768 bytes
%3 = load volatile <16 x i8>, <16 x i8>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -121,7 +125,8 @@ define void @loadstore_v8i16_just_under_simm10() nounwind {
; MIPS32-AE: loadstore_v8i16_just_under_simm10:
%1 = alloca <8 x i16>
%2 = alloca [1008 x i8] ; Push the frame right up to 1024 bytes
%2 = alloca [1004 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 1024 bytes
%3 = load volatile <8 x i16>, <8 x i16>* %1
; MIPS32-AE: ld.h [[R1:\$w[0-9]+]], 1008($sp)
@ -136,7 +141,8 @@ define void @loadstore_v8i16_just_over_simm10() nounwind {
; MIPS32-AE: loadstore_v8i16_just_over_simm10:
%1 = alloca <8 x i16>
%2 = alloca [1009 x i8] ; Push the frame just over 1024 bytes
%2 = alloca [1009 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 1024 bytes
%3 = load volatile <8 x i16>, <8 x i16>* %1
; MIPS32-AE: addiu [[BASE:\$([0-9]+|gp)]], $sp, 1024
@ -153,7 +159,8 @@ define void @loadstore_v8i16_just_under_simm16() nounwind {
; MIPS32-AE: loadstore_v8i16_just_under_simm16:
%1 = alloca <8 x i16>
%2 = alloca [32752 x i8] ; Push the frame right up to 32768 bytes
%2 = alloca [32752 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 32768 bytes
%3 = load volatile <8 x i16>, <8 x i16>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -172,7 +179,8 @@ define void @loadstore_v8i16_just_over_simm16() nounwind {
; MIPS32-AE: loadstore_v8i16_just_over_simm16:
%1 = alloca <8 x i16>
%2 = alloca [32753 x i8] ; Push the frame just over 32768 bytes
%2 = alloca [32753 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 32768 bytes
%3 = load volatile <8 x i16>, <8 x i16>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -224,7 +232,8 @@ define void @loadstore_v4i32_just_under_simm10() nounwind {
; MIPS32-AE: loadstore_v4i32_just_under_simm10:
%1 = alloca <4 x i32>
%2 = alloca [2032 x i8] ; Push the frame right up to 2048 bytes
%2 = alloca [2028 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 2048 bytes
%3 = load volatile <4 x i32>, <4 x i32>* %1
; MIPS32-AE: ld.w [[R1:\$w[0-9]+]], 2032($sp)
@ -239,7 +248,8 @@ define void @loadstore_v4i32_just_over_simm10() nounwind {
; MIPS32-AE: loadstore_v4i32_just_over_simm10:
%1 = alloca <4 x i32>
%2 = alloca [2033 x i8] ; Push the frame just over 2048 bytes
%2 = alloca [2033 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 2048 bytes
%3 = load volatile <4 x i32>, <4 x i32>* %1
; MIPS32-AE: addiu [[BASE:\$([0-9]+|gp)]], $sp, 2048
@ -256,7 +266,8 @@ define void @loadstore_v4i32_just_under_simm16() nounwind {
; MIPS32-AE: loadstore_v4i32_just_under_simm16:
%1 = alloca <4 x i32>
%2 = alloca [32752 x i8] ; Push the frame right up to 32768 bytes
%2 = alloca [32752 x i8] ; Push the frame--acounting for the emergency spill
; slot-- right up to 32768 bytes
%3 = load volatile <4 x i32>, <4 x i32>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -275,7 +286,8 @@ define void @loadstore_v4i32_just_over_simm16() nounwind {
; MIPS32-AE: loadstore_v4i32_just_over_simm16:
%1 = alloca <4 x i32>
%2 = alloca [32753 x i8] ; Push the frame just over 32768 bytes
%2 = alloca [32753 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 32768 bytes
%3 = load volatile <4 x i32>, <4 x i32>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -327,8 +339,8 @@ define void @loadstore_v2i64_just_under_simm10() nounwind {
; MIPS32-AE: loadstore_v2i64_just_under_simm10:
%1 = alloca <2 x i64>
%2 = alloca [4080 x i8] ; Push the frame right up to 4096 bytes
%2 = alloca [4076 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 4096 bytes
%3 = load volatile <2 x i64>, <2 x i64>* %1
; MIPS32-AE: ld.d [[R1:\$w[0-9]+]], 4080($sp)
store volatile <2 x i64> %3, <2 x i64>* %1
@ -342,7 +354,8 @@ define void @loadstore_v2i64_just_over_simm10() nounwind {
; MIPS32-AE: loadstore_v2i64_just_over_simm10:
%1 = alloca <2 x i64>
%2 = alloca [4081 x i8] ; Push the frame just over 4096 bytes
%2 = alloca [4081 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 4096 bytes
%3 = load volatile <2 x i64>, <2 x i64>* %1
; MIPS32-AE: addiu [[BASE:\$([0-9]+|gp)]], $sp, 4096
@ -359,7 +372,8 @@ define void @loadstore_v2i64_just_under_simm16() nounwind {
; MIPS32-AE: loadstore_v2i64_just_under_simm16:
%1 = alloca <2 x i64>
%2 = alloca [32752 x i8] ; Push the frame right up to 32768 bytes
%2 = alloca [32752 x i8] ; Push the frame--acounting for the emergency spill
; slot--right up to 32768 bytes
%3 = load volatile <2 x i64>, <2 x i64>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768
@ -378,7 +392,8 @@ define void @loadstore_v2i64_just_over_simm16() nounwind {
; MIPS32-AE: loadstore_v2i64_just_over_simm16:
%1 = alloca <2 x i64>
%2 = alloca [32753 x i8] ; Push the frame just over 32768 bytes
%2 = alloca [32753 x i8] ; Push the frame--acounting for the emergency spill
; slot--just over 32768 bytes
%3 = load volatile <2 x i64>, <2 x i64>* %1
; MIPS32-AE: ori [[R2:\$([0-9]+|gp)]], $zero, 32768

View file

@ -1,5 +1,7 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -O2 -mtriple=x86_64-linux-android -mattr=+mmx | FileCheck %s --check-prefix=X64
; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=+mmx | FileCheck %s --check-prefix=X64
; RUN: llc < %s -O2 -mtriple=x86_64-linux-gnu -mattr=-mmx | FileCheck %s --check-prefix=X64_NO_MMX
; RUN: llc < %s -O2 -mtriple=i686-linux-gnu -mattr=+mmx | FileCheck %s --check-prefix=X32
; Check soft floating point conversion function calls.
@ -359,6 +361,69 @@ cleanup: ; preds = %entry, %if.then
; X64: retq
}
define i1 @PR34866(i128 %x) {
; X64-LABEL: PR34866:
; X64: # BB#0:
; X64-NEXT: movaps {{.*}}(%rip), %xmm0
; X64-NEXT: movaps %xmm0, -{{[0-9]+}}(%rsp)
; X64-NEXT: xorq -{{[0-9]+}}(%rsp), %rsi
; X64-NEXT: xorq -{{[0-9]+}}(%rsp), %rdi
; X64-NEXT: orq %rsi, %rdi
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X64_NO_MMX-LABEL: PR34866:
; X64_NO_MMX: # BB#0:
; X64_NO_MMX-NEXT: orq %rsi, %rdi
; X64_NO_MMX-NEXT: sete %al
; X64_NO_MMX-NEXT: retq
;
; X32-LABEL: PR34866:
; X32: # BB#0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: orl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: orl {{[0-9]+}}(%esp), %eax
; X32-NEXT: orl %ecx, %eax
; X32-NEXT: sete %al
; X32-NEXT: retl
%bc_mmx = bitcast fp128 0xL00000000000000000000000000000000 to i128
%cmp = icmp eq i128 %bc_mmx, %x
ret i1 %cmp
}
define i1 @PR34866_commute(i128 %x) {
; X64-LABEL: PR34866_commute:
; X64: # BB#0:
; X64-NEXT: movaps {{.*}}(%rip), %xmm0
; X64-NEXT: movaps %xmm0, -{{[0-9]+}}(%rsp)
; X64-NEXT: xorq -{{[0-9]+}}(%rsp), %rsi
; X64-NEXT: xorq -{{[0-9]+}}(%rsp), %rdi
; X64-NEXT: orq %rsi, %rdi
; X64-NEXT: sete %al
; X64-NEXT: retq
;
; X64_NO_MMX-LABEL: PR34866_commute:
; X64_NO_MMX: # BB#0:
; X64_NO_MMX-NEXT: orq %rsi, %rdi
; X64_NO_MMX-NEXT: sete %al
; X64_NO_MMX-NEXT: retq
;
; X32-LABEL: PR34866_commute:
; X32: # BB#0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: orl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: orl {{[0-9]+}}(%esp), %eax
; X32-NEXT: orl %ecx, %eax
; X32-NEXT: sete %al
; X32-NEXT: retl
%bc_mmx = bitcast fp128 0xL00000000000000000000000000000000 to i128
%cmp = icmp eq i128 %x, %bc_mmx
ret i1 %cmp
}
declare double @copysign(double, double) #1
attributes #2 = { nounwind readnone }

View file

@ -0,0 +1,63 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=i386-unknown-linux-gnu -mattr=avx512bw,avx512vl,avx512dq | FileCheck %s
define void @pr34605(i8* nocapture %s, i32 %p) {
; CHECK-LABEL: pr34605:
; CHECK: # BB#0: # %entry
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax
; CHECK-NEXT: vpbroadcastd {{[0-9]+}}(%esp), %zmm0
; CHECK-NEXT: vpcmpeqd {{\.LCPI.*}}, %zmm0, %k0
; CHECK-NEXT: vpcmpeqd {{\.LCPI.*}}, %zmm0, %k1
; CHECK-NEXT: kunpckwd %k0, %k1, %k0
; CHECK-NEXT: vpcmpeqd {{\.LCPI.*}}, %zmm0, %k1
; CHECK-NEXT: vpcmpeqd {{\.LCPI.*}}, %zmm0, %k2
; CHECK-NEXT: kunpckwd %k1, %k2, %k1
; CHECK-NEXT: kunpckdq %k0, %k1, %k0
; CHECK-NEXT: kxord %k0, %k0, %k1
; CHECK-NEXT: movl $1, %ecx
; CHECK-NEXT: kmovd %ecx, %k2
; CHECK-NEXT: kunpckdq %k2, %k1, %k1
; CHECK-NEXT: kandq %k1, %k0, %k1
; CHECK-NEXT: vmovdqu8 {{\.LCPI.*}}, %zmm0 {%k1} {z}
; CHECK-NEXT: vmovdqu8 %zmm0, (%eax)
; CHECK-NEXT: vpxord %zmm0, %zmm0, %zmm0
; CHECK-NEXT: vmovdqu32 %zmm0, 64(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 128(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 192(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 256(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 320(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 384(%eax)
; CHECK-NEXT: vmovdqu32 %zmm0, 448(%eax)
; CHECK-NEXT: vzeroupper
; CHECK-NEXT: retl
entry:
%broadcast.splatinsert = insertelement <64 x i32> undef, i32 %p, i32 0
%broadcast.splat = shufflevector <64 x i32> %broadcast.splatinsert, <64 x i32> undef, <64 x i32> zeroinitializer
%0 = icmp eq <64 x i32> %broadcast.splat, <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31, i32 32, i32 33, i32 34, i32 35, i32 36, i32 37, i32 38, i32 39, i32 40, i32 41, i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49, i32 50, i32 51, i32 52, i32 53, i32 54, i32 55, i32 56, i32 57, i32 58, i32 59, i32 60, i32 61, i32 62, i32 63>
%1 = and <64 x i1> %0, <i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false>
%2 = zext <64 x i1> %1 to <64 x i8>
%3 = bitcast i8* %s to <64 x i8>*
store <64 x i8> %2, <64 x i8>* %3, align 1
%4 = getelementptr inbounds i8, i8* %s, i32 64
%5 = bitcast i8* %4 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %5, align 1
%6 = getelementptr inbounds i8, i8* %s, i32 128
%7 = bitcast i8* %6 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %7, align 1
%8 = getelementptr inbounds i8, i8* %s, i32 192
%9 = bitcast i8* %8 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %9, align 1
%10 = getelementptr inbounds i8, i8* %s, i32 256
%11 = bitcast i8* %10 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %11, align 1
%12 = getelementptr inbounds i8, i8* %s, i32 320
%13 = bitcast i8* %12 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %13, align 1
%14 = getelementptr inbounds i8, i8* %s, i32 384
%15 = bitcast i8* %14 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %15, align 1
%16 = getelementptr inbounds i8, i8* %s, i32 448
%17 = bitcast i8* %16 to <64 x i8>*
store <64 x i8> zeroinitializer, <64 x i8>* %17, align 1
ret void
}

View file

@ -0,0 +1,35 @@
; RUN: llc -filetype=obj -O0 < %s -mtriple sparc64-unknown-linux-gnu | llvm-dwarfdump - | FileCheck %s
; The undescribable 128-bit register should be split into two 64-bit registers.
; CHECK: Location description: 90 48 93 08 90 49 93 08
; DW_OP_reg74 DW_OP_piece 8 DW_OP_reg75 DW_OP_piece 8 ...
target datalayout = "E-m:e-i64:64-n32:64-S128"
target triple = "sparc64"
; Function Attrs: nounwind readnone
define void @fn1(fp128 %b) local_unnamed_addr !dbg !7 {
entry:
tail call void @llvm.dbg.value(metadata fp128 %b, i64 0, metadata !13, metadata !18), !dbg !17
tail call void @llvm.dbg.value(metadata fp128 0xL00000000000000000000000000000000, i64 0, metadata !13, metadata !19), !dbg !17
ret void, !dbg !20
}
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, i64, metadata, metadata)
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!4}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug)
!1 = !DIFile(filename: "subreg.c", directory: ".")
!4 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !8, unit: !0)
!8 = !DISubroutineType(types: !9)
!9 = !{null, !10}
!10 = !DIBasicType(name: "long double", size: 128, encoding: DW_ATE_float)
!13 = !DILocalVariable(name: "a", scope: !7, file: !1, line: 1, type: !14)
!14 = !DIBasicType(name: "complex", size: 256, encoding: DW_ATE_complex_float)
!17 = !DILocation(line: 1, column: 48, scope: !7)
!18 = !DIExpression(DW_OP_LLVM_fragment, 0, 128)
!19 = !DIExpression(DW_OP_LLVM_fragment, 128, 128)
!20 = !DILocation(line: 1, column: 55, scope: !7)

View file

@ -0,0 +1,50 @@
; RUN: %llc_dwarf %s -filetype=obj -o %t
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
; Reduced test case from PR35212. Two DISubprogram belong to a different CU but
; share a scope. Both are declarations and end up in the scope's CU. We want to
; check that the CU from the context DIE is used (rather than from the IR).
; This manifests itself by the DW_base_type ending up in the second CU, rather
; than in the first one as specified in the IR.
; CHECK: DW_TAG_compile_unit
; CHECK-NEXT: discriminator 0
; CHECK: DW_TAG_compile_unit
; CHECK-NEXT: discriminator 1
; CHECK: DW_TAG_structure_type
; CHECK-NOT: NULL
; CHECK: DW_TAG_subprogram
; CHECK-NOT: NULL
; CHECK: DW_TAG_formal_parameter
; CHECK-NOT: NULL
; CHECK: DW_AT_type{{.*}}{[[USIZE_LABEL:0x[0-9a-f]+]]}
; CHECK: NULL
; CHECK: [[USIZE_LABEL]]: DW_TAG_base_type
; CHECK-NOT: NULL
; CHECK: DW_AT_name{{.*}}"usize"
define hidden void @foo() !dbg !4 {
ret void, !dbg !7
}
!llvm.dbg.cu = !{!0, !2}
!llvm.module.flags = !{!3}
!0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "clang LLVM (rustc version 1.23.0-nightly (discriminator 0))", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "../lib.rs", directory: "/home/alex/code/rust4/lol")
!2 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !1, producer: "clang LLVM (rustc version 1.23.0-nightly (discriminator 1))", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = distinct !DISubprogram(name: "clone<alloc::string::String>", linkageName: "_ZN5alloc3vec8{{impl}}28clone<alloc::string::String>E", scope: null, file: !1, line: 1519, type: !5, isLocal: false, isDefinition: true, scopeLine: 1519, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !6, variables: !6)
!5 = !DISubroutineType(types: !6)
!6 = !{}
!7 = !DILocation(line: 1612, scope: !8, inlinedAt: !11)
!8 = distinct !DILexicalBlock(scope: !9, file: !1, line: 86, column: 12)
!9 = distinct !DISubprogram(name: "allocate_in<alloc::string::String,alloc::heap::Heap>", linkageName: "_ZN5alloc7raw_vec8{{impl}}52allocate_in<alloc::string::String,alloc::heap::Heap>E", scope: !10, file: !1, line: 82, type: !5, isLocal: false, isDefinition: true, scopeLine: 82, flags: DIFlagPrototyped, isOptimized: true, unit: !2, templateParams: !6, variables: !6)
!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "RawVec<alloc::string::String, alloc::heap::Heap>", file: !1, size: 128, align: 64, elements: !6, identifier: "5c6e4db16d2c64555e40661d70c4d81e")
!11 = distinct !DILocation(line: 86, scope: !8, inlinedAt: !12)
!12 = distinct !DILocation(line: 141, scope: !13, inlinedAt: !17)
!13 = distinct !DISubprogram(name: "with_capacity<alloc::string::String>", linkageName: "_ZN5alloc7raw_vec8{{impl}}36with_capacity<alloc::string::String>E", scope: !10, file: !1, line: 140, type: !5, isLocal: false, isDefinition: true, scopeLine: 140, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !6, variables: !14)
!14 = !{!15}
!15 = !DILocalVariable(name: "cap", arg: 1, scope: !13, file: !1, line: 1, type: !16)
!16 = !DIBasicType(name: "usize", size: 64, encoding: DW_ATE_unsigned)
!17 = !DILocation(line: 1521, scope: !4)

View file

@ -0,0 +1,17 @@
; RUN: llvm-as -o %t %s
; RUN: llvm-lto2 run %t -r %t,foo, -r %t,baz,p -o %t2 -save-temps
; RUN: llvm-dis -o - %t2.0.0.preopt.bc | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--fuchsia"
; CHECK: declare void @foo()
@foo = weak alias void(), void()* @bar
define internal void @bar() {
ret void
}
define void()* @baz() {
ret void()* @foo
}

View file

@ -0,0 +1,7 @@
@used1 = global i8 4
@used2 = global i32 123
@llvm.compiler.used = appending global [2 x i8*] [
i8* @used1,
i8* bitcast (i32* @used2 to i8*)
], section "llvm.metadata"

View file

@ -0,0 +1,20 @@
define internal void @ctor1() {
call void @func1()
ret void
}
define internal void @ctor2() {
ret void
}
define void @func1() {
ret void
}
define void @unused() {
ret void
}
@llvm.global_ctors = appending global[2 x{i32, void() *, i8 * }] [
{i32, void() *, i8 * } { i32 2, void() *@ctor1, i8 *null},
{i32, void() *, i8 * } { i32 7, void() *@ctor2, i8 *null}]

View file

@ -0,0 +1,20 @@
define internal void @dtor1() {
call void @func1()
ret void
}
define internal void @dtor2() {
ret void
}
define void @func1() {
ret void
}
define void @unused() {
ret void
}
@llvm.global_dtors = appending global[2 x{i32, void() *, i8 * }] [
{i32, void() *, i8 * } { i32 2, void() *@dtor1, i8 *null},
{i32, void() *, i8 * } { i32 7, void() *@dtor2, i8 *null}]

View file

@ -0,0 +1,7 @@
@used1 = global i8 4
@used2 = global i32 123
@llvm.used = appending global [2 x i8*] [
i8* @used1,
i8* bitcast (i32* @used2 to i8*)
], section "llvm.metadata"

Some files were not shown because too many files have changed in this diff Show more